MCPcopy Index your code
hub / github.com/bytebase/bytebase / handleAuthorizationCodeGrant

Method handleAuthorizationCodeGrant

backend/api/oauth2/token.go:95–164  ·  view source on GitHub ↗
(c *echo.Context, client *store.OAuth2ClientMessage, req *tokenRequest)

Source from the content-addressed store, hash-verified

93}
94
95func (s *Service) handleAuthorizationCodeGrant(c *echo.Context, client *store.OAuth2ClientMessage, req *tokenRequest) error {
96 ctx := c.Request().Context()
97
98 // Validate grant type is allowed
99 if !slices.Contains(client.Config.GrantTypes, "authorization_code") {
100 return oauth2Error(c, http.StatusBadRequest, "unauthorized_client", "client not authorized for authorization_code grant")
101 }
102
103 // Validate code
104 if req.Code == "" {
105 return oauth2Error(c, http.StatusBadRequest, "invalid_request", "code is required")
106 }
107
108 authCode, err := s.store.GetOAuth2AuthorizationCode(ctx, client.ClientID, req.Code)
109 if err != nil {
110 return oauth2Error(c, http.StatusInternalServerError, "server_error", "failed to lookup code")
111 }
112 if authCode == nil {
113 return oauth2Error(c, http.StatusBadRequest, "invalid_grant", "invalid or expired code")
114 }
115
116 // Validate code belongs to this client BEFORE deleting
117 // This prevents DoS where attacker with stolen code invalidates it for legitimate client
118 if authCode.ClientID != client.ClientID {
119 return oauth2Error(c, http.StatusBadRequest, "invalid_grant", "code was not issued to this client")
120 }
121
122 // Validate code not expired
123 if time.Now().After(authCode.ExpiresAt) {
124 // Delete expired code
125 if err := s.store.DeleteOAuth2AuthorizationCode(ctx, client.ClientID, req.Code); err != nil {
126 slog.Warn("failed to delete expired OAuth2 authorization code", slog.String("code", req.Code), log.BBError(err))
127 }
128 return oauth2Error(c, http.StatusBadRequest, "invalid_grant", "code has expired")
129 }
130
131 // Validate redirect_uri matches
132 if req.RedirectURI != authCode.Config.RedirectUri {
133 return oauth2Error(c, http.StatusBadRequest, "invalid_grant", "redirect_uri mismatch")
134 }
135
136 // Validate PKCE
137 if req.CodeVerifier == "" {
138 return oauth2Error(c, http.StatusBadRequest, "invalid_request", "code_verifier is required")
139 }
140 if !verifyPKCE(req.CodeVerifier, authCode.Config.CodeChallenge, authCode.Config.CodeChallengeMethod) {
141 return oauth2Error(c, http.StatusBadRequest, "invalid_grant", "invalid code_verifier")
142 }
143
144 // Delete code after all validations pass (single use)
145 if err := s.store.DeleteOAuth2AuthorizationCode(ctx, client.ClientID, req.Code); err != nil {
146 slog.Warn("failed to delete OAuth2 authorization code after use", slog.String("code", req.Code), log.BBError(err))
147 }
148
149 // Get user
150 user, err := s.store.GetUserByEmail(ctx, authCode.UserEmail)
151 if err != nil || user == nil {
152 return oauth2Error(c, http.StatusBadRequest, "invalid_grant", "user not found")

Callers 1

handleTokenMethod · 0.95

Calls 10

resolveBoundWorkspaceMethod · 0.95
issueTokensMethod · 0.95
BBErrorFunction · 0.92
oauth2ErrorFunction · 0.85
verifyPKCEFunction · 0.85
workspaceResolutionErrorFunction · 0.85
GetUserByEmailMethod · 0.80
StringMethod · 0.65

Tested by

no test coverage detected