ory/hydra · error

Session must be of type JWTSessionContainer but got type: %T

Error message

Session must be of type JWTSessionContainer but got type: %T

What it means

fosite's DefaultJWTStrategy.generate requires the requester's session to implement JWTSessionContainer; any other Session implementation cannot contribute JWT claims and is rejected with this type assertion error. It is a programming/configuration error: the session type attached to the request is wrong for JWT token generation.

Source

Thrown at fosite/handler/oauth2/strategy_jwt.go:90

	case v.Has(jwt.ValidationErrorUnverifiable | jwt.ValidationErrorSignatureInvalid):
		return fosite.ErrTokenSignatureMismatch
	case v.Has(jwt.ValidationErrorExpired):
		return fosite.ErrTokenExpired
	case v.Has(jwt.ValidationErrorAudience |
		jwt.ValidationErrorIssuedAt |
		jwt.ValidationErrorIssuer |
		jwt.ValidationErrorNotValidYet |
		jwt.ValidationErrorId |
		jwt.ValidationErrorClaimsInvalid):
		return fosite.ErrTokenClaim
	default:
		return fosite.ErrRequestUnauthorized
	}
}

func (h *DefaultJWTStrategy) generate(ctx context.Context, tokenType fosite.TokenType, requester fosite.Requester) (string, string, error) {
	if jwtSession, ok := requester.GetSession().(JWTSessionContainer); !ok {
		return "", "", errors.Errorf("Session must be of type JWTSessionContainer but got type: %T", requester.GetSession())
	} else if claims := jwtSession.GetJWTClaims(); claims == nil {
		return "", "", errors.New("GetTokenClaims() must not be nil")
	} else {
		claims.
			With(
				jwtSession.GetExpiresAt(tokenType),
				requester.GetGrantedScopes(),
				requester.GetGrantedAudience(),
			).
			WithDefaults(
				time.Now().UTC(),
				h.Config.GetAccessTokenIssuer(ctx),
			).
			WithScopeField(
				h.Config.GetJWTScopeField(ctx),
			)

		return h.Signer.Generate(ctx, claims.ToMapClaims(), jwtSession.GetJWTHeader())

View on GitHub (pinned to 4174065ffb)

Solutions

  1. Use/attach a session type implementing JWTSessionContainer (e.g. compose fosite's JWTSession or implement GetJWTClaims/GetExpiresAt/GetSubject) for JWT strategy requests
  2. Ensure the session manager/storage creates the JWT-capable session type for token requests, not the default session
  3. If you need opaque tokens, configure the hmac strategy instead of jwt for that grant type
  4. Add a startup type check: if _, ok := sess.(fositeJWT.JWTSessionContainer); !ok { fail fast }

Example fix

// before
session := &fosite.DefaultSession{Subject: user.ID}
// after
session := &oauth2.JWTSession{Session: &fosite.DefaultSession{Subject: user.ID}, Header: &jwt.Header{Extra: map[string]interface{}{"alg":"RS256"}}}
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := req.GetSession().(JWTSessionContainer); !ok {
    return fmt.Errorf("token endpoint misconfigured: session %T does not implement JWTSessionContainer", req.GetSession())
}

Type guard

func asJWTSession(s fosite.Session) (JWTSessionContainer, bool) {
    js, ok := s.(JWTSessionContainer)
    return js, ok
}

Try / catch

resp, err := oauth2Client.GetAccessToken(ctx, req)
if err != nil && strings.Contains(err.Error(), "must be of type JWTSessionContainer") {
    log.Fatalf("config error: jwt strategy requires JWTSessionContainer sessions: %v", err)
}

Prevention

When it happens

Trigger: Calling GenerateAccessToken (or any generate-path) on a strategy built with DefaultJWTStrategy while the request's GetSession() returns a plain/default session (e.g. fosite's DefaultSession or a custom session not implementing JWTSessionContainer) instead of a JWT-capable session (e.g. handler/oauth2.JWTSession or an HMACSession wrapper implementing GetJWTClaims).

Common situations: Switching the access token strategy to jwt in config without changing the session store/manager to create JWTSessionContainer sessions; custom Session types used with the default strategy; upgrading fosite where session wiring was changed.

Related errors


AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03). Data as JSON: /api/errors/b028f98b44299760. Report an issue: GitHub.