Aws-lambda-dotnet: JWT-Bearer Signature Validation failed (IDX10501)

Created on 31 Jul 2018  路  1Comment  路  Source: aws/aws-lambda-dotnet

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

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 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

>All comments

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

Was this page helpful?
0 / 5 - 0 ratings