Hinrich
Hinrich

Reputation: 13983

Asp.Net - Jwt Bearer Authentication: Invalid Signature

I obtain an access_token and id_token from AzureAD for my app, which is using OAuth2 with the implicit flow. This is a sample URL where I obtain the tokens:

https://login.microsoftonline.com/my_tenant_id/oauth2/v2.0/authorize?response_type=id_token+token&client_id=my_client_id&state=some_state&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Fsign-in&scope=openid%20https%3A%2F%2Fgraph.microsoft.com%2Fuser.read&nonce=some_nonce

The scope is openid https://grap.microsoft.com/user.read.

The response_type is id_token+token.

I also have a Asp.Net backend, I want to secure. So I use the Authorize Attribute for my controller and send a token in the header as like this: Authentication : "Bearer THE_TOKEN".

My configuration in Startup.cs looks like this:

app.UseJwtBearerAuthentication(new JwtBearerOptions
{
    Authority = string.Format("https://login.microsoftonline.com/{0}/v2.0/",
            "d67853c3-db96-4dac-a37b-f2bfb12b42d1"),
    Audience = "8422b3fb-5612-4fdd-a90f-707d7218de57"
});

From what I have read, the access token should be used for this, and the id_token should not leave the frontend. But authentication in the backend only works with the id token in my case. The access_token can not be signed Bearer error="invalid_token", error_description="The signature is invalid".

Looking at the access_token in jwt.io, I see the tokens have different audiences and issuers. The access_token for example has this

"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/d67853c3-db96-4dac-a37b-f2bfb12b42d1/",

whereas the id token has this

"aud": "my_client_id",
"iss": "https://login.microsoftonline.com/my_tenant_id/v2.0",

So it seems to me, the access_token was somehow issued for the Graph API. Would be glad if someone could tell me, what i am doing wrong or how I can try to solve my issues.

edit: It WAS working as intended before when I used the scope openid profile. But due to changes in Azure, this scope is not valid anymore and Microsoft directed me to use the scope mentioned above.

Upvotes: 0

Views: 2585

Answers (1)

Fei Xue
Fei Xue

Reputation: 14649

As you mentioned, the access token you requested is for the Microsoft Graph. And the id_token is only for the client to authenticate the user instead of for the resource server.

To protect the web API using the Azure AD V2.0 endpoint, we can acquire the access token for the web API like request below:

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=token&client_id={client_id}&scope=api://{client_id}/access_as_user&redirect_uri={redirect_uri}

And here is the code using protecting the web API via Azure AD V2.0 endpoint:

public void ConfigureAuth(IAppBuilder app)
{
    System.Diagnostics.Trace.TraceWarning("Hello");
    var tvps = new TokenValidationParameters
    {
        // The web app and the service are sharing the same clientId
        ValidAudience = clientId,
        ValidateIssuer = false,
    };

    // NOTE: The usual WindowsAzureActiveDirectoryBearerAuthenticaitonMiddleware uses a
    // metadata endpoint which is not supported by the v2.0 endpoint.  Instead, this 
    // OpenIdConenctCachingSecurityTokenProvider can be used to fetch & use the OpenIdConnect
    // metadata document.

    app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
    {
        AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider("https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration")),
    });
}

}

More detail about protecting the web API via Azure AD V2.0 endpoint, you can refer the document below:

Calling a web API from a .NET web app

Upvotes: 2

Related Questions