JWT Token authentication - Doing it right way - asp.net-mvc

Overview of my project structure:
I have 2 Projects.
Asp.net core Web Api
Asp.net core Web MVC
In Web Api Project
I am NOT using Asp.net core Identity for login, instead, I am using my own login mechanism.
LoginAction method will authenticate user in database and generate JWT Token.
I was able to generate JWT Token and Life is smooth till this point.
Generate Token
[AllowAnonymous]
[Route("requesttoken")]
[HttpPost]
public async Task<IActionResult> RequestToken([FromBody] TokenRequest request)
{
var result = await IsValidUser(request);
if(result)
{
var claims = new[]
{
new Claim(ClaimTypes.Name, request.Email)
};
var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_myAppSettings.SecurityKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _myAppSettings.WebsiteName.ToLower(),
audience: _myAppSettings.WebsiteName.ToLower(),
claims: claims,
notBefore: Utilities.GetEST_DateTimeNow(),
expires: Utilities.GetEST_DateTimeNow().AddMinutes(5),
signingCredentials: creds);
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token)
});
}
else
{
return Unauthorized();
}
}
Inside Startup class
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyAppSettings>(Configuration.GetSection("MyAppSettings"));
#region Validate JWT Token
ConfigureJwtAuthService(services, Configuration);
#endregion
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
JWT Validation part (As partial startup class)
public void ConfigureJwtAuthService(IServiceCollection services, IConfiguration configuration)
{
var symmetricKeyAsBase64 = configuration["MyAppSettings:SecurityKey"];
var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
var signingKey = new SymmetricSecurityKey(keyByteArray);
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = Configuration["MyAppSettings:WebsiteName"].ToLower(),
// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = Configuration["MyAppSettings:WebsiteName"].ToLower(),
// Validate the token expiry
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(
options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o => o.TokenValidationParameters = tokenValidationParameters);
}
Sample response of LoginAction Method.
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkrDtGhuIETDs8OoIiwiYWRtaW4iOnRydWV9.469tBeJmYLERjlKi9u6gylb-2NsjHLC_6kZNdtoOGsA"
}
In Web MVC Project
I am consuming above Web Api and passing login parameters and was able to get JWT Token response.
I am storing JWT Token response in cookie [Manually - _httpContextAccessor.HttpContext.Response.Cookies.Append(key, jwtTokenValue, option);]
Based on JWT Token response receive, I am trying to extract claims from that JWT Token, so that I can able to create valid identity of user and login user on the web.
I am trying to achieve something like below:
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, model.Email)
};
var userIdentity = new ClaimsIdentity(claims, "login");
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
return RedirectToLocal(returnUrl);
}
Questions
Am I doing right by storing JWT Token in cookie. Is my manual approach of storing cookie is correct or is there any better way?
How can I get claims from JWT in Web Project, so that I can able to singin user using cookie?
Want to do it right way, any help would be much appreciated.

Following seems to helped me: http://blogs.quovantis.com/json-web-token-jwt-with-web-api/ not sure whether that is right way of doing or not.
/// Using the same key used for signing token, user payload is generated back
public JwtSecurityToken GenerateUserClaimFromJWT(string authToken)
{
var tokenValidationParameters = new TokenValidationParameters()
{
ValidAudiences = new string[]
{
"http://www.example.com",
},
ValidIssuers = new string[]
{
"self",
},
IssuerSigningKey = signingKey
};
var tokenHandler = new JwtSecurityTokenHandler();
SecurityToken validatedToken;
try {
tokenHandler.ValidateToken(authToken,tokenValidationParameters, out validatedToken);
}
catch (Exception)
{
return null;
}
return validatedToken as JwtSecurityToken;
}

Related

JWT token isn't validated even if it's correct using Microsoft.Azure.Mobile SDK

