Auth0 - Authenticating with RS256 using JWT on Owin with bearer-accessToken - asp.net-web-api2

While implementing Auth0 Authentication/Authorization with a normal embedded login, I am able to authenticate the user and gets back the valid accessToken/idToken.
Initialization
webAuth = new auth0.WebAuth({
domain: 'xxx.auth0.com',
clientID: 'myclientid',
responseType: 'token id_token'
});
Successfully getting token.
webAuth.client.login({
realm: _Connection,
username: 'aaa#b.com',
password: 'password',
audience: 'https://xxx.auth0.com/api/v2/',
scope: 'openid profile email'
}, function (err, args) {
if (!err)
{
webAuth.client.userInfo(token, function (args, authUserData) {
var ajaxAdapter = breeze.config.getAdapterInstance("ajax");
***Setting bearer token to Global level.**
ajaxAdapter.defaultSettings = {
headers: ({ "Authorization": "Bearer " + token })
};
myAPICall(args.email).then({}).fail({});
});
}
});
Server code which is validating RS256 signed JWT with OWIN.
private void ConfigureAuthZero(IAppBuilder app)
{
var issuer = $"https://{ConfigurationManager.AppSettings["Auth0:Domain"]}/";
var audience = ConfigurationManager.AppSettings["Auth0:ClientID"];
var apiIdentifier = ConfigurationManager.AppSettings["Auth0:ApiIdentifier"];
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
string certificatePath = HostingEnvironment.MapPath("~/mycertificate.cer");
var certificate = new X509Certificate2(certificatePath);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = audience,
ValidIssuer = issuer,
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) => new X509SecurityKey(certificate)
}
});
}
My Problem:
The above server code won't authorize the user.
But if I set ValidAudience = "https://xxx.auth0.com/api/v2/" i.e to Auth0 API Identifier, then the API method successfully authorizes (status 200) the user.
But this time it won't give ClaimsIdentity.Claims with ClaimTypes.Email
What am I missing here?

My mistakes:
I should pass ApiIdentifier to ValidAudience value.
As I was passing accessToken while authorizing the user, by the
time the accessToken claims doesn't contain the ClaimTypes.Email, so
I need to set the rules in Auth0 as:How to set the rules in Auth0.
Which later I can check in my server api logic as(below code) to
validate the user.
(User.Identity as ClaimsIdentity)?.Claims.FirstOrDefault(c => c.Type == "you-have-set-this-rule-in-auth0")?.Value;
Just to Add-on, The Link worth reading while implementing the Auth0.
Auth0 has provided a nice nuget package Auth0.OpenIdConnectSigningKeyResolver which has a nice use in the above provided link.

Related

Automatic login using jwt in Cookie in ASP.net MVC Core

My process flow is :
User logs into a Issuer Application (Username/Password)
Clicks a link of the Client Application that they want to goto
Issuer Application creates a jwt and stores it in a Cookie
Issuer Application does a Response.Redirect to Client Application
Client Application authenticates user using the jwt in the Cookie and creates the Principal and automatically logs in user.
Below is my Client Application setting from the Startup ConfigureServices method:
var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("password"));
SigningCredentials SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidIssuer = "issuerapp",
ValidateAudience = false,
ValidAudience = "clientapp",
ValidateIssuerSigningKey = true,
IssuerSigningKey = SigningCredentials.Key,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.ClaimsIssuer = "issuerapp";
options.TokenValidationParameters = tokenValidationParameters;
options.SaveToken = true;
})
.AddCookie(JwtBearerDefaults.AuthenticationScheme,
options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.Name = Configuration.GetValue<string>("AppSettings:CookieName");
options.AccessDeniedPath = authenticationSettings.AccessDeniedPath;
options.Events = new CookieAuthenticationEvents
{
// Check if JWT needs refreshed
OnValidatePrincipal = RefreshTokenMonitor.ValidateAsync,
OnSigningOut = (context) =>
{
context.HttpContext.Response.Redirect(Configuration.GetValue<string>("AppSettings:LogoutPath"));
return Task.CompletedTask;
},
};
});
In my Client Application I have all controllers decorated with [Authorize] attribute.
I need the Client Application automatically authenticating the user using the jwt. Which is not happening using the above mentioned configurations.
My AccessDeniedPath (Action Method) is not getting hit either.
The workaround that I have been using is to redirect user from the Issuer Applicaiton to a Login action in the Client Application where :
I read the jwt from the Cookie
Validate the jwt to get the Principal
Call httpContext.SignInAsync
How can I get the user logged in automatically using the jwt.
Any help / pointer are appreciated.
Thanks.
By default , the AddJwtBearer extension will get the token from request's Authorization header :
Authorization: Bearer <token>
But you are pass the token in cookie , so you can find the token in cookie and set token in OnMessageReceived event in AddJwtBearer :
options.Events = new JwtBearerEvents {
OnMessageReceived = ctx =>
{
ctx.Token = ctx.HttpContext.Request.Cookies["jwt"];
return Task.CompletedTask;
}
};

