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

Function ValidateAPIKey

coderd/httpmw/apikey.go:250–493  ·  view source on GitHub ↗

ValidateAPIKey extracts and validates the API key from the request. It performs all security-critical checks: - Token extraction and parsing - Database lookup + secret hash validation - Expiry check - OIDC/OAuth token refresh (if applicable) - API key LastUsed / ExpiresAt DB updates - User role look

(ctx context.Context, cfg ValidateAPIKeyConfig, r *http.Request)

Source from the content-addressed store, hash-verified

248//
249// Returns (result, nil) on success or (nil, error) on failure.
250func ValidateAPIKey(ctx context.Context, cfg ValidateAPIKeyConfig, r *http.Request) (*ValidateAPIKeyResult, *ValidateAPIKeyError) {
251 key, valErr := apiKeyFromRequestValidate(ctx, cfg.DB, cfg.SessionTokenFunc, r)
252 if valErr != nil {
253 return nil, valErr
254 }
255
256 // Log the API key ID for all requests that have a valid key
257 // format and secret, regardless of whether subsequent validation
258 // (expiry, user status, etc.) succeeds.
259 if rl := loggermw.RequestLoggerFromContext(ctx); rl != nil {
260 rl.WithFields(slog.F("api_key_id", key.ID))
261 }
262
263 now := dbtime.Now()
264 if key.ExpiresAt.Before(now) {
265 return nil, &ValidateAPIKeyError{
266 Code: http.StatusUnauthorized,
267 Response: codersdk.Response{
268 Message: SignedOutErrorMessage,
269 Detail: fmt.Sprintf("API key expired at %q.", key.ExpiresAt.String()),
270 },
271 }
272 }
273
274 // Refresh OIDC/GitHub tokens if applicable.
275 if key.LoginType == database.LoginTypeGithub || key.LoginType == database.LoginTypeOIDC {
276 //nolint:gocritic // System needs to fetch UserLink to check if it's valid.
277 link, err := cfg.DB.GetUserLinkByUserIDLoginType(dbauthz.AsSystemRestricted(ctx), database.GetUserLinkByUserIDLoginTypeParams{
278 UserID: key.UserID,
279 LoginType: key.LoginType,
280 })
281 if errors.Is(err, sql.ErrNoRows) {
282 return nil, &ValidateAPIKeyError{
283 Code: http.StatusUnauthorized,
284 Response: codersdk.Response{
285 Message: SignedOutErrorMessage,
286 Detail: "You must re-authenticate with the login provider.",
287 },
288 }
289 }
290 if err != nil {
291 return nil, &ValidateAPIKeyError{
292 Code: http.StatusInternalServerError,
293 Response: codersdk.Response{
294 Message: "A database error occurred",
295 Detail: fmt.Sprintf("get user link by user ID and login type: %s", err.Error()),
296 },
297 Hard: true,
298 }
299 }
300 // Check if the OAuth token is expired.
301 if !link.OAuthExpiry.IsZero() && link.OAuthExpiry.Before(now) {
302 if cfg.OAuth2Configs.IsZero() {
303 return nil, &ValidateAPIKeyError{
304 Code: http.StatusInternalServerError,
305 Response: codersdk.Response{
306 Message: internalErrorMessage,
307 Detail: fmt.Sprintf("Unable to refresh OAuth token for login type %q. "+

Callers 2

PrecheckAPIKeyFunction · 0.85
ExtractAPIKeyFunction · 0.85

Calls 15

TokenSourceMethod · 0.95
RequestLoggerFromContextFunction · 0.92
NowFunction · 0.92
AsSystemRestrictedFunction · 0.92
UserRBACSubjectFunction · 0.85
DurationMethod · 0.80
ScopeSetMethod · 0.80
WithFieldsMethod · 0.65
TokenMethod · 0.65
ContextMethod · 0.65

Tested by

no test coverage detected