MCPcopy Index your code
hub / github.com/coder/coder / refreshTokenGrant

Function refreshTokenGrant

coderd/oauth2provider/tokens.go:381–492  ·  view source on GitHub ↗
(ctx context.Context, db database.Store, app database.OAuth2ProviderApp, lifetimes codersdk.SessionLifetime, req codersdk.OAuth2TokenRequest)

Source from the content-addressed store, hash-verified

379}
380
381func refreshTokenGrant(ctx context.Context, db database.Store, app database.OAuth2ProviderApp, lifetimes codersdk.SessionLifetime, req codersdk.OAuth2TokenRequest) (codersdk.OAuth2TokenResponse, error) {
382 // Validate the token.
383 token, err := ParseFormattedSecret(req.RefreshToken)
384 if err != nil {
385 return codersdk.OAuth2TokenResponse{}, errBadToken
386 }
387 //nolint:gocritic // OAuth2 system context — no authenticated user during refresh
388 dbToken, err := db.GetOAuth2ProviderAppTokenByPrefix(dbauthz.AsSystemOAuth2(ctx), []byte(token.Prefix))
389 if errors.Is(err, sql.ErrNoRows) {
390 return codersdk.OAuth2TokenResponse{}, errBadToken
391 }
392 if err != nil {
393 return codersdk.OAuth2TokenResponse{}, err
394 }
395 equal := apikey.ValidateHash(dbToken.RefreshHash, token.Secret)
396 if !equal {
397 return codersdk.OAuth2TokenResponse{}, errBadToken
398 }
399
400 // Ensure the token has not expired.
401 if dbToken.ExpiresAt.Before(dbtime.Now()) {
402 return codersdk.OAuth2TokenResponse{}, errBadToken
403 }
404
405 // Verify resource parameter consistency for refresh tokens (RFC 8707)
406 if req.Resource != "" {
407 // If resource is provided in refresh request, it must match the original token's audience
408 if !dbToken.Audience.Valid || dbToken.Audience.String != req.Resource {
409 return codersdk.OAuth2TokenResponse{}, errInvalidResource
410 }
411 }
412
413 // Grab the user roles so we can perform the refresh as the user.
414 //nolint:gocritic // OAuth2 system context — need to read the previous API key
415 prevKey, err := db.GetAPIKeyByID(dbauthz.AsSystemOAuth2(ctx), dbToken.APIKeyID)
416 if err != nil {
417 return codersdk.OAuth2TokenResponse{}, err
418 }
419
420 actor, _, err := httpmw.UserRBACSubject(ctx, db, prevKey.UserID, rbac.ScopeAll)
421 if err != nil {
422 return codersdk.OAuth2TokenResponse{}, xerrors.Errorf("fetch user actor: %w", err)
423 }
424
425 // Generate a new refresh token.
426 refreshToken, err := GenerateSecret()
427 if err != nil {
428 return codersdk.OAuth2TokenResponse{}, err
429 }
430
431 // Generate the new API key.
432 // TODO: We are ignoring scopes for now.
433 tokenName := fmt.Sprintf("%s_%s_oauth_session_token", prevKey.UserID, app.ID)
434 key, sessionToken, err := apikey.Generate(apikey.CreateParams{
435 UserID: prevKey.UserID,
436 LoginType: database.LoginTypeOAuth2ProviderApp,
437 DefaultLifetime: lifetimes.DefaultDuration.Value(),
438 // For now, we allow only one token per app and user at a time.

Callers 1

TokensFunction · 0.85

Calls 15

AsSystemOAuth2Function · 0.92
ValidateHashFunction · 0.92
NowFunction · 0.92
UserRBACSubjectFunction · 0.92
GenerateFunction · 0.92
AsFunction · 0.92
ParseFormattedSecretFunction · 0.85
GenerateSecretFunction · 0.70
GetAPIKeyByIDMethod · 0.65
AddMethod · 0.65
InTxMethod · 0.65

Tested by

no test coverage detected