Can't get asp .net core 2.2 to validate my JWT

(TL;DR: check the last update)
The first issue with this is that the API has changed between the different versions of .net core.
The second one is that every example I find online is slightly different with not real authoritative answer as to what does what; rather I keep finding posts with 'oh, changing this worked for me', but it looks like everyone is, like me, experimenting with it rather than having a full understanding.
Anyhow, here is the code:
Services.AddAuthentication(A =>
{
A.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
A.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(O =>
{
O.RequireHttpsMetadata = false;
O.SaveToken = true;
O.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AuthJWTPublicKey)),
ValidateIssuer = false,
ValidateAudience = false
};
});
I have a valid JWT but any call to my controller results in an immediate error 401.
I have tried to decorate the controller with:
[Authorize]
[Authorize(Roles = "offline_access")]
[Authorize(AuthenticationSchemes =
JwtBearerDefaults.AuthenticationScheme, Roles = "offline_access")]
but no luck
The JWT content is:
{
"jti":"837c2dd1-cca5-491e-84a4-b17429366df5",
"exp":1558355152,
"nbf":0,
"iat":1558354852,
"iss":"xxxx",
"aud":"account",
"sub":"4ed1c313-c692-44db-86d3-7605f3e2c2c1",
"typ":"Bearer",
"azp":"test-app",
"auth_time":1558354850,
"session_state":"e40c9a95-ae8a-4d6e-b2a4-ad5e833867ea",
"acr":"1",
"realm_access":{
"roles":[
"offline_access",
"uma_authorization"
]
},
"resource_access":{
"account":{
"roles":[
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope":"openid email profile",
"email_verified":true,
"name":"firstd6d05 last29954",
"preferred_username":"xxxx",
"given_name":"firstd6d05",
"family_name":"last29954",
"email":"xxxx",
"group":[
"/Administrators"
]
}
My goal is purely to verify the signature of the JWT (and eventually it's expiration) and have access to the token in the controller.
I am passing the JWT through the header, under 'Authorization' and with the text 'Bearer' in front of the token.
What am I missing?
Following the answer below, I did the following change:
I added:
Services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
and then added the following class with a break
internal class ClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
Debugger.Break();
}
}
but I am still getting a 401 with the Keycloak token; so it looks like it doesn't get to the claims transformer before being rejected.
I added the debug output of ASP.
It is at: https://pastebin.com/qvGsQG6j
The relevant part seems to be:
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
=> ConnectionId:0HLN4CPASJL8F => RequestId:0HLN4CPASJL8F:00000001 RequestPath:/helpers/log => Test.WebControllers.HelpersController.GetLog (Test)
Authorization failed.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Info:Authorization failed.
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Info:Authorization failed.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[3]
=> ConnectionId:0HLN4CPASJL8F => RequestId:0HLN4CPASJL8F:00000001 RequestPath:/helpers/log => Test.WebControllers.HelpersController.GetLog (Test)
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Info:Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Info:Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
=> ConnectionId:0HLN4CPASJL8F => RequestId:0HLN4CPASJL8F:00000001 RequestPath:/helpers/log => Test.WebControllers.HelpersController.GetLog (Test)
This specific line may explain the issue:
Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'
but 'failed' seems a bit vague to me.
Last test:
I have this token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoibXkgbmFtZSIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL2VtYWlsYWRkcmVzcyI6Im5vQGVtYWlsLmNvbSIsImh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9jbGFpbXMvZXhwaXJhdGlvbiI6IjA1LzMxLzIwMTkgMDA6MTM6MjAiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9zaWQiOiI3Y2FjZjdiNS04NjY5LTQ2OWUtOTg4NS1kNDgwNGYyOGNjNGEiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA5LzA5L2lkZW50aXR5L2NsYWltcy9hY3RvciI6ImQyZjZiNzI0LWE0ZjktNGJkZC1hNjQ3LTRkM2UxYTU5NjhkZSIsIm5iZiI6MTU1OTE3NTIwMCwiZXhwIjoxNTU5MjYxNjAwLCJpc3MiOiJ0ZXN0IiwiYXVkIjoidGVzdC1hcHAifQ.y42RUvMM69aDTvCydoU3mOKu2giub6OvKpd-RNVmom4
with the key:
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjayVuqZOuKK38rhsRwrRGzVcv/7b4fHXrzpol3K5TTAPttNUaQvCKQD7BQN+V8nvkBsQcxPk5ONnxzbFb/npENC4UtwK5J6iiVrinE7sDrWZQNo9LkwbuG9x0fuuf8U3H2CnwZEfFaf2kbU1v7XosNGi+aYASupvhwoiJtK+17ZPloxSQy3Qny2tQWi7Dh/Cr5+m5JBy6HeGLq2cq+oalFYzrGGmQXndLtJpBZgrPd7nR6lJSMiRcJtcpxTJbYTEVVXoB0SR1bPmYYB/6y7klVDVedTow+1mwZrDMrbRiTBPSifCIBs3rxLQaL207blg+kj+EVLED5fZSOBlOyTOYQIDAQAB
it decodes to (as tested by jwt.io):
{
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "my name",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "no#email.com",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/expiration": "05/31/2019 00:13:20",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid": "7cacf7b5-8669-469e-9885-d4804f28cc4a",
"http://schemas.xmlsoap.org/ws/2009/09/identity/claims/actor": "d2f6b724-a4f9-4bdd-a647-4d3e1a5968de",
"nbf": 1559175200,
"exp": 1559261600,
"iss": "test",
"aud": "test-app"
}
it is generated by the following code:
var Expiration = DateTime.UtcNow + TimeSpan.FromDays(1);
var Identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "my name"),
new Claim(ClaimTypes.Email, "no#email.com"),
new Claim(ClaimTypes.Expiration, Expiration.ToString(CultureInfo.InvariantCulture)),
new Claim(ClaimTypes.Sid, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.Actor, Guid.NewGuid().ToString()),
});
var Token = new JwtSecurityToken
(
issuer: "test",
audience: "test-app",
claims: Identity.Claims,
notBefore: DateTime.UtcNow,
expires: Expiration,
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_JwtRsaPublicKey)), SecurityAlgorithms.HmacSha256)
);
var TokenString = new JwtSecurityTokenHandler().WriteToken(Token);
return TokenString;
In asp, I have the following code:
Services.AddAuthentication(A =>
{
A.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
A.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(O =>
{
O.RequireHttpsMetadata = false;
O.SaveToken = true;
O.IncludeErrorDetails = true;
O.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AuthJWTPublicKey)),
ValidateIssuer = false,
ValidateAudience = false
};
});
and I have a controller method with:
[Authorize]
But I keep getting a 401, no matter what I try, I get a 401...
Even if I set ValidateIssuerSigningKey to false. I get a 401
The setup is:
In ConfigureServices, I have:
Services.AddMvc()
and the code above
In Configure, I have:
Application.UseAuthentication();
Application.UseMvc(Routes => { Routes.MapRoute("default_route", "{controller}/{action}/{id?}"); });
According to dotnet/corefx:
public static class ClaimTypes
{
internal const string ClaimTypeNamespace ="http://schemas.microsoft.com/ws/2008/06/identity/claims";
....
public const string Role = ClaimTypeNamespace + "/role";
...
The const ClaimTypes.Role is http://schemas.microsoft.com/ws/2008/06/identity/claims/role
Note your controller requires a role of offline_access:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "offline_access")]
In other words, it expects the decoded JWT has a property of http://schemas.microsoft.com/ws/2008/06/identity/claims/role to configure the roles:
{
"nbf": ...,
"exp": ...,
"iss": ...,
"aud": ...,
...,
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [
"offline_access",
"...other roles"
],
}
However, you configure the roles in the following way:
"realm_access":{
"roles":[
"offline_access",
"uma_authorization"
]
},
The easiest way is rebuild the token to config a role of offline_access:
ClaimsIdentity identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name,"1024"),
new Claim(ClaimTypes.Role,"offline_access"),
new Claim(ClaimTypes.Role,"...other roles"),
// ... other claims
});
var token = new JwtSecurityToken
(
issuer: _issuer,
audience: _audience,
claims: identity.Claims,
expires: expiry,
notBefore: DateTime.UtcNow,
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(mykeyname)),
SecurityAlgorithms.HmacSha256)
);
var tokenStr = tokenHandler.WriteToken(token);
Or you could transform the keycloak's style claim to Microsoft's style by registering a custom IClaimsTransformation, see a Sample by ASP.NET Core Team https://github.com/aspnet/AspNetCore/blob/658b37d2bd3b0da2c07e25b53fa5c97ce8d656d3/src/Security/samples/ClaimsTransformation/Startup.cs#L34
I am not sure what is stored in the variable but it looks like it's not a private token:
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(AuthJWTPublicKey)),
This is as far as I know a private symmetric key, perhaps you are passing a wrong value in there?
You can modify keycloak configuration for JWT creation to map the roles to "roles" item instead grouping under "realm_access".
This can be done by adding a Mapper in Keycloak client.
This works for me:
Keycloak Mapper
You can also create a second Mapper for "User Client Role". Just select "User Client Role" for Mapper Type.

