protected override async Task<AuthenticateResult> HandleAuthenticateAsync() { if (!Options.UseReferenceTokens) { return await base.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)); }
/// <summary> /// Invoked when a token is to be parsed from a newly-received request. /// </summary> public virtual Task RetrieveToken(RetrieveTokenContext context) => OnRetrieveToken(context);