Search code examples
azure-active-directorymicrosoft-graph-apiadalazure-ad-msalcortana-skills-kit

On behalf of token issue (AADSTS50013: Assertion contains an invalid signature)


I'm getting an error (mentioned below) when I'm trying to use Cortana Bot user token (which is a Graph token) to generate an "on-behalf-of" token to another consuming Web API application using ClientAssertionCertificate / ClientCredential targeted to another consuming Web API by passing its AppId as ResourceId and userAssertion generated by using Cortana Bot user token.

When checked our Bot AAD settings it is configured with other consuming Web API (API B) as valid application along with Graph application. Do we need to do any additional setting in AAD to get this on-behalf-of token?

AADSTS50013: Assertion contains an invalid signature. 
[Reason - The provided signature value did not match the expected signature value., 
    Thumbprint of key used by client: '9DB0B05B5D70DD7901FB151A5F029148B8CC1C64', 
    Found key 'Start=11/11/2018 00:00:00, 
    End=11/11/2020 00:00:00'
]
Trace ID: a440869f-b8f5-4d87-ba1a-6bd8dd7ba200
Correlation ID: 651e1fa8-2069-4489-a687-e68e5206e193
Timestamp: 2019-01-02 07:14:45Z

Following is the flow and Sample code how we are trying to get an on-behalf-of token for other consuming Web API (API B).

Flow Steps:

  1. Cortana asks for user Sign-in
  2. User Sign-in to Cortana
  3. Cortana sends this user token (generated targeting to use https://graph.microsoft.com as Audience) to Microsoft Bot Framework API
  4. Microsoft Bot Framework API validates and wants to consume this token for calling other Web API (which is called API B).
  5. As this Cortana user token cannot be used directly, it needs to be generated as an on-behalf-of token to API B from Microsoft Bot Framework API.
  6. Following is the code sample used to generate an on-behalf-of token from Microsoft Bot Framework API:

    public async Task<string> GetOnBehalfOfTokenAsync(string authority, string resource, string scope = "", string token = "") 
    {
        AuthenticationResult output;
        var clientId = ConfigurationManager.AppSettings["API-B-ClientId"];
    
        // Read certificate which can be used for getting token to API B using ClientAssertionCertificate
        // GetCert() is used to get the Certificate based on Thumbprint configured in Web.config file.
        var certificate = this.GetCert();
    
        // 'authority' is https://login.microsoftonline.com/{tenant id}
        var authContext = new AuthenticationContext(authority);
        var cllientCertificateCredential = new ClientAssertionCertificate(clientId, certificate);
    
        // 'token' is the user token which was received from Cortana.
        var userAssertion = (!string.IsNullOrWhiteSpace(token)) ?
            new UserAssertion(token, "urn:ietf:params:oauth:grant-type:jwt-bearer", 
                TokenHelper.ExtractUserInfoFromAuthToken(token, "upn")) : null;
        try 
        {
            // 'resource' is the Resource Id of API B
            // if UserAssertion is null then get token with ClientAssertionCertificate else get 
            // on-behalf-of token using UserAssertion and ClientAssertionCertificate
            if (userAssertion == null) 
            {
                output = await authContext
                    .AcquireTokenAsync(resource, cllientCertificateCredential)
                    .ConfigureAwait(false);
            }   
            else 
            {
                output = await authContext
                    .AcquireTokenAsync(resource, cllientCertificateCredential, userAssertion)
                    .ConfigureAwait(false);
            }
        } 
        catch (Exception ex) 
        {
            logger.log("Error acquiring the AAD authentication token", ex);
        }
    
        return output.AccessToken;
    }
    
  7. Getting an exception which was mentioned above at this step:

    output = await authContext
       .AcquireTokenAsync(resource, cllientCertificateCredential, userAssertion)
        .ConfigureAwait(false);
    

Solution

  • We could able to resolve this issue by configuring our dependent custom API (API B) "user_impersonation" scope to Cortana channel configuration to our Bot. With this configuration change, we do not need to generate On-Behalf-Of token to API B from our Microsoft Bot application.

    Thanks to all who has supported to provide solutions for this thread...