Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Token validation fails when referencing the latest versions of Okta.AspNetCore and Okta.Sdk #267

Open
jforage-sw opened this issue Sep 25, 2024 · 8 comments
Labels
bug Something isn't working

Comments

@jforage-sw
Copy link

jforage-sw commented Sep 25, 2024

Describe the bug?

We use the Okta.AspNetCore 4.6.1 package to authenticate end-user access tokens. We also use the Okta.Sdk v8 to perform management tasks via the Okta management API. These 2 packages use different versions of the following Microsoft JWT packages:

  • Microsoft.IdentityModel.JsonWebTokens
  • System.IdentityModel.Tokens.Jwt

Version 8 of these JWT packages (as referenced by the Okta.Sdk v8 package) returns security tokens as a JsonWebToken, rather than a JwtSecurityToken, which seems to break the OAuth flow for our end users.

What is expected to happen?

It should be possible to use the AddOktaWebApi authentication builder extension method from the Okta.AspNetCore 4.6.1 package which supports signature validation when using the latest versions of the Microsoft JWT packages.

What is the actual behavior?

Signature validation of the token fails with the following exception message

Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10500: Signature validation failed. No security keys were provided to validate the signature.

Reproduction Steps?

Try this test repo created by @laura-rodriguez but with either v8 of the Okta.Sdk package included, or explicitly adding the latest versions of:

  • Microsoft.IdentityModel.JsonWebTokens
  • System.IdentityModel.Tokens.Jwt

Additional Information?

No response

.NET Version

ASP.Net Core SDK 8.0.401

SDK Version

Okta.Sdk v8.1.5
Okta.AspNetCore v4.6.1

OS version

No response

@jforage-sw jforage-sw added the bug Something isn't working label Sep 25, 2024
@jforage-sw jforage-sw changed the title No option to force the use of JwtSecurityTokenValidator in Okta.AspNet.Core No option to force the use of JwtSecurityTokenValidator in Okta.AspNetCore Sep 25, 2024
@jforage-sw
Copy link
Author

This ticket follows on from #261

@bryanapellanes-okta
Copy link
Contributor

@jforage-sw Thanks for bringing this to our attention. I've entered an internal ticket for tracking and prioritization: OKTA-811798

@jforage-sw jforage-sw changed the title No option to force the use of JwtSecurityTokenValidator in Okta.AspNetCore Token validation fails when referencing the latest versions of Okta.AspNetCore and Okta.Sdk Sep 25, 2024
@jforage-sw
Copy link
Author

@bryanapellanes-okta What is the SLA / timeline for this ticket to reviewed by your dev team, please? The reason I ask is that this issue is blocking progress on our end currently

@jforage-sw
Copy link
Author

Note that the issue appears to be with the Okta.AspNetCore AddOktaWepApi extension which doesn't appear to validate the signature of the token using the public signing keys. As such, we've had to implement our own custom AuthenticationBuilder extension as follows:

    public static AuthenticationBuilder UseOkta(this AuthenticationBuilder builder,
        OktaWebApiOptions oktaWebApiOptions)
    {
        builder.AddJwtBearer(OktaDefaults.ApiAuthenticationScheme, jwtBearerOptions =>
        {
            var issuerUrl = UrlHelper.CreateIssuerUrl(
                oktaWebApiOptions.OktaDomain,
                oktaWebApiOptions.AuthorizationServerId);

            var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(
                issuerUrl + "/.well-known/oauth-authorization-server",
                new OpenIdConnectConfigurationRetriever(),
                new HttpDocumentRetriever());

            var validationParameters = new DefaultTokenValidationParameters(oktaWebApiOptions, issuerUrl)
            {
                ValidAudience = oktaWebApiOptions.Audience,
                SignatureValidator = (token, _) =>
                    ValidateToken(token, issuerUrl, oktaWebApiOptions.Audience!, configurationManager).Result
            };

            jwtBearerOptions.TokenHandlers.Clear();
            jwtBearerOptions.TokenHandlers.Add(new StrictTokenHandler());
            jwtBearerOptions.Audience = oktaWebApiOptions.Audience;
            jwtBearerOptions.Authority = issuerUrl;
            jwtBearerOptions.TokenValidationParameters = validationParameters;
            jwtBearerOptions.BackchannelHttpHandler = new OktaHttpMessageHandler(
                "okta-aspnetcore",
                typeof(OktaAuthenticationOptionsExtensions).Assembly.GetName().Version,
                oktaWebApiOptions);
            jwtBearerOptions.Events = oktaWebApiOptions.JwtBearerEvents ?? new JwtBearerEvents();
            jwtBearerOptions.BackchannelTimeout = oktaWebApiOptions.BackchannelTimeout;
        });

        return builder;

        static async Task<JwtSecurityToken> ValidateToken(
            string token,
            string issuer,
            string audience,
            IConfigurationManager<OpenIdConnectConfiguration> configurationManager,
            CancellationToken cancellationToken = default)
        {
            var discoveryDocument =
                await configurationManager.GetConfigurationAsync(cancellationToken);

            var validationParameters = new TokenValidationParameters
            {
                ValidAudience = audience,
                ValidIssuer = issuer,
                ValidateIssuerSigningKey = true,
                IssuerSigningKeys = discoveryDocument.SigningKeys,
                // Allow for some drift in server time
                // (a lower value is better; we recommend two minutes or less)
                ClockSkew = TimeSpan.FromMinutes(2),
            };

            _ = new JwtSecurityTokenHandler().ValidateToken(token, validationParameters, out var rawValidatedToken);
            return (JwtSecurityToken)rawValidatedToken;
        }
    }

Is there any reason why you aren't validating the token signature out of the box?

@bryanapellanes-okta
Copy link
Contributor

@jforage-sw Can you confirm if the issue persists after updating to v8.1.5 of Okta.Sdk? A new release was made which updated the referenced version of Microsoft.IdentityModel.Tokens and System.IdentityModel.Tokens.Jwt to v8.0.2.

This is the change: https://github.com/okta/okta-sdk-dotnet/pull/744/files
This is the release: https://github.com/okta/okta-sdk-dotnet/releases/tag/v8.1.5

@jforage-sw
Copy link
Author

@bryanapellanes-okta Yes, the versions we are using are as follows:

  • Okta.Sdk v8.1.5
  • Okta.AspNetCore v4.6.1

I can confirm that this results in v8.0.2 of the Jwt / JsonWebToken Microsoft packages dependencies, as you say

@jforage-sw
Copy link
Author

As I say, the error we get is that the signing keys aren't available as part of token validation. Not without the custom workaround I gave above. I'm interested to understand why the AddOktaWebApi extension doesn't cater for token signature validation

@bryanapellanes-okta
Copy link
Contributor

@jforage-sw I'm uncertain what the original reason is for the lack of token validation. It is probable that validation of tokens varies by application configuration and one solution may not have been universally appropriate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants