{"record":{"id":"b5b0715adb9df306","repo":"oauth2-proxy/oauth2-proxy","slug":"could-not-create-session-from-token-v","errorCode":null,"errorMessage":"could not create session from token: %v","messagePattern":"could not create session from token: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"providers/keycloak_oidc.go","lineNumber":53,"sourceCode":"var _ Provider = (*KeycloakOIDCProvider)(nil)\n\n// addAllowedRoles sets Keycloak roles that are authorized.\n// Assumes `SetAllowedGroups` is already called on groups and appends to that\n// with `role:` prefixed roles.\nfunc (p *KeycloakOIDCProvider) addAllowedRoles(roles []string) {\n\tif p.AllowedGroups == nil {\n\t\tp.AllowedGroups = make(map[string]struct{})\n\t}\n\tfor _, role := range roles {\n\t\tp.AllowedGroups[formatRole(role)] = struct{}{}\n\t}\n}\n\n// CreateSessionFromToken converts Bearer IDTokens into sessions\nfunc (p *KeycloakOIDCProvider) CreateSessionFromToken(ctx context.Context, token string) (*sessions.SessionState, error) {\n\tss, err := p.OIDCProvider.CreateSessionFromToken(ctx, token)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"could not create session from token: %v\", err)\n\t}\n\n\t// Extract custom keycloak roles and enrich session\n\tif err := p.extractRoles(ss); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn ss, nil\n}\n\n// EnrichSession is called after Redeem to allow providers to enrich session fields\n// such as User, Email, Groups with provider specific API calls.\nfunc (p *KeycloakOIDCProvider) EnrichSession(ctx context.Context, s *sessions.SessionState) error {\n\terr := p.OIDCProvider.EnrichSession(ctx, s)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"could not enrich oidc session: %v\", err)\n\t}\n\treturn p.extractRoles(s)","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/oauth2-proxy/oauth2-proxy/blob/33c2eb92dea78204f7a18bc2dfdbccc220f39257/providers/keycloak_oidc.go#L35-L71","documentation":"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'.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"parts := strings.Split(token, \".\")\nif len(parts) != 3 {\n    return errors.New(\"not a JWT ID token: expected 3 segments\")\n}","typeGuard":null,"tryCatchPattern":"ss, err := provider.CreateSessionFromToken(ctx, token)\nif err != nil {\n    log.Printf(\"token rejected: %v\", err) // includes signature/expiry cause\n    return http.StatusUnauthorized\n}","preventionTips":["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"],"tags":["oidc","jwt","keycloak","token-validation"],"backgroundTag":"jwt-token-expired","analyzedSha":"33c2eb92dea78204f7a18bc2dfdbccc220f39257","analyzedAt":"2026-09-06T08:51:53.077Z","contentChangedAt":"2026-09-06T08:51:53.077Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}