IdentityServer / IdentityServer4.AccessTokenValidation

IdentityServer Access Token Validation for ASP.NET Core
Apache License 2.0
544 stars 214 forks source link

Support opaque tokens with a dot when used together with JWT #123

Closed doubliez closed 4 years ago

doubliez commented 5 years ago

I'm trying to have my API support both JWT and opaque tokens (through OAuth2 introspection) for authentication. My OAuth2 access tokens are issued by ORY Hydra (https://gethydra.sh/) and they include a dot.

In the code it seems that the only check that is done to determine if the token is a JWT is if it contains a dot, and there is no way to change this behavior as far as I can tell. So it tries to validate my opaque token using JWT scheme which doesn't work (it doesn't fallback to the introspection scheme in this case).

I think it would be reasonable to check for 2 dots in the JWT (the ORY Hydra tokens only have 1 dot), and/or fallback to introspection when the JWT verification fails.

Or is there a workaround I could use in my case?

leastprivilege commented 5 years ago

That's a bummer ;)

I was aware that this is not the perfect check - but note the name of the repo/package...It works for IdentityServer.

That said - maybe an event is needed to dynamically determine the token type?

doubliez commented 5 years ago

That's right, however I thought this package would be generic enough to work with any standard OAuth2 server.

Anyway I found a workaround by using the JWT handler and OAuth2 introspection packages directly:

services.AddAuthentication(options =>
{
    options.DefaultScheme = "custom";
    options.DefaultChallengeScheme = "custom";
})
    .AddPolicyScheme("custom", "JWT or opaque OAuth2 access token", options =>
    {
        options.ForwardDefaultSelector = context =>
        {
            // Determine which scheme to use based on number of dots in token
            var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
            if (!string.IsNullOrEmpty(authHeader)) {
                var token = authHeader.Split(' ')[1];
                if (!string.IsNullOrEmpty(token)) {
                    if (token.Split('.').Length == 3) {
                        return "jwt";
                    }
                    return "introspection";
                }
            }
            // Fallback to JWT if missing/malformed header
            return "jwt";
        };
    })
    .AddOAuth2Introspection("introspection", options =>
    {
        // Need to not skip tokens with dots
        options.SkipTokensWithDots = false;
        // configure other OAuth2 introspection options here
    })
    .AddJwtBearer("jwt", options =>
    {
        // configure JWT options here
    });
leastprivilege commented 5 years ago

Yep - that's a good way to do that.

leastprivilege commented 4 years ago

https://leastprivilege.com/2020/07/06/flexible-access-token-validation-in-asp-net-core/