Refactor OAuth response handling and improve content type management

- Updated response methods to standardize Content-Type header to "application/json" across OAuth endpoints, enhancing compliance with JSON standards.
- Refactored error and success response methods to streamline response generation without unnecessary wrappers, improving clarity and maintainability.
- Enhanced security by ensuring all responses include appropriate OAuth security headers, aligning with best practices for sensitive endpoints.
- Simplified test assertions for Content-Type in OAuth tests, ensuring consistency in response validation.
This commit is contained in:
Max 2025-07-22 15:36:41 +08:00
parent 7e8d4a9ba9
commit d54572a7d1
5 changed files with 91 additions and 213 deletions

View file

@ -123,7 +123,7 @@ func (openapi *OpenAPI) oauthToken(c *gin.Context) {
// Validate grant type
if grantType == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
@ -141,7 +141,7 @@ func (openapi *OpenAPI) oauthToken(c *gin.Context) {
openapi.handleTokenExchangeGrant(c)
default:
openapi.respondWithTokenError(c, ErrUnsupportedGrantType)
openapi.respondWithSecureError(c, StatusBadRequest, ErrUnsupportedGrantType)
}
}
@ -150,20 +150,20 @@ func (openapi *OpenAPI) handleStandardTokenGrant(c *gin.Context, grantType strin
// Extract client credentials from Basic Auth header or form parameters
clientID, clientSecret := openapi.extractClientCredentials(c)
if clientID == "" {
openapi.respondWithTokenError(c, ErrInvalidClient)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClient)
return
}
// Validate client credentials using OAuth service
oauthService, ok := openapi.OAuth.(*oauth.Service)
if !ok {
openapi.respondWithTokenError(c, ErrInvalidClient)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClient)
return
}
clientInfo, err := oauthService.GetClientProvider().GetClientByCredentials(c, clientID, clientSecret)
if err != nil {
openapi.respondWithTokenError(c, ErrInvalidClient)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClient)
return
}
@ -179,13 +179,13 @@ func (openapi *OpenAPI) handleStandardTokenGrant(c *gin.Context, grantType strin
// Basic validation for authorization code grant
if code == "" || redirectURI == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
// Validate that client supports authorization code grant
if !openapi.clientSupportsGrantType(clientInfo, types.GrantTypeAuthorizationCode) {
openapi.respondWithTokenError(c, ErrUnauthorizedClient)
openapi.respondWithSecureError(c, StatusUnauthorized, ErrUnauthorizedClient)
return
}
@ -194,13 +194,13 @@ func (openapi *OpenAPI) handleStandardTokenGrant(c *gin.Context, grantType strin
// Basic validation for device code grant
if code == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
// Validate that client supports device code grant
if !openapi.clientSupportsGrantType(clientInfo, types.GrantTypeDeviceCode) {
openapi.respondWithTokenError(c, ErrUnauthorizedClient)
openapi.respondWithSecureError(c, StatusUnauthorized, ErrUnauthorizedClient)
return
}
@ -210,7 +210,7 @@ func (openapi *OpenAPI) handleStandardTokenGrant(c *gin.Context, grantType strin
// Validate that client supports client credentials grant
if !openapi.clientSupportsGrantType(clientInfo, types.GrantTypeClientCredentials) {
openapi.respondWithTokenError(c, ErrUnauthorizedClient)
openapi.respondWithSecureError(c, StatusUnauthorized, ErrUnauthorizedClient)
return
}
}
@ -218,17 +218,17 @@ func (openapi *OpenAPI) handleStandardTokenGrant(c *gin.Context, grantType strin
// Call OAuth service to handle the token request
token, err := openapi.OAuth.Token(c, grantType, code, clientID, codeVerifier)
if err != nil {
// Convert OAuth service error to token error response
// Convert OAuth service error to token error response with security headers
if oauthErr, ok := err.(*ErrorResponse); ok {
openapi.respondWithTokenError(c, oauthErr)
openapi.respondWithSecureError(c, StatusBadRequest, oauthErr)
} else {
openapi.respondWithTokenError(c, ErrInvalidGrant)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidGrant)
}
return
}
// Return successful token response
openapi.respondWithTokenSuccess(c, token)
// Return successful token response with OAuth security headers (RFC 6749 Section 5.1: MUST set Cache-Control: no-store)
openapi.respondWithSecureSuccess(c, StatusOK, token)
}
// handleRefreshTokenGrant handles refresh token requests - RFC 6749 Section 6
@ -236,26 +236,26 @@ func (openapi *OpenAPI) handleRefreshTokenGrant(c *gin.Context) {
// Extract client credentials from Basic Auth header or form parameters
clientID, clientSecret := openapi.extractClientCredentials(c)
if clientID == "" {
openapi.respondWithTokenError(c, ErrInvalidClient)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClient)
return
}
// Validate client credentials using OAuth service
oauthService, ok := openapi.OAuth.(*oauth.Service)
if !ok {
openapi.respondWithTokenError(c, ErrInvalidClient)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClient)
return
}
clientInfo, err := oauthService.GetClientProvider().GetClientByCredentials(c, clientID, clientSecret)
if err != nil {
openapi.respondWithTokenError(c, ErrInvalidClient)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClient)
return
}
// Validate that client supports refresh token grant
if !openapi.clientSupportsGrantType(clientInfo, types.GrantTypeRefreshToken) {
openapi.respondWithTokenError(c, ErrUnauthorizedClient)
openapi.respondWithSecureError(c, StatusUnauthorized, ErrUnauthorizedClient)
return
}
@ -264,7 +264,7 @@ func (openapi *OpenAPI) handleRefreshTokenGrant(c *gin.Context) {
// Basic validation
if refreshToken == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
@ -276,17 +276,17 @@ func (openapi *OpenAPI) handleRefreshTokenGrant(c *gin.Context) {
refreshResponse, err = openapi.OAuth.RefreshToken(c, refreshToken)
}
if err != nil {
// Convert OAuth service error to token error response
// Convert OAuth service error to token error response with security headers
if oauthErr, ok := err.(*ErrorResponse); ok {
openapi.respondWithTokenError(c, oauthErr)
openapi.respondWithSecureError(c, StatusBadRequest, oauthErr)
} else {
openapi.respondWithTokenError(c, ErrInvalidGrant)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidGrant)
}
return
}
// Return successful refresh token response
openapi.respondWithTokenSuccess(c, refreshResponse)
// Return successful refresh token response with security headers
openapi.respondWithSecureSuccess(c, StatusOK, refreshResponse)
}
// handleTokenExchangeGrant handles token exchange requests - RFC 8693
@ -298,24 +298,24 @@ func (openapi *OpenAPI) handleTokenExchangeGrant(c *gin.Context) {
// Basic validation
if subjectToken == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
// Call OAuth service to handle token exchange
exchangeResponse, err := openapi.OAuth.TokenExchange(c, subjectToken, subjectTokenType, audience, scope)
if err != nil {
// Convert OAuth service error to token error response
// Convert OAuth service error to token error response with security headers
if oauthErr, ok := err.(*ErrorResponse); ok {
openapi.respondWithTokenError(c, oauthErr)
openapi.respondWithSecureError(c, StatusBadRequest, oauthErr)
} else {
openapi.respondWithTokenError(c, ErrInvalidGrant)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidGrant)
}
return
}
// Return successful token exchange response
openapi.respondWithTokenSuccess(c, exchangeResponse)
// Return successful token exchange response with security headers
openapi.respondWithSecureSuccess(c, StatusOK, exchangeResponse)
}
// oauthRevoke handles token revocation - RFC 7009
@ -324,7 +324,7 @@ func (openapi *OpenAPI) oauthRevoke(c *gin.Context) {
tokenTypeHint := c.PostForm("token_type_hint") // Optional hint about token type
if token == "" {
openapi.respondWithError(c, StatusBadRequest, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
@ -348,18 +348,18 @@ func (openapi *OpenAPI) oauthIntrospect(c *gin.Context) {
token := c.PostForm("token")
if token == "" {
openapi.respondWithError(c, StatusBadRequest, ErrInvalidRequest)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidRequest)
return
}
// Call OAuth service to introspect the token
introspectionResult, err := openapi.OAuth.Introspect(c, token)
if err != nil {
// Return inactive token response on error (RFC 7662)
// Return inactive token response on error (RFC 7662) with security headers
response := &TokenIntrospectionResponse{
Active: false,
}
openapi.respondWithSuccess(c, StatusOK, response)
openapi.respondWithSecureSuccess(c, StatusOK, response)
return
}
@ -376,7 +376,7 @@ func (openapi *OpenAPI) oauthIntrospect(c *gin.Context) {
Audience: introspectionResult.Audience,
}
openapi.respondWithSuccess(c, StatusOK, response)
openapi.respondWithSecureSuccess(c, StatusOK, response)
}
// oauthJWKS returns JSON Web Key Set - RFC 7517
@ -387,16 +387,8 @@ func (openapi *OpenAPI) oauthJWKS(c *gin.Context) {
return
}
// RFC 7517 compliance: Return JWKS directly as JSON without wrapper
// Set security headers for JWKS endpoint
c.Header("Cache-Control", "no-store")
c.Header("Pragma", "no-cache")
c.Header("X-Content-Type-Options", "nosniff")
c.Header("X-Frame-Options", "DENY")
c.Header("Referrer-Policy", "no-referrer")
// Return JWKS directly as per RFC 7517
c.JSON(StatusOK, jwks)
// RFC 7517 compliance: Return JWKS directly with security headers
openapi.respondWithSecureSuccess(c, StatusOK, jwks)
}
// oauthUserInfo returns user information - OpenID Connect Core 1.0
@ -419,24 +411,24 @@ func (openapi *OpenAPI) oauthRegister(c *gin.Context) {
var req DynamicClientRegistrationRequest
if err := c.ShouldBindJSON(&req); err != nil {
openapi.respondWithError(c, StatusBadRequest, ErrInvalidClientMetadata)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClientMetadata)
return
}
// Basic validation
if len(req.RedirectURIs) == 0 {
openapi.respondWithError(c, StatusBadRequest, ErrMissingRedirectURI)
openapi.respondWithSecureError(c, StatusBadRequest, ErrMissingRedirectURI)
return
}
res, err := openapi.OAuth.DynamicClientRegistration(c, &req)
if err != nil {
openapi.respondWithError(c, StatusBadRequest, ErrInvalidClientMetadata)
openapi.respondWithSecureError(c, StatusBadRequest, ErrInvalidClientMetadata)
return
}
// Return the authorization response directly (RFC 7591 compliant)
openapi.respondWithOAuthDirect(c, StatusCreated, res)
// Return the authorization response with security headers (RFC 7591 compliant, contains client credentials)
openapi.respondWithSecureSuccess(c, StatusCreated, res)
}
// extractClientCredentials extracts client ID and secret from Basic Auth header or form parameters
@ -532,7 +524,7 @@ func (openapi *OpenAPI) oauthDeviceAuthorization(c *gin.Context) {
clientID := c.PostForm("client_id")
if clientID == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithError(c, StatusBadRequest, ErrInvalidRequest)
return
}
@ -545,7 +537,7 @@ func (openapi *OpenAPI) oauthDeviceAuthorization(c *gin.Context) {
Interval: 5, // 5 seconds
}
openapi.respondWithTokenSuccess(c, response)
openapi.respondWithSuccess(c, StatusOK, response)
}
// oauthPushedAuthorizationRequest handles PAR - RFC 9126
@ -577,13 +569,13 @@ func (openapi *OpenAPI) oauthTokenExchange(c *gin.Context) {
grantType := c.PostForm("grant_type")
if grantType != types.GrantTypeTokenExchange {
openapi.respondWithTokenError(c, ErrUnsupportedGrantType)
openapi.respondWithError(c, StatusBadRequest, ErrUnsupportedGrantType)
return
}
subjectToken := c.PostForm("subject_token")
if subjectToken == "" {
openapi.respondWithTokenError(c, ErrInvalidRequest)
openapi.respondWithError(c, StatusBadRequest, ErrInvalidRequest)
return
}
@ -595,7 +587,7 @@ func (openapi *OpenAPI) oauthTokenExchange(c *gin.Context) {
ExpiresIn: 3600, // 1 hour
}
openapi.respondWithTokenSuccess(c, response)
openapi.respondWithSuccess(c, StatusOK, response)
}
// parseAuthorizationRequest parses and validates authorization request parameters

