oauth2-proxy/oauth2-proxy · error
could not create session from token: %v
Error message
could not create session from token: %v
What it means
KeycloakOIDCProvider.CreateSessionFromToken delegates to the generic OIDC provider to verify a bearer ID token and build a session. Any underlying verification failure (signature, expiry, audience, malformed token) is wrapped as 'could not create session from token'.
Source
Thrown at providers/keycloak_oidc.go:53
var _ Provider = (*KeycloakOIDCProvider)(nil)
// addAllowedRoles sets Keycloak roles that are authorized.
// Assumes `SetAllowedGroups` is already called on groups and appends to that
// with `role:` prefixed roles.
func (p *KeycloakOIDCProvider) addAllowedRoles(roles []string) {
if p.AllowedGroups == nil {
p.AllowedGroups = make(map[string]struct{})
}
for _, role := range roles {
p.AllowedGroups[formatRole(role)] = struct{}{}
}
}
// CreateSessionFromToken converts Bearer IDTokens into sessions
func (p *KeycloakOIDCProvider) CreateSessionFromToken(ctx context.Context, token string) (*sessions.SessionState, error) {
ss, err := p.OIDCProvider.CreateSessionFromToken(ctx, token)
if err != nil {
return nil, fmt.Errorf("could not create session from token: %v", err)
}
// Extract custom keycloak roles and enrich session
if err := p.extractRoles(ss); err != nil {
return nil, err
}
return ss, nil
}
// EnrichSession is called after Redeem to allow providers to enrich session fields
// such as User, Email, Groups with provider specific API calls.
func (p *KeycloakOIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {
err := p.OIDCProvider.EnrichSession(ctx, s)
if err != nil {
return fmt.Errorf("could not enrich oidc session: %v", err)
}
return p.extractRoles(s)View on GitHub (pinned to 33c2eb92de)
Solutions
- Ensure the bearer token passed is a valid, unexpired ID token from the correct Keycloak realm
- Verify the --oidc-issuer-url matches the realm that issued the token exactly
- Check server clock sync (NTP) to avoid token-time verification failures
- Confirm the JWKS URL is reachable and the signing keys match the realm's current keys
Defensive patterns
Strategy: try-catch
Validate before calling
parts := strings.Split(token, ".")
if len(parts) != 3 {
return errors.New("not a JWT ID token: expected 3 segments")
} Try / catch
ss, err := provider.CreateSessionFromToken(ctx, token)
if err != nil {
log.Printf("token rejected: %v", err) // includes signature/expiry cause
return http.StatusUnauthorized
} Prevention
- Pass ID tokens, not access tokens, where an ID token is expected
- Keep server clocks NTP-synchronized with the Keycloak host
- Pin the issuer URL to the exact realm that issues tokens
- Rotate trust only through the realm's JWKS endpoint, not static keys
When it happens
Trigger: CreateSessionFromToken is called with a bearer ID token and the embedded OIDC CreateSessionFromToken returns an error — invalid signature, expired token, wrong issuer/audience, or malformed JWT.
Common situations: Passing an access token instead of an ID token; clock skew between server and Keycloak; Keycloak realm/issuer URL changed; key set (JWKS) rotation mismatch; token truncated or copied incorrectly.
Related errors
- email in id_token (%s) isn't verified
- failed to verify token: %v
- failed to parse default id_token claims: %v
- audience claim %s holds unsupported type %T
- audience claims %v do not exist in claims: %v
AI-assisted analysis of oauth2-proxy/oauth2-proxy@33c2eb92de (2026-09-06).
Data as JSON: /api/errors/b5b0715adb9df306.
Report an issue: GitHub.