oauth2-proxy/oauth2-proxy · error
Forbidden
Error message
Forbidden
What it means
When a request carries a JWT in the Authorization header but the session cannot be retrieved from it (invalid, expired, or malformed token), and denyInvalidJWTs is enabled, the middleware responds with HTTP 403 Forbidden and stops the request chain. Without the deny flag the request would proceed unauthenticated instead.
Source
Thrown at pkg/middleware/jwt_session.go:56
// will be loaded and the request will be passed to the next handler.
// Or if the JWT is invalid and denyInvalidJWTs, return 403 now.
// If a session was loaded by a previous handler, it will not be replaced.
func (j *jwtSessionLoader) loadSession(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
scope := middlewareapi.GetRequestScope(req)
// If scope is nil, this will panic.
// A scope should always be injected before this handler is called.
if scope.Session != nil {
// The session was already loaded, pass to the next handler
next.ServeHTTP(rw, req)
return
}
session, err := j.getJwtSession(req)
if err != nil {
logger.Errorf("Error retrieving session from token in Authorization header: %v", err)
if j.denyInvalidJWTs {
http.Error(rw, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return
}
}
// Add the session to the scope if it was found
scope.Session = session
next.ServeHTTP(rw, req)
})
}
// getJwtSession loads a session based on a JWT token in the authorization header.
// (see the config options skip-jwt-bearer-tokens, extra-jwt-issuers, and bearer-token-login-fallback)
func (j *jwtSessionLoader) getJwtSession(req *http.Request) (*sessionsapi.SessionState, error) {
auth := req.Header.Get("Authorization")
if auth == "" {
// No auth header provided, so don't attempt to load a session
return nil, nil
}View on GitHub (pinned to 33c2eb92de)
Solutions
- Obtain a fresh, valid JWT from the configured issuer and resend with 'Authorization: Bearer <token>'
- Verify the JWT's signature key, issuer, and audience match the middleware configuration
- Check server logs for 'Error retrieving session from token in Authorization header' to see the underlying cause
- If tokens are only sometimes invalid and should not be hard-denied, disable the deny-invalid-JWTs option
Example fix
// client side // before Authorization: eyJhbGciOi... // after Authorization: Bearer eyJhbGciOi... // with a valid, unexpired token
Defensive patterns
Strategy: try-catch
Validate before calling
parts := strings.SplitN(authz, " ", 2)
valid := len(parts) == 2 && parts[0] == "Bearer" && len(parts[1]) > 0
if !valid { /* refresh or obtain a token before the request */ } Type guard
func hasBearerToken(h http.Header) (string, bool) {
const p = "Bearer "
v := h.Get("Authorization")
return strings.TrimPrefix(v, p), strings.HasPrefix(v, p)
} Try / catch
// parse and validate the JWT client-side before sending:
tok, err := jwt.Parse(token, keyfunc)
if err != nil || !tok.Valid {
token = refreshToken()
} Prevention
- Refresh tokens proactively before expiry; add clock-skew tolerance
- Confirm issuer/audience configuration matches what your IdP issues
- Always use the exact 'Bearer <token>' header format
- Handle 403 by re-authenticating rather than retrying with the same token
When it happens
Trigger: Sending a request whose Authorization header JWT fails validation (bad signature, expired, wrong issuer/audience, malformed) while the JWT session middleware is configured with deny invalid JWTs enabled.
Common situations: Expired or rotated signing keys after a key change; clock skew between client and server; token from a different issuer than configured; copy-pasted tokens with extra whitespace or 'Bearer' casing issues.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- unable to verify bearer token
- failed to verify token: %v
- audience from claim %s with value %s does not match with any
- session is expired
- login.gov provider requires a private key for signing JWTs
AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06).
Data as JSON: /api/errors/2e170871312ed94d.
Report an issue: GitHub.