keycloak/keycloak · error · VerificationException

Token not set

Error message

Token not set

What it means

Thrown by TokenVerifier.parse() when both the jws field and the tokenString field are null. parse() needs a token to deserialize; if no token string was supplied to the verifier (and no pre-parsed JWSInput), there is nothing to parse. This is a usage error — the verifier was constructed without a token and then asked to parse.

Source

Thrown at core/src/main/java/org/keycloak/TokenVerifier.java:402

            audienceChecks[i] = new AudienceCheck(expectedAudiences[i]);
        }
        return this.replaceCheck(AudienceCheck.class, true, audienceChecks);
    }

    /**
     * Add check for verifying that token issuedFor (azp claim) is the expected value
     *
     * @param expectedIssuedFor issuedFor, which needs to be in the target token. Can't be null
     * @return This token verifier
     */
    public TokenVerifier<T> issuedFor(String expectedIssuedFor) {
        return this.replaceCheck(IssuedForCheck.class, true, new IssuedForCheck(expectedIssuedFor));
    }

    public TokenVerifier<T> parse() throws VerificationException {
        if (jws == null) {
            if (tokenString == null) {
                throw new VerificationException("Token not set");
            }

            try {
                jws = new JWSInput(tokenString);
            } catch (JWSInputException e) {
                throw new VerificationException("Failed to parse JWT", e);
            }


            try {
                token = jws.readJsonContent(clazz);
            } catch (JWSInputException e) {
                throw new VerificationException("Failed to read access token from JWT", e);
            }
        }
        return this;
    }

View on GitHub (pinned to 66c7e15a37)

Solutions

  1. Ensure a non-null token string is supplied to TokenVerifier.create(token, clazz) before calling parse/verify.
  2. Add a null/empty guard on the extracted Authorization header before constructing the verifier.
  3. If the token is optional in your flow, branch before building the verifier rather than letting parse() throw.

Example fix

// before: header may be null, verifier built unconditionally
TokenVerifier.create(header, AccessToken.class).verify();

// after: guard the token source
if (header == null || header.isBlank()) {
  throw new UnauthorizedException("Missing bearer token");
}
TokenVerifier.create(header, AccessToken.class).verify();
Defensive patterns

Strategy: validation

Validate before calling

// Guard the token source before constructing the verifier
if (tokenString == null || tokenString.isBlank()) {
  throw new UnauthorizedException("Missing bearer token");
}
TokenVerifier.create(tokenString, AccessToken.class).verify();

Type guard

static boolean hasToken(String s) {
  return s != null && !s.isBlank();
}

Try / catch

try {
  TokenVerifier.create(token, AccessToken.class).verify();
} catch (VerificationException e) {
  if (e.getMessage().equals("Token not set")) {
    // caller error — no token provided; return 401
  } else throw e;
}

Prevention

When it happens

Trigger: Calling TokenVerifier.create(null, AccessToken.class) (or constructing a verifier and never setting a token) followed by .parse() or .verify(). The jws==null branch is entered and the inner tokenString==null check trips.

Common situations: A code path that extracts a token from a request header but proceeds even when the header is absent, or building a verifier lazily and forgetting to populate the token string.

Related errors


AI-assisted analysis of keycloak/keycloak@66c7e15a37 (2026-08-14). Data as JSON: /api/errors/c957d38df9d26030. Report an issue: GitHub.