ASP.Net Core - JWT Authentication with WebAPI and MVC Frontend not working

The Project consists of two Parts:
ASP.Net Core API
ASP.Net Core MVC Frontend
Basically, what I want to do is authentication via JWT. So the API issues JWT and the MVC Frontend uses Identity with the claims and roles declared in the JWT.
Startup.cs in the API:
private const string SecretKey = "my_Secret_Key";
private readonly SymmetricSecurityKey _signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(SecretKey));
#region JWT Auth
// jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy(Constants.Policies.ApiAccess, policy => policy.RequireClaim(Constants.JwtClaimIdentifiers.Rol, Constants.JwtClaims.ApiAccess));
});
#endregion
JWT Generation:
public async Task<string> GenerateEncodedToken(string userName)
{
User user = _userManager.GetUserByUserName(userName);
List<string> userRoles = _userManager.GetRoles(user.Guid);
var claimsToEncode = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim("web", user.WebId),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
new Claim(Constants.JwtClaimIdentifiers.Rol,Constants.JwtClaims.ApiAccess),
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claimsToEncode,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
jwt.Payload.Add("roles", userRoles.ToArray());
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
Authorization works like a charm with this in the API.
Now I want to do the following:
Implement the same in the Frontend, so that:
MVC Frontend receives Credentials, send them to the API, get Token, and Authorize with the Claims and Roles in the Token.
I tried several things, but none of them worked so far.
What do I have to insert in the Startup.cs in the Frontend so that Identity checks not against the secret key (which the Frontend is not allowed to have) but against a public key? Or do I have to implement a Endpoint in the API which validates the JWT remotely?
When you get the token in web client, you can store it in a session object and send that whenever you are requesting something from the webapi

AWS cognito: Auto login after registration confirmation

I am using the JavaScript SDK of AWS Cognito (http://docs.aws.amazon.com/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-javascript-examples.html).
When a new user completes registration confirmation, the documentation says the user is now ready to sign in. Is it possible to automatically sign in the user at this time?
For eg., after confirmation when I use the following I get null:
userPool.getCurrentUser();
If this is the intended behavior, are there any ways to sign in the user without explicitly asking the user again?
I know this is not a good idea, one thing I can think of is to save the user credentials in local storage and use them after confirmation to automatically sign in. Any other ideas better than this?
Upon user signup, your backend will be receiving users credentials, which you can use to generate the JWT token. Then you can add the JWT token in the same response, which can be use by the browser client to request authorized endpoints.
Example:
AWSCognito.config.region = 'us-east-1'; //This is required to derive the endpoint
var poolData = {
UserPoolId: 'us-east-1_TcoKGbf7n',
ClientId: '4pe2usejqcdmhi0a25jp4b5sh3'
};
var userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);
var attributeList = [];
var dataEmail = {
Name: 'email',
Value: 'email#mydomain.com'
};
var authenticationData = {
Username: 'username',
Password: 'password',
};
var attributeEmail = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserAttribute(dataEmail);
attributeList.push(attributeEmail);
userPool.signUp(authenticationData.Username, authenticationData.Password, attributeList, null, function (err, result) {
if (err) {
alert(err);
return;
}
var authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);
var userData = {
Username: authenticationData.Username,
Pool: userPool
};
var cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
console.log('access token + ' + result.getAccessToken().getJwtToken());
/*Use the idToken for Logins Map when Federating User Pools with Cognito Identity or when passing through an Authorization Header to an API Gateway Authorizer*/
console.log('idToken + ' + result.idToken.jwtToken);
/*Return the result.idToken.jwtToken with the response*/
},
onFailure: function (err) {
alert(err);
},
});
});