I'm using Microsoft.Azure.Mobile SDK for implementing Server code.
Code in OWIN startup is as below:
public void ConfigureAuth(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration().ApplyTo(config);
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
SigningKey = ConfigurationManager.AppSettings["SigningKey"],
ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] },
ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] },
TokenHandler = config.GetAppServiceTokenHandler()
});
app.UseWebApi(config);
}
Token generation code:
Claim[] claims = new Claim[]
{
new Claim("sub", "SampleSubject"),
new Claim("Id", Convert.ToString(Users[0].user_id)),
new Claim("name", Users[0].name),
new Claim("surname", Users[0].surname),
new Claim(ClaimTypes.Role, "user")
};
var token = AppServiceLoginHandler.CreateToken(claims, ConfigurationManager.AppSettings["SigningKey"], ConfigurationManager.AppSettings["ValidAudience"], ConfigurationManager.AppSettings["ValidIssuer"], TimeSpan.FromDays(30));
return token.RawData;
A sample JWT token is
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJHcnViZXJBUEkiLCJJZCI6IjMyODkwIiwibmFtZSI6IkRhdmlkZSIsInN1cm5hbWUiOiJCb25ldHRhIiwicm9sZSI6InVzZXIiLCJ2ZXIiOiIzIiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6MjM1MzEvIiwiYXVkIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6MjM1MzIvIiwiZXhwIjoxNTAyNDYyNDQzLCJuYmYiOjE0OTk4NzA0NDN9.b5VhWzvkaEumutPZpLzImcAy4NotXCSgUIqLltVUQWI
The token is valid per below screenshot
And for below code,
[Authorize]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/values/5
public string Get(int id)
{
try
{
ClaimsPrincipal claims;
AppServiceTokenHandler s = new AppServiceTokenHandler(new HttpConfiguration());
s.TryValidateLoginToken(Request.Headers.Authorization.Parameter, ConfigurationManager.AppSettings["SigningKey"], new[] { ConfigurationManager.AppSettings["ValidAudience"] }, new[] { ConfigurationManager.AppSettings["ValidIssuer"] }, out claims);
AppServiceTokenHandler.ValidateToken(Request.Headers.Authorization.Parameter, ConfigurationManager.AppSettings["SigningKey"], ConfigurationManager.AppSettings["ValidAudience"], ConfigurationManager.AppSettings["ValidIssuer"]);
}
catch (Exception ex)
{
throw;
}
return "value";
}
'/Get' request fails with HTTP 401.
BUT For the same JWT token 'Get/5' returns HTTP 200 (validates token manually).
The problem is, when I use Authorize attribute, api returns 401.
According to your description, I checked this issue on my side.
Access the protected Web API
In summary, you could refer to the above screen shoot and check with your api endpoint. Additionally, you could refer to AppServiceTokenHandler.cs and HmacSigningCredentials.cs for implementing your custom TokenHandler to troubleshoot this issue. Moreover, you could refer to adrian hall's book about Custom Authentication
.

MSIS9649: Received invalid OAuth request. The 'assertion' parameter value is not a valid access token

I am trying to implement ADFS4 - OAuth (OpenID connect) for authentication and webapp to webapi communication.
I have configured ADFS application group accordingly and use OpenIdconnectauth pipeline in webapp for authentication. In order to call webapi, if I request accesstoken using just client credential grant, it works fine as I receive the valid access token and able to get to the api. However, the access token does not have any user details in it which I need it from the webapi end.
So, then I tried by creating UserAssertion object from bootstrapcontext.token. But this time, when ever I request access token, I receive this error as mentioned in the title.
Here is the code snippet:
AuthenticationContext authContext = null;
AuthenticationResult result = null;
authContext = new AuthenticationContext(Startup.authority, false);
ClientCredential credential = new ClientCredential(Startup.clientId, Startup.appKey);
string usercheck = User.Identity.Name; //For checking, returns username
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string username = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userAccessToken = bootstrapContext.Token;
UserAssertion userAssertion = new UserAssertion(bootstrapContext.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer", username);
string accessToken = null;
HttpClient httpClient = new HttpClient();
try {
//result = authContext.AcquireTokenAsync(Startup.apiResourceId, credential).Result; // This works fine but no user details in the token
result = authContext.AcquireTokenAsync(Startup.apiResourceId, credential, userAssertion).Result;
}
Here is how the Startup.ConfigureAuth(IAppBuilder app) looks like in both webapp and webapi:
In webapp:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
AuthenticationType = OpenIdConnectAuthenticationDefaults.AuthenticationType,
MetadataAddress = metadataAddress,
PostLogoutRedirectUri = postLogoutRedirectUri,
RedirectUri = postLogoutRedirectUri,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
{
SaveSigninToken = true
},
ResponseType = "code id_token",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
}
});
}
And in webapi:
public void ConfigureAuth(IAppBuilder app)
{
JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
app.UseActiveDirectoryFederationServicesBearerAuthentication(
new ActiveDirectoryFederationServicesBearerAuthenticationOptions
{
MetadataEndpoint = ConfigurationManager.AppSettings["ida:AdfsMetadataEndpoint"],
TokenValidationParameters = new TokenValidationParameters() {
SaveSigninToken = true,
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
}
});
}
I reckon that the token that I am passing in to the userassertion is incorrect. But how can I fix this? Is there any other way which I can get the user details in to the access token. I really appreciate if anyone can help us to solve this issue?
Thanks.
You have to use authorization code flow to get the MVC app to talk to the API. Vittorio has a nice post on it here, although it talks about azure.
In order to do that you need to handle the AuthorizationCodeReceived Event via Notifications on the OpenIdConnectAuthenticationOptions from Startup.ConfigureAuth(IAppBuilder app)
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions {
...
Notifications = new OpenIdConnectAuthenticationNotifications {
AuthorizationCodeReceived = async code => {
ClientCredential credential = new ClientCredential(Startup.clientId, Startup.appKey);
AuthenticationContext authContext = new AuthenticationContext(Startup.authority, false);
AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
code.Code,
new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)),
credential,
Startup.apiResourceId);
}
}
When you are ready to make the call you acquire your token silently.
var authContext = new AuthenticationContext(Startup.authority, false);
var credential = new ClientCredential(Startup.clientId, Startup.appKey);
var claim = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
var userId = new UserIdentifier(claim, UserIdentifierType.UniqueId);
result = await authContext.AcquireTokenSilentAsync(
Startup.apiResourceId,
credential,
userId);
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer",
result.AccessToken);

