Allows customization of the token validation logic.
Inheritance: Microsoft.AspNetCore.Authentication.BaseControlContext
 /// <summary>
 /// Invoked when a token is to be validated, before final processing.
 /// </summary>
 public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context);
 /// <summary>
 /// Invoked when a token is to be validated, before final processing.
 /// </summary>
 public virtual Task ValidateToken(ValidateTokenContext context) => OnValidateToken(context);
Example #3
0
        protected override async Task <AuthenticateResult> HandleAuthenticateAsync()
        {
            var context = new RetrieveTokenContext(Context, Scheme, Options);
            await Events.RetrieveToken(context);

            if (context.Result != null)
            {
                Logger.LogInformation("The default authentication handling was skipped from user code.");

                return(context.Result);
            }

            var token = context.Token;

            if (string.IsNullOrEmpty(token))
            {
                // Try to retrieve the access token from the authorization header.
                string header = Request.Headers[HeaderNames.Authorization];
                if (string.IsNullOrEmpty(header))
                {
                    Logger.LogDebug("Authentication was skipped because no bearer token was received.");

                    return(AuthenticateResult.NoResult());
                }

                // Ensure that the authorization header contains the mandatory "Bearer" scheme.
                // See https://tools.ietf.org/html/rfc6750#section-2.1
                if (!header.StartsWith(OAuthValidationConstants.Schemes.Bearer + ' ', StringComparison.OrdinalIgnoreCase))
                {
                    Logger.LogDebug("Authentication was skipped because an incompatible " +
                                    "scheme was used in the 'Authorization' header.");

                    return(AuthenticateResult.NoResult());
                }

                // Extract the token from the authorization header.
                token = header.Substring(OAuthValidationConstants.Schemes.Bearer.Length + 1).Trim();

                if (string.IsNullOrEmpty(token))
                {
                    Logger.LogDebug("Authentication was skipped because the bearer token " +
                                    "was missing from the 'Authorization' header.");

                    return(AuthenticateResult.NoResult());
                }
            }

            // Try to unprotect the token and return an error
            // if the ticket can't be decrypted or validated.
            var result = await CreateTicketAsync(token);

            if (!result.Succeeded)
            {
                Context.Features.Set(new OAuthValidationFeature
                {
                    Error = new OAuthValidationError
                    {
                        Error            = OAuthValidationConstants.Errors.InvalidToken,
                        ErrorDescription = "The access token is not valid."
                    }
                });

                return(result);
            }

            // Ensure that the authentication ticket is still valid.
            var ticket = result.Ticket;

            if (ticket.Properties.ExpiresUtc.HasValue &&
                ticket.Properties.ExpiresUtc.Value < Options.SystemClock.UtcNow)
            {
                Context.Features.Set(new OAuthValidationFeature
                {
                    Error = new OAuthValidationError
                    {
                        Error            = OAuthValidationConstants.Errors.InvalidToken,
                        ErrorDescription = "The access token is no longer valid."
                    }
                });

                return(AuthenticateResult.Fail("Authentication failed because the access token was expired."));
            }

            // Ensure that the access token was issued
            // to be used with this resource server.
            if (!ValidateAudience(ticket))
            {
                Context.Features.Set(new OAuthValidationFeature
                {
                    Error = new OAuthValidationError
                    {
                        Error            = OAuthValidationConstants.Errors.InvalidToken,
                        ErrorDescription = "The access token is not valid for this resource server."
                    }
                });

                return(AuthenticateResult.Fail("Authentication failed because the access token " +
                                               "was not valid for this resource server."));
            }

            var notification = new ValidateTokenContext(Context, Scheme, Options, ticket);
            await Events.ValidateToken(notification);

            if (notification.Result != null)
            {
                Logger.LogInformation("The default authentication handling was skipped from user code.");

                return(notification.Result);
            }

            // Optimization: avoid allocating a new AuthenticationTicket
            // if the principal/properties instances were not replaced.
            if (ReferenceEquals(notification.Principal, ticket.Principal) &&
                ReferenceEquals(notification.Properties, ticket.Properties))
            {
                return(AuthenticateResult.Success(ticket));
            }

            return(AuthenticateResult.Success(new AuthenticationTicket(
                                                  notification.Principal, notification.Properties, Scheme.Name)));
        }