/// <inheritdoc/> public async Task <TokenValidationResult> ValidateRefreshTokenAsync(string tokenHandle, Client client) { var result = await Inner.ValidateRefreshTokenAsync(tokenHandle, client); if (!result.IsError) { var valid = await SessionCoordinationService.ValidateSessionAsync(new SessionValidationRequest { SubjectId = result.RefreshToken.SubjectId, SessionId = result.RefreshToken.SessionId, Client = result.Client, Type = SessionValidationType.RefreshToken }); if (!valid) { result = TokenValidationError; } } return(result); }
public async Task <TokenValidationResult> ValidateAccessTokenAsync(string token, string expectedScope = null) { using var activity = Tracing.BasicActivitySource.StartActivity("TokenValidator.ValidateAccessToken"); _logger.LogTrace("Start access token validation"); _log.ExpectedScope = expectedScope; _log.ValidateLifetime = true; TokenValidationResult result; if (token.Contains(".")) { if (token.Length > _options.InputLengthRestrictions.Jwt) { _logger.LogError("JWT too long"); return(new TokenValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken, ErrorDescription = "Token too long" }); } _log.AccessTokenType = AccessTokenType.Jwt.ToString(); result = await ValidateJwtAsync( token, await _keys.GetValidationKeysAsync()); } else { if (token.Length > _options.InputLengthRestrictions.TokenHandle) { _logger.LogError("token handle too long"); return(new TokenValidationResult { IsError = true, Error = OidcConstants.ProtectedResourceErrors.InvalidToken, ErrorDescription = "Token too long" }); } _log.AccessTokenType = AccessTokenType.Reference.ToString(); result = await ValidateReferenceAccessTokenAsync(token); } _log.Claims = result.Claims.ToClaimsDictionary(); if (result.IsError) { return(result); } // make sure client is still active (if client_id claim is present) var clientClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.ClientId); if (clientClaim != null) { var client = await _clients.FindEnabledClientByIdAsync(clientClaim.Value); if (client == null) { _logger.LogError("Client deleted or disabled: {clientId}", clientClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return(result); } } // make sure user is still active (if sub claim is present) var subClaim = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Subject); if (subClaim != null) { var principal = Principal.Create("tokenvalidator", result.Claims.ToArray()); if (result.ReferenceTokenId.IsPresent()) { principal.Identities.First() .AddClaim(new Claim(JwtClaimTypes.ReferenceTokenId, result.ReferenceTokenId)); } var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.AccessTokenValidation); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { _logger.LogError("User marked as not active: {subject}", subClaim.Value); result.IsError = true; result.Error = OidcConstants.ProtectedResourceErrors.InvalidToken; result.Claims = null; return(result); } var sub = subClaim.Value; var sid = principal.FindFirstValue("sid"); if (sid != null) { var sessionResult = await _sessionCoordinationService.ValidateSessionAsync(new SessionValidationRequest { SubjectId = sub, SessionId = sid, Client = result.Client, Type = SessionValidationType.AccessToken }); if (!sessionResult) { _logger.LogError("Server-side session invalid for subject Id {subjectId} and session Id {sessionId}.", sub, sid); return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken)); } } } // check expected scope(s) if (expectedScope.IsPresent()) { var scope = result.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Scope && c.Value == expectedScope); if (scope == null) { LogError($"Checking for expected scope {expectedScope} failed"); return(Invalid(OidcConstants.ProtectedResourceErrors.InsufficientScope)); } } _logger.LogDebug("Calling into custom token validator: {type}", _customValidator.GetType().FullName); var customResult = await _customValidator.ValidateAccessTokenAsync(result); if (customResult.IsError) { LogError("Custom validator failed: " + (customResult.Error ?? "unknown")); return(customResult); } // add claims again after custom validation _log.Claims = customResult.Claims.ToClaimsDictionary(); LogSuccess(); return(customResult); }