I have setup an ASP.NET WebApi project with support of bearer token like this:
var oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
var oAuthBearerOptions = new OAuthBearerAuthenticationOptions();
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(oAuthBearerOptions);
When I make a request to the token endpoint I have this answer
{
"access_token":"GST9UwSuesiYhkezr94K4xwuzvNQ",
"token_type":"bearer",
"expires_in":86399
}
Is there any way to enrich the token with additional fields like this?
{
"access_token":"GST9UwSuesiYhkezr94K4xwuzvNQ",
"token_type":"bearer",
"expires_in":86399,
"username":"user#mail.com"
}
Well here is the solution:
In your class that inherits from OAuthAuthorizationServerProvider
public override async Task TokenEndpoint(OAuthTokenEndpointContext context)
{
context.AdditionalResponseParameters.Add("username", "user#mail.com");
return Task.FromResult<object>(null);
}
Related
I have created a ASP.NET WEB.API project with OWIN JWT Authentication. Is is working as expected, but what I want is to show custom validation message to use instead of default message if JWT authentication fails.
Right now it shows
{
"message": "Authorization has been denied for this request."
}
This is my Validation Code.
public class OwinStartUp
{
public void Configuration(IAppBuilder app)
{
HttpStatusCode statusCode;
HttpResponseMessage message = new HttpResponseMessage();
try
{
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "http://jwt.com",
ValidAudience = "http://jwt.com",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("jwt_key_asdf"))
}
});
}
catch (SecurityTokenValidationException e )
{
statusCode = HttpStatusCode.Unauthorized;
message = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("Failed") /////// Even tried this but it does not work.
};
}
catch(Exception ex)
{
}
}
}
I'm trying to add JWT validation in my dot net core application. I've followed this link to understand JWT and able to generate a token by givings some values like this.
var token = new JwtSecurityToken(
issuer: issuer,
audience: aud,
claims: claims,
expires: expTime,
signingCredentials: creds
);
Edit: and to follow this answer, I've also added JwtBearerAuthentication middleware in my app by adding app.UseJwtBearerAuthentication(new JwtBearerOptions { /* options */ }) to Startup.Configure() method.
Now I'm stuck how could I pass this token inside HTTP header? I'm generating this token on Login but whats next? How could I get to know that JWT is added and working fine??
Any kind of help will be appreciated.
This is a runnable sample for bearer token authentication in ASP.NET Core.
How to achieve a bearer token authentication and authorization in ASP.NET Core
At back end, you can generate the token following this code:
[Route("api/[controller]")]
public class TokenAuthController : Controller
{
[HttpPost]
public string GetAuthToken(User user)
{
var existUser = UserStorage.Users.FirstOrDefault(u => u.Username == user.Username && u.Password == user.Password);
if (existUser != null)
{
var requestAt = DateTime.Now;
var expiresIn = requestAt + TokenAuthOption.ExpiresSpan;
var token = GenerateToken(existUser, expiresIn);
return JsonConvert.SerializeObject(new {
stateCode = 1,
requertAt = requestAt,
expiresIn = TokenAuthOption.ExpiresSpan.TotalSeconds,
accessToken = token
});
}
else
{
return JsonConvert.SerializeObject(new { stateCode = -1, errors = "Username or password is invalid" });
}
}
private string GenerateToken(User user, DateTime expires)
{
var handler = new JwtSecurityTokenHandler();
ClaimsIdentity identity = new ClaimsIdentity(
new GenericIdentity(user.Username, "TokenAuth"),
new[] {
new Claim("ID", user.ID.ToString())
}
);
var securityToken = handler.CreateToken(new SecurityTokenDescriptor
{
Issuer = TokenAuthOption.Issuer,
Audience = TokenAuthOption.Audience,
SigningCredentials = TokenAuthOption.SigningCredentials,
Subject = identity,
Expires = expires
});
return handler.WriteToken(securityToken);
}
}
In Startup.cs/ConfigureServices method
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
And add this code in Configure method
app.UseJwtBearerAuthentication(new JwtBearerOptions {
TokenValidationParameters = new TokenValidationParameters {
IssuerSigningKey = TokenAuthOption.Key,
ValidAudience = TokenAuthOption.Audience,
ValidIssuer = TokenAuthOption.Issuer,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(0)
}
});
At front end, you just add the token to header like this:
$.ajaxSetup({
headers: { "Authorization": "Bearer " + accessToken }
});
or
$.ajax("http://somedomain/somepath/somepage",{
headers:{ "Authorization": "Bearer " + accessToken },
/*some else parameter for ajax, see more you can review the Jquery API*/
});
I am tying to do JwtBearerAuthentication on my .net WebAPI and it is just not working. The Authorize attribute is always claiming isAuthorized = false.
I am working with Okta as the SSO. I am authenticating on my client side and getting both an access token and id token. On a webapi get request I am providing the access token (i have also tried the id token) in the authorize header and I am able to see the authorize header with the token in the webapi actioncontext.
In my startup.cs I have the following
var clientID = WebConfigurationManager.AppSettings["okta:ClientId"];
var oidcIssuer = WebConfigurationManager.AppSettings["okta:OIDC_Issuer"];
TokenValidationParameters tvps = new TokenValidationParameters
{
ValidAudience = clientID,
ValidateAudience = true,
ValidIssuer = oidcIssuer,
ValidateIssuer = true
};
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
TokenValidationParameters = tvps,
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new OpenIdConnectCachingSecurityTokenProvider(oidcIssuer + "/.well-known/openid-configuration")
}
});
Am i missing some TokenValidationParameters that I need?
As I was typing this, I see that twaldron was able to figure it out!
I also realized that he was asking about WebAPI, and not MVC. However, here is the code that I needed to get the following working with ASP.NET Core MVC, of particular interest might be this line, which is necessary to get access to the additional claims in the JWT:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
Here is how this code sample works from the command line, the $ID_TOKEN variable contains a valid JWT:
$ curl -H "Authorization: Bearer ${ID_TOKEN}" http://localhost:3000/test/test
sub: 01a23b4cd5eFgHI6j7k8 email:test#example.com
Setup.cs:
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
namespace WebApplication
{
public class Startup
{
readonly string clientId = string.Empty;
readonly string issuer = string.Empty;
readonly string audience = string.Empty;
public Startup(IHostingEnvironment env)
{
clientId = "A0b1CDef2GHIj3k4lm5n";
issuer = "https://example.okta.com";
audience = "A0b1CDef2GHIj3k4lm5n";
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddDebug();
// https://github.com/aspnet/Security/issues/1043#issuecomment-261937401
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
TokenValidationParameters tvps = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = audience,
ValidateIssuer = true,
ValidIssuer = issuer,
ValidateLifetime = true,
ClockSkew = TimeSpan.FromMinutes(5)
};
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
MetadataAddress = issuer + "/.well-known/openid-configuration",
TokenValidationParameters = tvps
});
app.UseStaticFiles();
// Add external authentication middleware below. To configure them please see https://go.microsoft.com/fwlink/?LinkID=532715
app.UseMvc(routes =>
{
routes.MapRoute(
name: "test-controller",
template: "test/{action}",
defaults: new { controller = "Test", action = "Index" }
);
routes.MapRoute(
name: "default",
template: "{controller=Test}/{action=Index}/{id?}");
});
}
}
}
In Controllers/Test.cs:
[Authorize]
public IActionResult Test()
{
var contextUser = User.Identity as ClaimsIdentity;
Dictionary<string, string> claim = contextUser.Claims.ToDictionary(x => x.Type, x => x.Value);
var output = "sub: " + claim["sub"] + " email:" + claim["email"];
return Content(output);
}
My problem was not with the options.
It was 100% the need to move
app.UseWebApi(config);
below all the owin setup stuff.
I am having some trouble accessing my userId after and creating my dictionary with connectionIds. I currently and using OAuthBearer for authentication of my users and saving information into ClaimsIdentity, something like below:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (AuthRepository _repo = new AuthRepository())
{
IdentityUser user = await _repo.FindUser(context.UserName, context.Password);
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", (context.ClientId == null) ? string.Empty : context.ClientId
},
{
"userName", context.UserName
},
{
"userId", user.Id
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
}
When I am in my startup/my signalR hub, when I try using the IRequest.user.identity.name or HttpContext.Current.User.Identity.GetUserId();, I get an empty value.
public string GetUserId(IRequest request)
{
var userId = request.User.Identity.Name;
return userId.ToString();
}
I'm thinking that something is wrong with my claims because I can't access the values of UserId and userName. If I run HttpContext.Current.User.Identity.GetUserId(); anywhere else, I can get the userId.
Any help would be greatly appreciated as I've been stuck on this for quite a while.
I had the same issue, try replacing HttpContext.Current with
Context.Request.GetHttpContext() inside your signalR hub methods.
According to MSDN the HubCallerContext returns the context of the client.
I am developing a web application, mobile application and desktop application which all can access the data with the help of a single API which can be developed by ASP.NET Web API.
In my Web API can I authenticate the user credentials and the consumer Application key with the help of OAuth?
Can you guys guide me to achieve the same with any examples?
Add the following lines in startup class
public class Startup
{
public void Configuration(IAppBuilder app)
{
var oauthProvider = new OAuthAuthorizationServerProvider
{
OnGrantResourceOwnerCredentials = async context =>
{
IsValid = true;
//You can get the username and password by context.username and context.password
if (IsValid)
{
var claimsIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
claimsIdentity.AddClaim(new Claim("user", context.UserName));
context.Validated(claimsIdentity);
return;
}
context.Rejected();
},
OnValidateClientAuthentication = async context =>
{
string clientId;
string clientSecret;
if (context.TryGetBasicCredentials(out clientId, out clientSecret))
{
if (clientId == GlobalAppSettings.SystemSettings.ApplicationKey)
{
context.Validated();
}
}
}
};
var oauthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/accesstoken"),
Provider = oauthProvider,
AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(1),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(3),
SystemClock = new SystemClock()
};
app.UseOAuthAuthorizationServer(oauthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}
}
And invoke the startup method by start up the new OAuth APP from where you need the authorization and OAuth token
You can use your own host by using the self hosting namespace.
Otherwise you can use Microsoft.Owin.Host.HttpListener namespace and host the OAuth app in different host as below
var Basesite = "http://localhost:9327/";
var homeProcessorModel = new HomeProcessorModel();
using (WebApp.Start<Startup>(url: Basesite))
{
var client = new HttpClient();
var form = new Dictionary<string, string>
{
{"grant_type","password"},
{"userName",username},
{"passWord",password}
};//If you are using grant_type as password, you have to send the username and password to OAuth protocol.
var tokenResponse = client.PostAsync(Basesite + "accesstoken", new FormUrlEncodedContent(form)).Result;
var token = tokenResponse.Content.ReadAsAsync<Token>(new[] { new JsonMediaTypeFormatter() }).Result;
//You can get the token with token.AccessToken object
}