RS256: RSASSA-PKCS1-v1_5 with SHA-256 in a JWT
RS256 signs with an RSA private key using PKCS#1 v1.5 padding and SHA-256, and verifies with the matching public key. It is the default for OpenID Connect ID tokens because verifiers never need a secret.
At a glance
- Algorithm
- RS256, RSASSA-PKCS1-v1_5 using SHA-256
- Registered in
- RFC 7518 section 3.3
- Implementation requirement
- Recommended
- Key
- RSA key pair, 2048 bits or larger, which RFC 7518 states as a requirement
- Signature size
- Equal to the key size: 256 bytes for a 2048 bit key, 342 base64url characters
- Verified in the decoder
- Yes, in your browser. Paste the PEM public key; the private key is never needed to verify.
In detail
The asymmetry is the whole point. The authorization server keeps the private key and every resource server holds only the public one, so a compromised API cannot mint tokens for the rest of the estate. That is why OpenID Connect names RS256 as the default for ID tokens, and why providers publish public keys at a well known endpoint for anyone to fetch.
RFC 7518 requires a key of 2048 bits or larger. The signature is as long as the modulus, so a 2048 bit key produces a 256 byte signature, 342 base64url characters, roughly eight times an HS256 signature. Moving to a 4096 bit key doubles that again and makes signing noticeably slower, while verification stays cheap, which is the trade to weigh when tokens travel on every request.
Algorithm confusion is the attack this algorithm is famous for. The public key is published, so an attacker takes it, rewrites the header from RS256 to HS256, and computes an HMAC over the token using the public key bytes as the secret. A verifier that selects its algorithm from the header and passes in whatever key it has configured will compute the same HMAC and accept the forgery.
The fix is to decide the algorithm before looking at the token. Configure the verifier with the exact algorithms you accept, reject anything else outright, and use a key object typed to RSA so a symmetric operation cannot be performed with it. The decoder follows the token's own header when offering a verification path, which is the right behaviour for an inspection tool and the wrong behaviour for a service.
Examples
Header: { "alg": "RS256", "typ": "JWT", "kid": "2024-06-key" }
Encoded: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMjQtMDYta2V5In0kid tells the verifier which published key to use, which is how rotation works without downtime.
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----Public key in PEM form. Verification never requires the private key, so nothing sensitive is pasted.
Things that catch people out
- Letting the token choose the algorithm. Pin the accepted algorithms in configuration, otherwise a header rewritten to HS256 turns your published public key into an accepted secret.
- Pasting a certificate or a private key when a public key is wanted. The decoder verifies with a PEM public key, and a certificate has to have its key extracted first.
- Ignoring kid during rotation. Once an issuer publishes two keys, a verifier that always takes the first one fails as soon as signing moves to the second.
Try it: JWT Decoder
Paste a token to decode the header and payload, read the claims and expiry, and verify the signature in your browser. Nothing is uploaded.
JWT Decoder
LOCAL · Browser-OnlyDecode and inspect JSON Web Tokens without sending them to a server
Related JWT claims and algorithms
All jwt claims and algorithms →HS256: HMAC with SHA-256 in a JWT
HS256 signs a JWT with a shared secret using HMAC and SHA-256. Key sizing, the algorithm confusion attack, and verifying one in your browser.
RS512: RSASSA-PKCS1-v1_5 with SHA-512 in a JWT
RS512 signs a JWT with RSA and SHA-512. Why the signature length follows the key rather than the hash, and what the decoder needs to verify one.
PS256: RSASSA-PSS with SHA-256 in a JWT
PS256 signs a JWT using RSA-PSS with SHA-256 and MGF1. How it differs from RS256, why two signatures differ, and verifying with a public key.
RS384: RSASSA-PKCS1-v1_5 with SHA-384 in a JWT
RS384 signs a JWT with RSA and SHA-384. What changes against RS256, what does not, and why the token size stays the same for a given key.
PS384: RSASSA-PSS with SHA-384 in a JWT
PS384 signs a JWT using RSA-PSS with SHA-384 and a 48 byte salt. What changes against PS256, and how the decoder verifies one in your browser.
PS512: RSASSA-PSS with SHA-512 in a JWT
PS512 signs a JWT using RSA-PSS with SHA-512 and a 64 byte salt. Why very small keys cannot carry it, and how verification works in the decoder.
Tools for this
- JWT Decoder Free online JWT decoder - decode and inspect JSON Web Tokens without sending them to a server