Thinktecture IdentityServer v3 LogOut for Implicit flow

How do I get the id_token for the implicit token to pass in the id_token hint for logout for implicit flow or is there another way? I have the end point /connect/endsession?
id_token_hint=
Not sure how I get the id_token from the implict flow all I get is a access_token and expiration. Is there a setting in IdSvr?
There's three components to this.
First ensure you're requesting an id_token from Identity Server when you're configuring the OIDC authentication in your Startup.cs (as mentioned by #leastprivilege above):
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "https://localhost:44301/",
...
ResponseType = "id_token token", //(Here's where we request id_token!)
Secondly, using the OIDC notifications & after the security token is validated you add the id_token to your user's claims:
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
var nid = new ClaimsIdentity(
n.AuthenticationTicket.Identity.AuthenticationType,
Constants.ClaimTypes.GivenName,
Constants.ClaimTypes.Role);
// get userinfo data
var userInfoClient = new UserInfoClient(
new Uri(n.Options.Authority + "/" + Constants.RoutePaths.Oidc.UserInfo),
n.ProtocolMessage.AccessToken);
var userInfo = await userInfoClient.GetAsync();
userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Item1, ui.Item2)));
// keep the id_token for logout (**This bit**)
nid.AddClaim(new Claim(Constants.TokenTypes.IdentityToken, n.ProtocolMessage.IdToken));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
},
Finally, on the redirect for signout (also a notification event) you add the id_token to the Protocol Message:
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst(Constants.TokenTypes.IdentityToken);
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
You'll also need to ensure you setup the PostLogoutRedirectUris on the client within Identity Server:
new Client
{
Enabled = true,
ClientName = "(MVC) Web App",
ClientId = "mvc",
Flow = Flows.Implicit,
PostLogoutRedirectUris = new List<string>
{
"https://localhost:44300/" //(** The client's Url**)
}
}
That will ensure you give the user an option to return to the authorised client when they log out :)
All of this is pretty much as per the MVC Sample at https://identityserver.github.io/Documentation/docsv2/overview/mvcGettingStarted.html
Bit more than you asked for but hopefully that helps anyone else who's trying to figure it out too :)
To get an id_token, you have to ask for it. Use response_type=id_token token
Have you tried this?
ASP.Net Identity Logout
It should create the id token hint automatically