module

KemalIdentity::JWT

Constants

HS256 = HMAC.new("HS256", ::OpenSSL::Algorithm::SHA256, 32)

HMAC-SHA-256. The default choice for a token minted and verified by one deployment.

HS384 = HMAC.new("HS384", ::OpenSSL::Algorithm::SHA384, 48)

HMAC-SHA-384.

HS512 = HMAC.new("HS512", ::OpenSSL::Algorithm::SHA512, 64)

HMAC-SHA-512.

RS256 = RSA.new("RS256", ::OpenSSL::Algorithm::SHA256)

RSASSA-PKCS1-v1_5 over SHA-256. What almost every OIDC provider uses.

RS384 = RSA.new("RS384", ::OpenSSL::Algorithm::SHA384)

RSASSA-PKCS1-v1_5 over SHA-256. What almost every OIDC provider uses.

RS512 = RSA.new("RS512", ::OpenSSL::Algorithm::SHA512)

RSASSA-PKCS1-v1_5 over SHA-256. What almost every OIDC provider uses.

Class methods

unverified_issuer(credential : String | Nil, max_bytesize : Int32 = Validator::DEFAULT_MAX_BYTESIZE) : String | Nil

The iss a token claims, read without verifying anything at all.

What this is for

One Validator holds one issuer, so an API accepting tokens from several customer identity providers has one validator each — and has to decide which one to ask. It cannot ask them in turn: every JWT is three base64url segments, so AuthenticatorChain routes them all to the first validator, which fails the signature and stops the chain. Measured, in both orders, in blueprints/0025-maturity-validation-results.md (JWT-01): whichever issuer is registered second has its customers refused.

So the choice has to be made from the token, before any validation, and this is that read — bounded and strict, so an application does not write its own.

issuer = KemalIdentity::JWT.unverified_issuer(credential)
validator = issuer.try { |i| VALIDATORS[i]? }
outcome = validator.try(&.authenticate(credential)) ||
          KemalIdentity::Failed.new(KemalIdentity::FailureReason::InvalidClaim)

What it is not for, and the name says so

The return value is attacker-controlled. Nothing has been verified — not the signature, not exp, not aud. Two rules follow, and both are load-bearing:

  1. Never treat it as an identity. It selects a validator and nothing else. The trustworthy issuer is the one on Validator, after authenticate succeeded — that one was compared against a configured value.
  2. Never build a URL from it. Fetching JWKS from the issuer a token names is server-side request forgery with extra steps: the attacker chooses the host. Look the validator up in a map the application configured at boot, by exact string equality, and refuse anything not in it.

Bounded, like the validator itself

max_bytesize defaults to what Validator uses, and is checked before anything is decoded, so a two-megabyte Authorization header costs one integer comparison. The segment alphabet is the strict base64url of RFC 7515 §2 — the same decoder the validator uses, not a second one that might disagree with it.

Answers nil for anything that is not a well-formed JWT carrying a non-empty string iss. A nil means "no validator can be chosen", which the caller must treat as a refusal rather than as permission to pick a default.

Source

Nested types