PS256 (RSA-PSS SHA-256)
PS256 is an asymmetric JWT signing algorithm that combines RSA with PSS padding and SHA-256, defined in RFC 7518 as part of the RSA-PSS family. Only the authorization server holds the RSA private key; resource servers and third parties verify tokens with the public key distributed via PEM files or a JWKS endpoint. PSS provides tighter security proofs than the PKCS#1 v1.5 padding used by RS256, making PS256 the preferred RSA choice in modern cryptographic designs and some financial API standards. PS256 uses the same minimum 2048-bit RSA key sizes as RS256 — the difference is padding scheme, not key length. Adoption requires confirming library and gateway support across your stack, but for greenfield asymmetric deployments where all verifiers support PSS, PS256 offers the strongest RSA-based JWT signing option available in mainstream JOSE implementations.
Last updated July 25, 2026
How It Works
PS256 produces a JWS token with header {"alg":"PS256","typ":"JWT"} and your claim set in the payload. After Base64url encoding both segments, the signing input is header.payload. The signer loads an RSA private key (minimum 2048 bits) and applies RSASSA-PSS with SHA-256: MGF1 with SHA-256 as the mask generation function, a salt length matching the hash output, and SHA-256 as the underlying hash. The resulting signature is Base64url-encoded as the third segment. Verifiers fetch the public key — from a local PEM, a JWKS document, or a cached key set keyed by kid — and run the corresponding PSS verify operation. Critically, PS256 signatures are not compatible with RS256 verifiers even when the same RSA key pair is used, because PKCS#1 v1.5 and PSS produce different signature bytes over identical inputs. Production setups publish a JWKS endpoint listing the public key with "kty":"RSA", "alg":"PS256", and a unique kid for rotation. Middleware must pin algorithms: ['PS256'] and reject tokens whose header declares a different alg. Combine signature verification with standard claim checks (exp, aud, iss) and key rotation procedures that overlap old and new public keys during rollover windows.
When to Use
Choose PS256 for new asymmetric JWT deployments where microservices, partners, or browser clients verify tokens without access to the signing key. Prefer it over RS256 when your platform supports PSS, when standards such as FAPI recommend RSA-PSS, or when security architecture reviews request modern padding schemes. PS256 fits OAuth2 providers, multi-tenant SaaS platforms, and API gateways that publish JWKS for distributed verification.
When Not to Use
Avoid PS256 when legacy API gateways, older JWT libraries, or third-party integrations only support RS256 — compatibility failures appear as signature validation errors that are hard to diagnose under pressure. Skip it for single-service monoliths that both issue and verify tokens internally; HS256 with a strong secret is simpler. Do not mix PS256 and RS256 on the same key without distinct kid values and explicit verifier routing, or you will create ambiguous verification paths.
Key Length Requirements
Use RSA keys of at least 2048 bits for PS256, identical to RS256 requirements. Generate a fresh key pair with OpenSSL, your cloud KMS, or an RSA key generator tool. Store the private key in a hardware security module or secrets manager; publish only the public key via JWKS. Consider 4096-bit keys for long-lived root signing keys or high-assurance compliance mandates. Rotate keys by publishing overlapping JWKS entries with different kid values before retiring the old private key.
Security Pitfalls
- Verifying PS256 tokens with RS256 configuration silently fails or worse, accepting wrong algorithms if allowlists are too broad.
- Publishing private keys alongside public keys in JWKS endpoints or container images exposes the signing capability to attackers.
- Skipping kid-based key lookup and hardcoding a single public key prevents zero-downtime rotation when keys expire.
- Accepting tokens without validating aud and iss after signature verification allows cross-service token replay.
- Assuming all JWT libraries support PS256 — test your language stack, API gateway, and mobile SDKs before committing.
Code Examples
Node.js — sign and verify PS256
const fs = require('fs');
const jwt = require('jsonwebtoken');
const privateKey = fs.readFileSync('private.pem');
const publicKey = fs.readFileSync('public.pem');
const token = jwt.sign(
{ sub: 'user-99', aud: 'api.example.com' },
privateKey,
{ algorithm: 'PS256', keyid: 'key-2026-01', expiresIn: '1h' }
);
const payload = jwt.verify(token, publicKey, {
algorithms: ['PS256'],
audience: 'api.example.com',
});
console.log(payload.sub);Python — sign and verify PS256
import jwt
with open('private.pem', 'rb') as f:
private_key = f.read()
with open('public.pem', 'rb') as f:
public_key = f.read()
token = jwt.encode(
{"sub": "user-99", "aud": "api.example.com"},
private_key,
algorithm="PS256",
headers={"kid": "key-2026-01"},
)
payload = jwt.decode(
token,
public_key,
algorithms=["PS256"],
audience="api.example.com",
)
print(payload["sub"])Go — sign and verify PS256
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v5"
)
func main() {
privateKey, _ := jwt.ParseRSAPrivateKeyFromPEM(privatePEM)
publicKey, _ := jwt.ParseRSAPublicKeyFromPEM(publicPEM)
token := jwt.NewWithClaims(jwt.SigningMethodPS256, jwt.MapClaims{
"sub": "user-99",
"aud": "api.example.com",
"exp": time.Now().Add(time.Hour).Unix(),
})
token.Header["kid"] = "key-2026-01"
tokenString, _ := token.SignedString(privateKey)
parsed, _ := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
if t.Method != jwt.SigningMethodPS256 {
return nil, fmt.Errorf("unexpected alg: %v", t.Header["alg"])
}
return publicKey, nil
})
fmt.Println(parsed.Valid)
}Generate Keys
Recommended: 2048-bit
Open Rsa Key GeneratorRelated Comparisons
Related Terms
Related Guides
Frequently Asked Questions
What is the difference between PS256 and RS256?
Both use RSA keys of the same size. RS256 signs with PKCS#1 v1.5 padding; PS256 uses RSA-PSS, which has stronger theoretical security properties. Signatures are not interchangeable — verifiers must explicitly support PS256.
Can I use the same RSA key pair for PS256 and RS256?
The same key material can technically sign with both algorithms, but doing so is discouraged. Use separate key pairs with distinct kid values to avoid confusion and simplify rotation. Never verify both algorithms with one undifferentiated configuration.
How do I publish PS256 public keys for verifiers?
Expose a JWKS endpoint at /.well-known/jwks.json containing the RSA public key with alg set to PS256 and a unique kid. Verifiers cache keys by kid and refresh periodically. During rotation, publish both old and new keys until outstanding tokens expire.
Which JWT libraries support PS256?
Modern versions of jsonwebtoken, PyJWT, golang-jwt, and jose4j support PS256. Always verify your specific version — PS256 support was added after RS256 in many libraries. Test end-to-end in CI with real tokens before production rollout.
Should I choose PS256 or ES256 for a new project?
Both are strong asymmetric choices. ES256 produces smaller keys and signatures; PS256 leverages existing RSA infrastructure and HSM support. Choose PS256 when your organization standardizes on RSA-PSS; choose ES256 when compact keys and performance matter more.
Looking for a short definition?
Glossary: PS256 (RSA-PSS-SHA256)