public AuthCodeGrant CreateAuthorizationCodeGrant(TestOAuth2ServerTokenGenerator generator, string[] scopes, string redirectUri, string codeChallenge, OAuth2PkceChallengeMethod codeChallengeMethod) { string code = generator.CreateAuthorizationCode(); var grant = new AuthCodeGrant(code, scopes, redirectUri, codeChallenge, codeChallengeMethod); AuthGrants.Add(grant); return(grant); }
public TokenEndpointResponseJson CreateTokenByAuthorizationGrant( TestOAuth2ServerTokenGenerator generator, string authCode, string codeVerifier, string redirectUri) { var grant = AuthGrants.FirstOrDefault(x => x.Code == authCode); if (grant is null) { throw new Exception($"Invalid authorization code '{authCode}'"); } // Validate the grant's code challenge was constructed from the given code verifier if (!string.IsNullOrWhiteSpace(grant.CodeChallenge)) { if (string.IsNullOrWhiteSpace(codeVerifier)) { throw new Exception("Missing code verifier"); } switch (grant.CodeChallengeMethod) { case OAuth2PkceChallengeMethod.Sha256: using (var sha256 = SHA256.Create()) { string challenge = Base64UrlConvert.Encode( sha256.ComputeHash( Encoding.ASCII.GetBytes(codeVerifier) ), false ); if (challenge != grant.CodeChallenge) { throw new Exception($"Invalid code verifier '{codeVerifier}'"); } } break; case OAuth2PkceChallengeMethod.Plain: // The case matters! if (!StringComparer.Ordinal.Equals(codeVerifier, grant.CodeChallenge)) { throw new Exception($"Invalid code verifier '{codeVerifier}'"); } break; } } // If an explicit redirect URI was used as part of the authorization request then // the redirect URI used for the token call must match exactly. if (!string.IsNullOrWhiteSpace(grant.RedirectUri) && !StringComparer.Ordinal.Equals(grant.RedirectUri, redirectUri)) { throw new Exception("Redirect URI must match exactly the one used when requesting the authorization code."); } string accessToken = generator.CreateAccessToken(); string refreshToken = generator.CreateRefreshToken(); // Remove the auth code grant now we've generated an access token (do not allow auth code reuse) AuthGrants.Remove(grant); // Store the tokens AccessTokens[accessToken] = refreshToken; RefreshTokens[refreshToken] = grant.Scopes; return(new TokenEndpointResponseJson { TokenType = Constants.Http.WwwAuthenticateBearerScheme, AccessToken = accessToken, RefreshToken = refreshToken, Scope = string.Join(" ", grant.Scopes) // Keep the same scopes as before }); }