WSO2 Identity Server with OpenId Connect

I am trying to use WSO2 Identity Server (5.1.0) with Asp.Net MVC, as a proof of concept i created a sample asp.net MVC project in visual studio 2015.
Following the WSO2 Guide, i have configured the identity server as required.
https://docs.wso2.com/display/IS510/OpenID+Connect+with+the+WSO2+Identity+Server+and+WSO2+OAuth2+Playground
On the sample application, i have added reference to Microsoft.Owin.Security.OpenIdConnect and added code to ConfigureAuth in Startup.Auth.cs file.
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
//{
// ClientId = "",
// ClientSecret = ""
//});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = "SENmQQ9fOWcrqXjK1u3lXINhXtEa",
ClientSecret = "bFBJQqj4GT2Wfv8735fTTuHh3Isa",
Authority = "https://localhost:9443",
RedirectUri = "https://wso2openid.local.co.uk/Account/ExternalLoginCallback",
SignInAsAuthenticationType = "ClientCredCookie",
ResponseType = "id_token token",
Scope = "openid",
Configuration = new OpenIdConnectConfiguration
{
AuthorizationEndpoint = "https://localhost:9443/oauth2/authorize",
TokenEndpoint = "https://localhost:9443/oauth2/token"
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
RedirectToIdentityProvider = n =>
{
return Task.FromResult(0);
},
SecurityTokenReceived = n =>
{
return Task.FromResult(0);
},
AuthorizationCodeReceived = n =>
{
return Task.FromResult(0);
},
SecurityTokenValidated = n =>
{
var token = n.ProtocolMessage.AccessToken;
// persist access token in cookie
if (!string.IsNullOrEmpty(token))
{
n.AuthenticationTicket.Identity.AddClaim(
new Claim("access_token", token));
}
return Task.FromResult(0);
},
AuthenticationFailed = notification =>
{
if (string.Equals(notification.ProtocolMessage.Error, "access_denied", StringComparison.Ordinal))
{
notification.HandleResponse();
notification.Response.Redirect("/");
}
return Task.FromResult<object>(null);
}
}
});
}
When i run the application, on login it redirects to WSO2 Identity Server login and manage to login but when it redirect to Account\ExternalLoginCallback, the logininfo is always null.
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
Any advise as to why this is not working will be appreciated.?
NB: I tried to put a break point on SecurityTokenValidated but it did not hit that break point. The only breakpoint which i got hit was RedirectToIdentityProvider.
It's work well for me:
Step1 : Config WSO2 with this:
https://docs.wso2.com/display/IS570/Logging+in+to+a+.NET+application+using+the+Identity+Server
Step2:
public async Task<RedirectResult> LoginOAuth()
{
var url = "https://localhost:9443/oauth2/authorize?response_type=code&client_id=5a8urZQAc0r4R7iUS9ar1wOoq9Ma&scope=openid&redirect_uri=http://localhost:49545/Home/GetCode";
var client = new HttpClient();
var response = await client.GetAsync(url);
string urlDistance = response.RequestMessage.RequestUri.ToString();
client.Dispose();
return Redirect(urlDistance);
}
public async Task<RedirectToRouteResult> GetCode()
{
//باشد GetCode همشون حتما باید
var client = new HttpClient();
string code = Request.QueryString["code"];
string sessionState = Request.QueryString["session_state"];
string client_id = Request.QueryString["client_id"];
client.Dispose();
//از طریق ارسال کد میخواد توکن رو بگیره
//****************
var values = new Dictionary<string, string>
{
{ "code", code },
{ "sessionState", sessionState },
{ "client_id", "5a8urZQAc0r4R7iUS9ar1wOoq9Ma" },
{ "client_secret", "b0yefcCc4ftVYJm7ffQi2IZZ0eMa" },
{ "grant_type", "authorization_code" },
{ "redirect_uri", "http://localhost:49545/Home/GetCode" }//??????????????
};
var content = new FormUrlEncodedContent(values);
client = new HttpClient();
var response2 = await client.PostAsync("https://localhost:9443/oauth2/token", content);
string responseString = await response2.Content.ReadAsStringAsync();
JObject jsonResult = JObject.Parse(responseString);
string access_token = jsonResult["access_token"].ToString();
string refresh_token = jsonResult["refresh_token"].ToString();
string scope = jsonResult["scope"].ToString();
string id_token = jsonResult["id_token"].ToString();
string token_type = jsonResult["token_type"].ToString();
string expires_in = jsonResult["expires_in"].ToString();
//**************
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("https://localhost:9443/oauth2/userinfo?schema=openid");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", access_token);
string result = await httpClient.GetStringAsync("/oauth2/userinfo?schema=openid");
return RedirectToAction("Contact");
}

