OfficeDev / office-js

A repo and NPM package for Office.js, corresponding to a copy of what gets published to the official "evergreen" Office.js CDN, at https://appsforoffice.microsoft.com/lib/1/hosted/office.js.
https://learn.microsoft.com/javascript/api/overview
Other
687 stars 95 forks source link

NAA returns an "invalid" JWT #5069

Open barclayadam opened 3 days ago

barclayadam commented 3 days ago

When creating an NAA token the generated token cannot be validated as a valid JWT using the keys from https://login.microsoftonline.com/common/discovery/keys

Your Environment

Expected behavior

A validatable token (where the signing key being produced is correct) to be generated. We are migrating from legacy tokens to NAA. We only use the tokens as an SSO exchange on our platform, we have no need to use the tokens with Graph or other MS products.

Current behavior

We get quite different JWTs depending on the scopes requested (we do not need to call Graph so would prefer only the openid and profile scopes)

No Graph (scope ['openid', 'profile'])

The token generated is for audience https://outlook.office.com. I cannot successfully validate (server-side .net) the token, with error message Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException: IDX10511: Signature validation failed. Keys tried: 'Microsoft.IdentityModel.Tokens.X509SecurityKey, KeyId: '3PaK4EfyBNQu3CtjYsa3YmhQ5E0', InternalId: '3PaK4EfyBNQu3CtjYsa3YmhQ5E0'. , KeyId: 3PaK4EfyBNQu3CtjYsa3YmhQ5E0

Graph (scope ['User.Read', 'openid', 'profile'])

The token generated is for audience 00000003-0000-0000-c000-000000000000, but I still cannot validate it, with the same error above.

I saw some references to validating Graph-bound tokens at https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/609#issuecomment-405683736 but have not investigated whether this is the same problem I'm seeing yet.

The C# code for validation is:

    JwtSecurityTokenHandler _jwtSecurityTokenHandler = new()
    {
        MapInboundClaims = false,
    };

    var validationParameters = await GetTokenValidationParametersAsync();
    var result = _jwtSecurityTokenHandler.ValidateToken(userToken, validationParameters, out _);

    private async Task<TokenValidationParameters> GetTokenValidationParametersAsync()
    {
        var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(
            "https://login.microsoftonline.com/common/.well-known/openid-configuration",
            new OpenIdConnectConfigurationRetriever());

        var openidConfiguration = await configManager.GetConfigurationAsync();

        return new TokenValidationParameters
        {
            // We do not validate the issuer as it is specific to each tenant and we are a multi-tenant app so
            // cannot validate in much of a meaningful way (or at least, we cannot use a static list easily).
            ValidateIssuer = false,

            ValidateAudience = true,
            ValidAudience = "https://outlook.office.com",

            ValidateTokenReplay = true,

            IssuerSigningKeys = openidConfiguration.SigningKeys,
        };
    }

Steps to reproduce

  1. Use sample from https://learn.microsoft.com/en-gb/office/dev/add-ins/develop/enable-nested-app-authentication-in-your-add-in
  2. Configure token request scopes as described above
  3. Attempt to validate the generated token

Thank you for taking the time to report an issue. Our triage team will respond to you in less than 72 hours. Normally, response time is <10 hours Monday through Friday. We do not triage on weekends.

Leander83 commented 10 hours ago

I have been experiencing the same problem using Word as the host. It matches the KeyId but signature validation fails anyway.

davidchesnut commented 4 hours ago

Hi @barclayadam, If you request any Graph scopes (this includes openid and profile if selected from Graph delegated permissions) then the JWT will be intended to be validated by Graph.

Are you trying to use the NAA token in an on-behalf-of (OBO) flow to a middle-tier server? In that case you need to have a scope specific to your resource such as access_as_user. Then the token will be configured as expected for your middle-tier to validate it. You'd need to follow the app registration pattern here except you are using NAA and not the getAccessToken API.

I also recommend asking questions about configuring the NAA OBO flow scenario based on Microsoft identity team help.

Hope this helps, David