Hello,
I have an ASP.NET Core Serverless Project secured with bearer tokens provided by aws cognito. The Application consists of multiple routes (Controllers) and is available through aws api gateway configured as a proxy resource.
My Startup.cs
configuration consists of the following parts:
Authentication:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (t, st, i, p) =>
{
// Return correct json web key based on kid value
},
ValidIssuer = _awsIssuer,
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidateAudience = false, // Not provided by cognito
ClockSkew = TimeSpan.FromSeconds(5)
};
});
Authorization (checks if user is in a specific group)
services.AddAuthorization(
options =>
{
options.AddPolicy("AdministratorsGroup", policy => policy
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.AddRequirements(new CognitoGroupAuthorizationRequirement("Administrators"))
.Build());
}
);
The json web keys are requested from https://cognito-idp.{_region}.amazonaws.com/{_userPoolId}/.well-known/jwks.json
and resolved in the TokenValidationParameters.IssuerSigningKeyResolver
-Method.
If I run the application locally all requests are authorized correctly - so far so good! If the application deployed to aws lambda + api gateway in front of it (with lambda proxy integration) the provided token麓s signature is not validated anymore.
Cloudwatch: Bearer was not authenticated. Failure message: IDX10501: Signature validation failed. Unable to match keys: '...',
The token can be read with all required information (user, groups etc.), only the signature validation fails.
Is there any issue with the combination of API-Gateway+Lambda+ASP.NET Core Security?
Thanks in advance!
David
Okay, I was able to fix the problem by myself.
Solution:
I used the Base64UrlEncoder.DecodeBytes(...)
-Method to import the parameters into the RsaSecurityKey
.
Old:
using (var rsa = RSA.Create())
{
rsa.ImportParameters(
new RSAParameters
{
Modulus = Base64UrlEncoder.DecodeBytes(key),
Exponent = Base64UrlEncoder.DecodeBytes(exponent)
});
return new SecurityKey[] { new RsaSecurityKey(rsa) };
}
New:
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(
new RSAParameters
{
Modulus = FromBase64Url(key),
Exponent = FromBase64Url(exponent)
});
return new SecurityKey[] { new RsaSecurityKey(rsa) };
}
// see: https://stackoverflow.com/questions/34403823/verifying-jwt-signed-with-the-rs256-algorithm-using-public-key-in-c-sharp
static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/")
.Replace("-", "+");
return Convert.FromBase64String(base64);
}
Now the Bearer-Token is successfully validated in AWS Lambda :)
Greetings,
David
Most helpful comment
Okay, I was able to fix the problem by myself.
Solution:
I used the
Base64UrlEncoder.DecodeBytes(...)
-Method to import the parameters into theRsaSecurityKey
.Old:
New:
Now the Bearer-Token is successfully validated in AWS Lambda :)
Greetings,
David