oauth2-proxy/oauth2-proxy · error
malformed access token, expected 3 parts got %d
Error message
malformed access token, expected 3 parts got %d
What it means
getAccessClaims splits the session's access token to read its JWT payload and count the dot-separated parts. If fewer than 2 parts are found, the token is not a usable JWT and this error is thrown. Despite the message mentioning 3 parts, the check rejects tokens with fewer than 2 parts.
Source
Thrown at providers/keycloak_oidc.go:116
for _, role := range roles {
s.Groups = append(s.Groups, formatRole(role))
}
return nil
}
type realmAccess struct {
Roles []string `json:"roles"`
}
type accessClaims struct {
RealmAccess realmAccess `json:"realm_access"`
ResourceAccess map[string]interface{} `json:"resource_access"`
}
func (p *KeycloakOIDCProvider) getAccessClaims(s *sessions.SessionState) (*accessClaims, error) {
parts := strings.Split(s.AccessToken, ".")
if len(parts) < 2 {
return nil, fmt.Errorf("malformed access token, expected 3 parts got %d", len(parts))
}
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
if err != nil {
return nil, fmt.Errorf("malformed access token, couldn't extract jwt payload: %v", err)
}
var claims accessClaims
if err := json.Unmarshal(payload, &claims); err != nil {
return nil, err
}
return &claims, nil
}
// getClientRoles extracts client roles from the `resource_access` claim with
// the format `client:role`.
//
// ResourceAccess format:View on GitHub (pinned to 33c2eb92de)
Solutions
- Ensure the Keycloak client issues JWT access tokens (check 'Access Token' format settings in the Keycloak client config)
- Verify the session has a non-empty AccessToken before the refresh/extraction flow
- Re-authenticate to get a fresh token set rather than relying on a partially populated session
- If tokens are opaque by design, disable Keycloak-specific role extraction from the access token
Defensive patterns
Strategy: validation
Validate before calling
parts := strings.Split(s.AccessToken, ".")
if len(parts) < 3 {
return errors.New("access token is not a JWT; skipping role extraction")
} Type guard
func isJWTLike(token string) bool {
return strings.Count(token, ".") >= 2
} Prevention
- Ensure the Keycloak client issues JWT-format access tokens
- Never store empty/opaque tokens in sessions expected to carry JWTs
- Log token shape (segment count) at debug level to catch format drift
- Skip role extraction gracefully when tokens are opaque
When it happens
Trigger: extractRoles calls getAccessClaims with a session whose AccessToken is empty, opaque, or otherwise lacks at least two dot-separated segments.
Common situations: Keycloak client configured without 'Accept OIDC ID tokens' so only opaque access tokens are issued; access token empty because the session was created from a refresh flow without tokens; a non-JWT bearer token supplied to CreateSessionFromToken.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- malformed access token, couldn't extract jwt payload: %v
- could not create session from token: %v
- unable to verify bearer token
- login.gov provider requires a private key for signing JWTs
- email in id_token (%s) isn't verified
AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06).
Data as JSON: /api/errors/c7e87cf7920bc0ae.
Report an issue: GitHub.