MCPcopy Create free account
hub / github.com/bytebase/bytebase / issueTokens

Method issueTokens

backend/api/oauth2/token.go:302–345  ·  view source on GitHub ↗

issueTokens issues a new OAuth2 access token (and refresh token, when the grant supports it) bound to the given workspace. The workspace is sourced from the authorization code or refresh token being exchanged, not from the client — clients are workspace-agnostic.

(c *echo.Context, client *store.OAuth2ClientMessage, userEmail, workspaceID string)

Source from the content-addressed store, hash-verified

300// from the authorization code or refresh token being exchanged, not from the
301// client — clients are workspace-agnostic.
302func (s *Service) issueTokens(c *echo.Context, client *store.OAuth2ClientMessage, userEmail, workspaceID string) error {
303 ctx := c.Request().Context()
304
305 // Generate access token (JWT) with the workspace_id claim that
306 // downstream APIs (gRPC services, MCP middleware) use to scope requests.
307 accessToken, err := auth.GenerateOAuth2AccessToken(userEmail, client.ClientID, workspaceID, s.secret, accessTokenExpiry)
308 if err != nil {
309 return oauth2Error(c, http.StatusInternalServerError, "server_error", fmt.Sprintf("failed to generate access token with error: %v", err))
310 }
311
312 now := time.Now()
313
314 // Generate refresh token if allowed
315 var refreshTokenStr string
316 if slices.Contains(client.Config.GrantTypes, "refresh_token") {
317 refreshTokenStr, err = generateRefreshToken()
318 if err != nil {
319 return oauth2Error(c, http.StatusInternalServerError, "server_error", "failed to generate refresh token")
320 }
321
322 // Store refresh token with the workspace binding preserved so a
323 // subsequent /token refresh re-issues for the same workspace.
324 if _, err := s.store.CreateOAuth2RefreshToken(ctx, &store.OAuth2RefreshTokenMessage{
325 TokenHash: auth.HashToken(refreshTokenStr),
326 ClientID: client.ClientID,
327 UserEmail: userEmail,
328 Workspace: workspaceID,
329 ExpiresAt: now.Add(refreshTokenExpiry),
330 }); err != nil {
331 return oauth2Error(c, http.StatusInternalServerError, "server_error", "failed to store refresh token")
332 }
333 }
334
335 if err := s.store.UpdateOAuth2ClientLastActiveAt(ctx, client.ClientID); err != nil {
336 slog.Warn("failed to update OAuth2 client last active", slog.String("clientID", client.ClientID), log.BBError(err))
337 }
338
339 return c.JSON(http.StatusOK, &tokenResponse{
340 AccessToken: accessToken,
341 TokenType: "Bearer",
342 ExpiresIn: int(accessTokenExpiry.Seconds()),
343 RefreshToken: refreshTokenStr,
344 })
345}

Callers 2

Calls 8

HashTokenFunction · 0.92
BBErrorFunction · 0.92
oauth2ErrorFunction · 0.85
generateRefreshTokenFunction · 0.85
StringMethod · 0.65

Tested by

no test coverage detected