private async Task <AuthenticationTicket> ReceiveTokenAsync( [NotNull] string type, [NotNull] string value, [NotNull] OpenIddictServerOptions options, [NotNull] OpenIdConnectRequest request, [NotNull] ISecureDataFormat <AuthenticationTicket> format) { Debug.Assert(!(options.DisableTokenStorage && options.UseReferenceTokens), "Token revocation cannot be disabled when using reference tokens."); Debug.Assert(type == OpenIdConnectConstants.TokenUsages.AccessToken || type == OpenIdConnectConstants.TokenUsages.AuthorizationCode || type == OpenIdConnectConstants.TokenUsages.RefreshToken, "Only authorization codes, access and refresh tokens should be validated using this method."); string identifier; AuthenticationTicket ticket; object token; if (options.UseReferenceTokens) { // For introspection or revocation requests, this method may be called more than once. // For reference tokens, this may result in multiple database calls being made. // To optimize that, the token is added to the request properties to indicate that // a database lookup was already made with the same identifier. If the marker exists, // the property value (that may be null) is used instead of making a database call. if (request.HasProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}")) { token = request.GetProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}"); } else { // Retrieve the token entry from the database. If it // cannot be found, assume the token is not valid. token = await _tokenManager.FindByReferenceIdAsync(value); // Store the token as a request property so it can be retrieved if this method is called another time. request.AddProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}", token); } if (token == null) { _logger.LogInformation("The reference token corresponding to the '{Identifier}' " + "reference identifier cannot be found in the database.", value); return(null); } identifier = await _tokenManager.GetIdAsync(token); if (string.IsNullOrEmpty(identifier)) { _logger.LogWarning("The identifier associated with the received token cannot be retrieved. " + "This may indicate that the token entry is corrupted."); return(null); } // Extract the encrypted payload from the token. If it's null or empty, // assume the token is not a reference token and consider it as invalid. var payload = await _tokenManager.GetPayloadAsync(token); if (string.IsNullOrEmpty(payload)) { _logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be retrieved. " + "This may indicate that the token is not a reference token.", identifier); return(null); } ticket = format.Unprotect(payload); if (ticket == null) { _logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be decrypted. " + "This may indicate that the token entry is corrupted or tampered.", await _tokenManager.GetIdAsync(token)); return(null); } request.SetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}", token); } else if (type == OpenIdConnectConstants.TokenUsages.AuthorizationCode || type == OpenIdConnectConstants.TokenUsages.RefreshToken) { ticket = format.Unprotect(value); if (ticket == null) { _logger.LogTrace("The received token was invalid or malformed: {Token}.", value); return(null); } identifier = ticket.GetProperty(OpenIddictConstants.Properties.InternalTokenId); if (string.IsNullOrEmpty(identifier)) { _logger.LogWarning("The identifier associated with the received token cannot be retrieved. " + "This may indicate that the token entry is corrupted."); return(null); } // For introspection or revocation requests, this method may be called more than once. // For codes/refresh tokens, this may result in multiple database calls being made. // To optimize that, the token is added to the request properties to indicate that // a database lookup was already made with the same identifier. If the marker exists, // the property value (that may be null) is used instead of making a database call. if (request.HasProperty($"{OpenIddictConstants.Properties.Token}:{identifier}")) { token = request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}"); } // Otherwise, retrieve the authorization code/refresh token entry from the database. // If it cannot be found, assume the authorization code/refresh token is not valid. else { token = await _tokenManager.FindByIdAsync(identifier); // Store the token as a request property so it can be retrieved if this method is called another time. request.AddProperty($"{OpenIddictConstants.Properties.Token}:{identifier}", token); } if (token == null) { _logger.LogInformation("The token '{Identifier}' cannot be found in the database.", identifier); return(null); } } else { return(null); } // Dynamically set the creation and expiration dates. ticket.Properties.IssuedUtc = await _tokenManager.GetCreationDateAsync(token); ticket.Properties.ExpiresUtc = await _tokenManager.GetExpirationDateAsync(token); // Restore the token/authorization identifiers using the identifiers attached with the database entry. ticket.SetProperty(OpenIddictConstants.Properties.InternalTokenId, identifier); ticket.SetProperty(OpenIddictConstants.Properties.InternalAuthorizationId, await _tokenManager.GetAuthorizationIdAsync(token)); _logger.LogTrace("The token '{Identifier}' was successfully decrypted and " + "retrieved from the database: {Claims} ; {Properties}.", identifier, ticket.Principal.Claims, ticket.Properties.Items); return(ticket); }