RequireRegistrationAccessToken returns middleware that validates the registration access token for RFC 7592 endpoints
(db database.Store)
| 418 | |
| 419 | // RequireRegistrationAccessToken returns middleware that validates the registration access token for RFC 7592 endpoints |
| 420 | func RequireRegistrationAccessToken(db database.Store) func(http.Handler) http.Handler { |
| 421 | return func(next http.Handler) http.Handler { |
| 422 | return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { |
| 423 | ctx := r.Context() |
| 424 | |
| 425 | // Extract client ID from URL path |
| 426 | clientIDStr := chi.URLParam(r, "client_id") |
| 427 | clientID, err := uuid.Parse(clientIDStr) |
| 428 | if err != nil { |
| 429 | writeOAuth2RegistrationError(ctx, rw, http.StatusBadRequest, |
| 430 | "invalid_client_id", "Invalid client ID format") |
| 431 | return |
| 432 | } |
| 433 | |
| 434 | // Extract registration access token from Authorization header |
| 435 | authHeader := r.Header.Get("Authorization") |
| 436 | if authHeader == "" { |
| 437 | writeOAuth2RegistrationError(ctx, rw, http.StatusUnauthorized, |
| 438 | "invalid_token", "Missing Authorization header") |
| 439 | return |
| 440 | } |
| 441 | |
| 442 | if !strings.HasPrefix(authHeader, "Bearer ") { |
| 443 | writeOAuth2RegistrationError(ctx, rw, http.StatusUnauthorized, |
| 444 | "invalid_token", "Authorization header must use Bearer scheme") |
| 445 | return |
| 446 | } |
| 447 | |
| 448 | token := strings.TrimPrefix(authHeader, "Bearer ") |
| 449 | if token == "" { |
| 450 | writeOAuth2RegistrationError(ctx, rw, http.StatusUnauthorized, |
| 451 | "invalid_token", "Missing registration access token") |
| 452 | return |
| 453 | } |
| 454 | |
| 455 | // Get the client and verify the registration access token |
| 456 | //nolint:gocritic // OAuth2 system context — RFC 7592 registration access token validation |
| 457 | app, err := db.GetOAuth2ProviderAppByClientID(dbauthz.AsSystemOAuth2(ctx), clientID) |
| 458 | if err != nil { |
| 459 | if xerrors.Is(err, sql.ErrNoRows) { |
| 460 | // Return 401 for authentication-related issues, not 404 |
| 461 | writeOAuth2RegistrationError(ctx, rw, http.StatusUnauthorized, |
| 462 | "invalid_token", "Client not found") |
| 463 | } else { |
| 464 | writeOAuth2RegistrationError(ctx, rw, http.StatusInternalServerError, |
| 465 | "server_error", "Failed to retrieve client") |
| 466 | } |
| 467 | return |
| 468 | } |
| 469 | |
| 470 | // Check if client was dynamically registered |
| 471 | if !app.DynamicallyRegistered.Bool { |
| 472 | writeOAuth2RegistrationError(ctx, rw, http.StatusForbidden, |
| 473 | "invalid_token", "Client was not dynamically registered") |
| 474 | return |
| 475 | } |
| 476 | |
| 477 | // Verify the registration access token |
no test coverage detected