View file

@ -2,6 +2,7 @@ package oauth
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
@ -19,4 +20,11 @@ func (s *Service) Guard(c *gin.Context) {
}
// Validate the token
_, err := s.VerifyToken(strings.TrimPrefix(token, "Bearer "))
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
c.Abort()
return
}
}

View file

@ -69,7 +69,7 @@ func TestOAuthRegister(t *testing.T) {
assert.Equal(t, "nosniff", resp.Header.Get("X-Content-Type-Options"), "X-Content-Type-Options header should be set")
assert.Equal(t, "DENY", resp.Header.Get("X-Frame-Options"), "X-Frame-Options header should be set")
assert.Equal(t, "no-referrer", resp.Header.Get("Referrer-Policy"), "Referrer-Policy header should be set")
assert.Equal(t, "application/json;charset=UTF-8", resp.Header.Get("Content-Type"), "Content-Type header should be set")
assert.Equal(t, "application/json", resp.Header.Get("Content-Type"), "Content-Type header should be set")
// Read the complete response body for debugging
bodyBytes, _ := io.ReadAll(resp.Body)
@ -363,10 +363,9 @@ func TestOAuthJWKS(t *testing.T) {
// Should return 200 OK
assert.Equal(t, http.StatusOK, resp.StatusCode)
// Verify Content-Type header (case-insensitive comparison)
// Verify Content-Type header
contentType := resp.Header.Get("Content-Type")
assert.Contains(t, contentType, "application/json", "Content-Type should be JSON")
assert.Contains(t, contentType, "charset=utf", "Content-Type should specify charset")
assert.Equal(t, "application/json", contentType, "Content-Type should be application/json")
// Verify OAuth 2.1 security headers are present
assert.Equal(t, "no-store", resp.Header.Get("Cache-Control"), "Cache-Control header should be set")
@ -465,7 +464,7 @@ func TestOAuthJWKS(t *testing.T) {
"X-Content-Type-Options": "nosniff",
"X-Frame-Options": "DENY",
"Referrer-Policy": "no-referrer",
"Content-Type": "application/json; charset=utf-8",
"Content-Type": "application/json",
}
for header, expectedValue := range expectedHeaders {

View file

@ -57,7 +57,7 @@ func TestOAuthToken_AuthorizationCode(t *testing.T) {
// Verify OAuth 2.1 security headers
assert.Equal(t, "no-store", resp.Header.Get("Cache-Control"))
assert.Equal(t, "no-cache", resp.Header.Get("Pragma"))
assert.Equal(t, "application/json;charset=UTF-8", resp.Header.Get("Content-Type"))
assert.Equal(t, "application/json", resp.Header.Get("Content-Type"))
// Parse response
var tokenResp types.Token
@ -614,21 +614,11 @@ func TestOAuthIntrospect(t *testing.T) {
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
// Parse the wrapped response structure
var wrappedResp struct {
Success bool `json:"success"`
Data TokenIntrospectionResponse `json:"data"`
Timestamp string `json:"timestamp"`
}
err = json.Unmarshal(body, &wrappedResp)
// Parse response directly (no wrapper)
var introspectResp TokenIntrospectionResponse
err = json.Unmarshal(body, &introspectResp)
assert.NoError(t, err)
// Verify the wrapped response
assert.True(t, wrappedResp.Success)
// Get the actual introspection data
introspectResp := wrappedResp.Data
// Verify introspection response
assert.True(t, introspectResp.Active)
assert.Equal(t, client.ClientID, introspectResp.ClientID)
@ -664,21 +654,11 @@ func TestOAuthIntrospect(t *testing.T) {
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
// Parse the wrapped response structure
var wrappedResp struct {
Success bool `json:"success"`
Data TokenIntrospectionResponse `json:"data"`
Timestamp string `json:"timestamp"`
}
err = json.Unmarshal(body, &wrappedResp)
// Parse response directly (no wrapper)
var introspectResp TokenIntrospectionResponse
err = json.Unmarshal(body, &introspectResp)
assert.NoError(t, err)
// Verify the wrapped response
assert.True(t, wrappedResp.Success)
// Get the actual introspection data
introspectResp := wrappedResp.Data
// Should indicate token is inactive
assert.False(t, introspectResp.Active)
@ -746,21 +726,11 @@ func TestOAuthIntrospect(t *testing.T) {
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
// Parse the wrapped response structure
var wrappedResp struct {
Success bool `json:"success"`
Data TokenIntrospectionResponse `json:"data"`
Timestamp string `json:"timestamp"`
}
err = json.Unmarshal(body, &wrappedResp)
// Parse response directly (no wrapper)
var introspectResp TokenIntrospectionResponse
err = json.Unmarshal(body, &introspectResp)
assert.NoError(t, err)
// Verify the wrapped response
assert.True(t, wrappedResp.Success)
// Get the actual introspection data
introspectResp := wrappedResp.Data
// Revoked token should be inactive
// Note: For JWT tokens, revocation might not be immediately reflected in introspection
// since JWT tokens are stateless and contain their own validity information

View file

@ -2,7 +2,6 @@ package openapi
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/yaoapp/yao/openapi/oauth/types"
@ -146,15 +145,6 @@ const (
StatusServiceUnavailable = http.StatusServiceUnavailable // 503 - Service temporarily unavailable
)
// StandardResponse represents a standard OAuth API response
type StandardResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Error *ErrorResponse `json:"error,omitempty"`
Timestamp time.Time `json:"timestamp"`
RequestID string `json:"request_id,omitempty"`
}
// setOAuthSecurityHeaders sets standard OAuth 2.0/2.1 security headers
// These headers are required by OAuth 2.1 specification for enhanced security
func (openapi *OpenAPI) setOAuthSecurityHeaders(c *gin.Context) {
@ -167,66 +157,25 @@ func (openapi *OpenAPI) setOAuthSecurityHeaders(c *gin.Context) {
// setJSONContentType sets JSON content type header for OAuth responses
func (openapi *OpenAPI) setJSONContentType(c *gin.Context) {
c.Header("Content-Type", "application/json;charset=UTF-8")
c.Header("Content-Type", "application/json")
}
// Response helper functions for consistent OAuth responses
// respondWithSuccess sends a successful OAuth response
// respondWithSuccess sends a successful response (no wrapper, direct data)
func (openapi *OpenAPI) respondWithSuccess(c *gin.Context, statusCode int, data interface{}) {
openapi.setOAuthSecurityHeaders(c)
response := StandardResponse{
Success: true,
Data: data,
Timestamp: time.Now().UTC(),
RequestID: c.GetString("request_id"),
}
c.JSON(statusCode, response)
openapi.setJSONContentType(c)
c.JSON(statusCode, data)
}
// respondWithError sends an OAuth error response
// respondWithError sends an error response (no wrapper, direct error)
func (openapi *OpenAPI) respondWithError(c *gin.Context, statusCode int, err *ErrorResponse) {
openapi.setOAuthSecurityHeaders(c)
response := StandardResponse{
Success: false,
Error: err,
Timestamp: time.Now().UTC(),
RequestID: c.GetString("request_id"),
}
openapi.setJSONContentType(c)
// Add WWW-Authenticate header for 401 responses
if statusCode == StatusUnauthorized {
openapi.addWWWAuthenticateHeader(c, err)
}
c.JSON(statusCode, response)
}
// respondWithTokenSuccess sends a successful token response (without wrapper)
// This method is used for OAuth token endpoint responses that must follow RFC 6749 format
func (openapi *OpenAPI) respondWithTokenSuccess(c *gin.Context, token interface{}) {
openapi.setOAuthSecurityHeaders(c)
openapi.setJSONContentType(c)
c.JSON(StatusOK, token)
}
// respondWithTokenError sends a token endpoint error response (without wrapper)
// This method is used for OAuth token endpoint errors that must follow RFC 6749 format
func (openapi *OpenAPI) respondWithTokenError(c *gin.Context, err *ErrorResponse) {
openapi.setOAuthSecurityHeaders(c)
openapi.setJSONContentType(c)
c.JSON(StatusBadRequest, err)
}
// respondWithOAuthDirect sends a direct OAuth response without StandardResponse wrapper
// This method is used for endpoints that require RFC-compliant response format (e.g., client registration)
func (openapi *OpenAPI) respondWithOAuthDirect(c *gin.Context, statusCode int, data interface{}) {
openapi.setOAuthSecurityHeaders(c)
openapi.setJSONContentType(c)
c.JSON(statusCode, data)
c.JSON(statusCode, err)
}
// respondWithAuthorizationError sends an authorization endpoint error via redirect
@ -289,62 +238,22 @@ func (openapi *OpenAPI) addWWWAuthenticateHeader(c *gin.Context, err *ErrorRespo
c.Header("WWW-Authenticate", headerValue)
}
// Validation helper functions
// validateRedirectURI validates redirect URI according to RFC 6749
func (openapi *OpenAPI) validateRedirectURI(redirectURI string, client *ClientInfo) error {
if redirectURI == "" {
return ErrMissingRedirectURI
}
// Check if redirect URI is registered for the client
for _, registeredURI := range client.RedirectURIs {
if registeredURI == redirectURI {
return nil
}
}
return ErrInvalidRedirectURI
// respondWithSecureSuccess sends a successful response with OAuth security headers (for sensitive endpoints)
func (openapi *OpenAPI) respondWithSecureSuccess(c *gin.Context, statusCode int, data interface{}) {
openapi.setOAuthSecurityHeaders(c)
openapi.setJSONContentType(c)
c.JSON(statusCode, data)
}
// validatePKCE validates PKCE parameters according to RFC 7636
func (openapi *OpenAPI) validatePKCE(codeChallenge, codeChallengeMethod, codeVerifier string) error {
if codeChallenge == "" {
return ErrMissingCodeChallenge
// respondWithSecureError sends an error response with OAuth security headers (for sensitive endpoints)
func (openapi *OpenAPI) respondWithSecureError(c *gin.Context, statusCode int, err *ErrorResponse) {
openapi.setOAuthSecurityHeaders(c)
openapi.setJSONContentType(c)
// Add WWW-Authenticate header for 401 responses
if statusCode == StatusUnauthorized {
openapi.addWWWAuthenticateHeader(c, err)
}
if codeChallengeMethod != types.CodeChallengeMethodS256 && codeChallengeMethod != types.CodeChallengeMethodPlain {
return ErrInvalidCodeChallenge
}
// Additional PKCE validation logic would go here
// This is a simplified example
return nil
}
// createErrorWithState creates an error response with state parameter
func createErrorWithState(baseError *ErrorResponse, state string) *ErrorResponse {
errorWithState := &ErrorResponse{
Code: baseError.Code,
ErrorDescription: baseError.ErrorDescription,
ErrorURI: baseError.ErrorURI,
State: state,
}
return errorWithState
}
// Legacy OAuth 2.1 specific response helpers (deprecated)
// These methods are kept for backward compatibility but should use the unified approach above
// respondWithOAuth21Error ensures OAuth 2.1 compliance for error responses
// Deprecated: Use respondWithError instead, which now includes all OAuth 2.1 security headers
func (openapi *OpenAPI) respondWithOAuth21Error(c *gin.Context, statusCode int, err *ErrorResponse) {
openapi.respondWithError(c, statusCode, err)
}
// respondWithOAuth21TokenSuccess ensures OAuth 2.1 compliance for token responses
// Deprecated: Use respondWithTokenSuccess instead, which now includes all OAuth 2.1 security headers
func (openapi *OpenAPI) respondWithOAuth21TokenSuccess(c *gin.Context, token interface{}) {
openapi.respondWithTokenSuccess(c, token)
c.JSON(statusCode, err)
}