'AWS Cognito AccessToken vs IdToken
I created a .net Core API using the AWS Cognito SDK to authenticate and authorize users by posting credentials to my API and returning a JWT to a simple client side app (plain HTML/TypeScript). The request contains the user name and password.
...
var response = await cognito.AdminInitiateAuthAsync(request);
return Ok(response.AuthenticationResult.AccessToken);
vs
return Ok(response.AuthenticationResult.IdToken);
The problem I'm having is understanding why there are ID Tokens and Access Tokens. I'm able to secure controller endpoints with the [Authorize] attribute. The client app uses the Authorization header with Bearer {token}.
In my Startup.cs I'm able to AddAuthentication and verify the Signature, Issuer, Audience and Lifetime of the ID Token. However, I read that the ID Token contains claims about the identity of the user but not claims about the groups for authorization of the user. If I send the Access Token to my client and try to send this back to my API, I'm getting unauthorized. Maybe I'm not verifying the token properly but I still don't understand why there are two different types of tokens. The Access Token makes more sense to use for creating different auth policies based on claims the token contains.
The way I understand how JWT's work is that once a client obtains a token it stores it and uses it for all request to an API. I don't understand how this is supposed to work with two tokens.
Here is how I'm trying to validate the access token:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>{
options.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
// get JsonWebKeySet from AWS
var json = new WebClient().DownloadString(parameters.ValidIssuer + "/.well-known/jwks.json");
// serialize the result
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
// cast the result to be the type expected by IssuerSigningKeyResolver
return (IEnumerable<SecurityKey>)keys;
},
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Authentication:Cognito:MetadataAddress"],
ValidateIssuer = true,
ValidAudience = Configuration["Authentication:Cognito:ClientId"],
ValidateAudience = true,
ValidateLifetime = true,
RequireSignedTokens = true
};
});
There is no aud claim in the access token so I'm getting an error "Invalid token, audience = 'empty' is invalid.
Even if I remove ValidateAudience, I still get the error
Solution 1:[1]
For others, as me arriving through google, you can take a look to this other answer https://stackoverflow.com/a/70836794/9219975
I read several answers and the majority recomended setting
ValidateAudience = false
Since I didn't want to do that I ended up defining AudienceValidator, to do it you have to define a delegate in the options when configuring your application. So in Startup you have to include this:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Audience = configuration["AWS:Cognito:ClientId"];
options.Authority = configuration["AWS:Cognito:Authority"];
options.TokenValidationParameters.AudienceValidator = (audiences, securityToken, validationParameters) =>
{
//This is necessary because Cognito tokens doesn't have "aud" claim. Instead the audience is set in "client_id"
return validationParameters.ValidAudience.Contains(((JwtSecurityToken)securityToken).Payload["client_id"].ToString());
};
});
This will check that the claim "client_id" corresponds with the audience you're expecting
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