OAuth token bearer extra user information

I am using Web API secured with OAuth Bearer token. When getting the token I want to send extra information to the user, so I tried the following as per this thread:
CustomOAuthProvider.cs:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Other stuff, cut off for brevity
var user = await userManager.FindAsync(context.UserName, context.Password);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");
oAuthIdentity.AddClaims(ExtendedClaimsProvider.GetClaims(user));
oAuthIdentity.AddClaims(RolesFromClaims.CreateRolesBasedOnClaims(oAuthIdentity));
var ticket = new AuthenticationTicket(oAuthIdentity, this.CreateProperties(user.UserName, oAuthIdentity));
context.Validated(ticket);
}
private AuthenticationProperties CreateProperties(string userName, ClaimsIdentity oAuthIdentity)
{
var data = new Dictionary<string, string>
{
{ "username", userName },
{ "roles", JsonConvert.SerializeObject(oAuthIdentity.Claims.Where(c=> c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray()) }
};
return new AuthenticationProperties(data);
}
But the returned object is always as following:
{
access_token: "theTokenHash"
expires_in: 86399
token_type: "bearer"
}
This is my Startup.cs:
public void Configuration(IAppBuilder app)
{
// AutoMapper
AutoMapperConfig.RegisterMappings();
var httpConfig = new HttpConfiguration();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
WebApiConfig.Register(httpConfig);
AutofacConfig.Register(httpConfig);
app.UseWebApi(httpConfig);
httpConfig.EnsureInitialized();
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
var OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://localhost:59822")
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
What am I doing wrong here?
Wow never mind, I dug into the full example given in the answer of the link. It seems that adding the extra fields isn't enough. You still have to add the parameters to the context yourself by overriding the TokenEndpoint function:
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}

How to do long lived tokens with Katana OAuth Bearer Tokens

From the SPA template i managed to get basic OAuth flows working.
OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
ApplicationCanDisplayErrors = true,
TokenEndpointPath = new Microsoft.Owin.PathString("/Token"),
AuthorizeEndpointPath = new Microsoft.Owin.PathString("/api/Account/ExternalLogin"),
Provider = new CompositeWebroleOauthProvider<User>(PublicClientId, IdentityManagerFactory, CookieOptions)
};
I have a single page application that is hosted on a seperate domain that will interact with the webapi using the bearer tokens from the Token endpoint.
I am doing the ResourceOwnerCredentials flow, with a request with the following data:
data: {
grant_type: "password",
username: username,
password: password
}
These tokens are short lived ect. I now would like to extend my application such I can get a refress token or something such I do not have to authenticate all the time.
What is my next steps?
The GrantResourceOwnerCredentials implementation:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (var identityManager = _identityManagerFactory.Create())
{
var user = await identityManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await identityManager.CreateIdentityAsync(user, context.Options.AuthenticationType);
AuthenticationProperties properties = CreatePropertiesAsync(user);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
}
}
I just had to set the provider for it to generate refresh tokens.
Any comments for pointers on when to set refresh tokens and not would be nice.
RefreshTokenProvider = new AuthenticationTokenProvider
{
OnCreate = CreateRefreshToken,
OnReceive = ReceiveRefreshToken,
}
private void CreateRefreshToken(AuthenticationTokenCreateContext context)
{
context.SetToken(context.SerializeTicket());
}
private void ReceiveRefreshToken(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}

Resources