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

Function RevokeToken

coderd/oauth2provider/revoke.go:58–117  ·  view source on GitHub ↗

RevokeToken implements RFC 7009 OAuth2 Token Revocation Authentication is unique for this endpoint in that it does not use the standard token authentication middleware. Instead, it expects the token that is being revoked to be valid. TODO: Currently the token validation occurs in the revocation logi

(db database.Store, logger slog.Logger)

Source from the content-addressed store, hash-verified

56// This code should be refactored to share token validation logic with other parts
57// of the OAuth2 provider/http middleware.
58func RevokeToken(db database.Store, logger slog.Logger) http.HandlerFunc {
59 return func(rw http.ResponseWriter, r *http.Request) {
60 ctx := r.Context()
61 app := httpmw.OAuth2ProviderApp(r)
62
63 // RFC 7009 requires POST method with application/x-www-form-urlencoded
64 if r.Method != http.MethodPost {
65 httpapi.WriteOAuth2Error(ctx, rw, http.StatusMethodNotAllowed, codersdk.OAuth2ErrorCodeInvalidRequest, "Method not allowed")
66 return
67 }
68
69 req, err := extractRevocationRequest(r)
70 if err != nil {
71 httpapi.WriteOAuth2Error(ctx, rw, http.StatusBadRequest, codersdk.OAuth2ErrorCodeInvalidRequest, err.Error())
72 return
73 }
74
75 // Determine if this is a refresh token (starts with "coder_") or API key
76 // APIKeys do not have the SecretIdentifier prefix.
77 const coderPrefix = SecretIdentifier + "_"
78 isRefreshToken := strings.HasPrefix(req.Token, coderPrefix)
79
80 // Revoke the token with ownership verification
81 err = db.InTx(func(tx database.Store) error {
82 if isRefreshToken {
83 // Handle refresh token revocation
84 return revokeRefreshTokenInTx(ctx, tx, req.Token, app.ID)
85 }
86 // Handle API key revocation
87 return revokeAPIKeyInTx(ctx, tx, req.Token, app.ID)
88 }, nil)
89 if err != nil {
90 if errors.Is(err, ErrTokenNotBelongsToClient) {
91 // RFC 7009: Return success even if token doesn't belong to client (don't reveal token existence)
92 logger.Debug(ctx, "token revocation failed: token does not belong to requesting client",
93 slog.F("client_id", app.ID.String()),
94 slog.F("app_name", app.Name))
95 rw.WriteHeader(http.StatusOK)
96 return
97 }
98 if errors.Is(err, ErrInvalidTokenFormat) {
99 // Invalid token format should return 400 bad request
100 logger.Debug(ctx, "token revocation failed: invalid token format",
101 slog.F("client_id", app.ID.String()),
102 slog.F("app_name", app.Name))
103 httpapi.WriteOAuth2Error(ctx, rw, http.StatusBadRequest, codersdk.OAuth2ErrorCodeInvalidRequest, "Invalid token format")
104 return
105 }
106 logger.Error(ctx, "token revocation failed with internal server error",
107 slog.Error(err),
108 slog.F("client_id", app.ID.String()),
109 slog.F("app_name", app.Name))
110 httpapi.WriteOAuth2Error(ctx, rw, http.StatusInternalServerError, codersdk.OAuth2ErrorCodeServerError, "Internal server error")
111 return
112 }
113
114 // RFC 7009: successful revocation returns HTTP 200
115 rw.WriteHeader(http.StatusOK)

Callers 1

revokeOAuth2TokenMethod · 0.92

Calls 11

OAuth2ProviderAppFunction · 0.92
WriteOAuth2ErrorFunction · 0.92
extractRevocationRequestFunction · 0.85
revokeRefreshTokenInTxFunction · 0.85
revokeAPIKeyInTxFunction · 0.85
ContextMethod · 0.65
InTxMethod · 0.65
ErrorMethod · 0.45
IsMethod · 0.45
StringMethod · 0.45
WriteHeaderMethod · 0.45

Tested by

no test coverage detected