Reputation: 51
I use aps.net core with JWT authentication and I found that aws cognito returns wrong token. Instead aud it returns client_id in access token. I use Nuget libraries
It was the same result. For examaple: Access token is:
{
"sub": "9ed87b45-da04-4fda-bc74-XXXXXXXXXXXX",
"event_id": "469880d0-8b17-417a-88d7-XXXXXXXXXXXX",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin",
"auth_time": 1583252488,
"iss": "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_XXXXXXXX",
"exp": 1583256088,
"iat": 1583252488,
"jti": "c1ca9561-51ce-4b57-9f51-3355363fb4f6",
"client_id": "AppClientIDXXXXXXXXXXXXX",
"username": "testname"
}
After all I found that id token returns with 'aud'
{
"sub": "9ed87b45-da04-4fda-bc74-XXXXXXXXXXXX",
"aud": "AppClientIDXXXXXXXXXXXXX",
"email_verified": true,
"event_id": "469880d0-8b17-417a-88d7-XXXXXXXXXXXX",
"token_use": "id",
"auth_time": 1583252488,
"iss": "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_XXXXXXXX",
"cognito:username": "testname",
"exp": 1583256088,
"iat": 1583252488,
"email": "[email protected]"
}
I used two way of adding jwt authentication. It didn't work for me. Example 1:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(parameters.ValidIssuer + "/.well-known/jwks.json");
return JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
},
ValidateIssuer = true,
ValidIssuer = $"https://cognito-idp.{region}.amazonaws.com/{poolId}",
ValidateAudience = true,
ValidAudience = appClientId,
};
});
Example 2:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Audience = appClientId;
options.Authority = $"https://cognito-idp.{region}.amazonaws.com/{poolId}";
});
My authentication code
using AWSSDK.CognitoIdentityProvider
var initiateAuthRequest = new InitiateAuthRequest()
{
ClientId = myClientId,
AuthFlow = AuthFlowType.USER_PASSWORD_AUTH,
};
initiateAuthRequest.AuthParameters.Add("USERNAME", user.Username);
initiateAuthRequest.AuthParameters.Add("PASSWORD", user.Password);
var authResponse = await _cognitoIdentityProvider.InitiateAuthAsync(initiateAuthRequest);
using Amazon.Extensions.CognitoAuthentication
var provider = new AmazonCognitoIdentityProviderClient(new EnvironmentVariablesAWSCredentials(), myRegion);
var userPool = new CognitoUserPool(myPool, myClient, provider);
var usr = new CognitoUser(user.Username, myClient, userPool, provider);
AuthFlowResponse authResponse = await usr.StartWithSrpAuthAsync(
new InitiateSrpAuthRequest(){Password = user.Password}).ConfigureAwait(false);
How to get valid JWT token? How to validate token correctly?
Updated: In Example 1 if I set ValidateAudience to false and removed ValidAudience I get 401 error
ValidateAudience = false,
//ValidAudience = appClientId
My Startup.cs is
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public static IConfiguration Configuration { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
var region = Configuration[Resources.AWSRegion];
var poolId = Configuration[Resources.AWSPoolId];
var appClientId = Configuration[Resources.AWSClientId];
services.AddSingleton<IAmazonCognitoIdentityProvider>(provider => new AmazonCognitoIdentityProviderClient(RegionEndpoint.USEast2)));
services.AddControllers();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(parameters.ValidIssuer + "/.well-known/jwks.json");
return JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
},
ValidateIssuer = true,
ValidIssuer = $"https://cognito-idp.{region}.amazonaws.com/{poolId}",
ValidateAudience = true,
ValidAudience = appClientId
};
});
services.AddAuthorization();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseAuthentication();
}
}
Upvotes: 5
Views: 3088
Reputation: 169
I read several answers and the majority recomended setting
ValidateAudience = false
Since I didn't want to do that, because it will avoid validating the correct audience, 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
Upvotes: 3
Reputation: 11
I think it is because you use the access jwt token returned from Cognito during sign-in. Use id token instead.
return new Promise((resolve, reject) => {
return user.authenticateUser(authenticationDetails, {
onFailure: (err) => {
reject(err);
},
onSuccess: (result) => {
resolve(new SignInResponse(result.getIdToken().getJwtToken()));
},
});
});
Upvotes: 1
Reputation: 1
I had the same issue and I have found only one solution.
If you are going to use an access token to authenticate user, set
ValidateAudience = false,
//ValidAudience = appClientId
and add AuthenticationSchemes to Authorize filter like that:
[HttpGet]
[Authorize(AuthenticationSchemes = "Bearer")]
public async Task<string> Test()
{
return await Task.Run(() => "hello world");
}
I have very similar code and it worked for me. Hope it helps for you as well.
Also you can replace this code:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
To that (just to simplify):
services.AddAuthentication("Bearer")
Upvotes: 0
Reputation: 13
This worked out for me, I used id token instead of access token
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = GetCognitoTokenValidationParams();
});
}
private TokenValidationParameters GetCognitoTokenValidationParams()
{
var cognitoIssuer = $"https://cognito-idp.{Configuration["AWS:Region"]}.amazonaws.com/{Configuration["AWS:UserPoolId"]}";
var jwtKeySetUrl = $"{cognitoIssuer}/.well-known/jwks.json";
var cognitoAudience = Configuration["AWS:UserPoolClientId"];
return new TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
// get JsonWebKeySet from AWS
var json = new WebClient().DownloadString(jwtKeySetUrl);
return JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
},
ValidIssuer = cognitoIssuer,
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidAudience = cognitoAudience
};
}
Upvotes: 1