Convert Ory Sessions to JSON Web Tokens
Ory offers a powerful session management system that is based on cookies. In some contexts however, relying on Cookies is not possible:
- You need to make a cross-origin (CORS) request where including the Ory Session Cookie is not trivial or possible.
- You need a JWT which represents a signed-in user.
- You need to integrate with a third party such as Zendesk SSO JWTs.
- You want to reduce the amount of calls to Ory's APIs.
In this guide, we will show you how to convert Ory Sessions to JSON Web Tokens (JWTs).
End-to-end example
Let's look at an end-to-end example. This guide assumes that you already have an Ory Network project running. If not, create a new project now. First we need to create a JSON Web Key set and store it locally:
ory create jwk some-example-set \
--alg ES256 --project $PROJECT_ID --format json-pretty \
> es256.jwks.json
Next, we need to create a JsonNet template that will be used to modify the claims of the JWT:
local claims = std.extVar('claims');
local session = std.extVar('session');
{
claims: {
iss: claims.iss + "/additional-component",
schema_id: session.identity.schema_id,
session: session,
}
}
The easiest way to supplies these files to Ory Network is to base64-encode them:
JWKS_B64_ENCODED=$(cat es256.jwks.json | base64)
JSONNET_B64_ENCODED=$(cat claims.jsonnet | base64)
Next, we configure our Ory Network project's tokenizer templates. The key we choose here is jwt_example_template1
. We supply
that template with the base64-encoded files from above:
ory patch identity-config $PROJECT_ID \
--add '/session/whoami/tokenizer/templates/jwt_example_template1={"jwks_url":"base64://'$JWKS_B64_ENCODED'","claims_mapper_url":"base64://'$JSONNET_B64_ENCODED'","ttl":"10m"}' \
--format yaml
Great! Everything is set up! Let's convert an Ory Session to a JWT:
- Ory JS SDK
- REST API
import { Configuration, FrontendApi } from "@ory/client"
const frontend = new FrontendApi(
new Configuration({
basePath: `https://${process.env.ORY_PROJECT_SLUG}.projects.oryapis.com`,
}),
)
export async function toSessionWithJwt(sessionId: string) {
const session = await frontend.toSession({
tokenize_as: "jwt_example_template1",
})
const jwt = session.tokenized
return jwt
}
curl -X GET \
-H "Cookie: ory_session...=..." \
"https://$PROJECT_SLUG.projects.oryapis.com/sessions/whoami?tokenize_as=jwt_example_template1"
{
// ...
"tokenized": "{the-jwt}"
}
For more details see the API documentation.
To verify the resulting JSON Web Token, export the public key from the JSON Web Key Set and use it to verify the token:
ory get jwk some-example-set \
--public \
--project $PROJECT_ID --format json-pretty \
> es256-public.jwks.json
JSON Web Token templates
Now that you have seen how this feature works in practice, let's look at how to configure it in detail. Before issuing a JWT for a Ory Session, you need to define one or more Ory Session tokenizer templates. A template has a unique key, a claims template, a TTL, and a URL where the cryptographic keys (JSON Web Key Sets) are fetched from:
session:
whoami:
tokenizer:
templates:
jwt_template_1:
jwks_url: base64://... # A JSON Web Key Set (required)
claims_mapper_url: base64://... # A JsonNet template for modifying the claims
ttl: 1m # 1 minute (defaults to 10 minutes)
another_jwt_template:
jwks_url: base64://... # A JSON Web Key Set
JSON Web Token claim mapper
You can customize the JSON Web Token claims by providing a JsonNet template to claims_mapper_url
.
The sub
claim can not be customized and is always set to the Ory Session's IdentityID
.
The template has access to these variables:
claims
: The default claims the token has per default. You can modify these claims but not remove them:jti
: A unique UUID v4 value.iss
: The project's slug url (https://$PROJECT_SLUG.projects.oryapis.com
).exp
: The token's expiry which uses the template'sttl
value.sub
: The Ory Session'sIdentityID
.sid
: The Ory Session'sID
.nbf
: The time when the token becomes valid ("now").iat
: The time when the token was issued at ("now").
session
: Contains the Ory Session's data. See the Ory Session documentation for more information.
The template must return a JSON object. For example:
local claims = std.extVar('claims');
local session = std.extVar('session');
{
claims: {
foo: "baz",
sub: "this can not be overwritten and will always be session.identity.id",
schema_id: session.identity.schema_id,
aal: session.authenticator_assurance_level,
second_claim: claims.exp,
// ...
}
}
JSON Web Token signing key(s)
The jwks_url
must contain a JSON Web Key Set. All common cryptographic algorithms for JSON Web Tokens are supported such as
ES256, RS256, RS512, and others.
We recommend using ES256 or ES512 for signing JSON Web Tokens. Avoid using symmetric algorithms such as the HS family (HS256, HS512, etc).
To generate test-keys you can use a service such as mkjwk.org. To generate keys for production, use the Ory CLI:
ory create jwk some-example-set \
--alg ES256 --project $PROJECT_ID --format json-pretty
{
"set": "example-key-set",
"keys": [
{
"alg": "ES256",
"crv": "P-256",
"d": "XdO-4OkdDxsOhU_XwYFAzEg1Z3DfQ8LhwivJeFq-ppo",
"kid": "3045631b-95a8-433c-ab54-93fa52a55ea8",
"kty": "EC",
"use": "sig",
"x": "AAYxrjPNt6M-XBY1H57Mc_6moiETkg_Cf2egHXPOEGo",
"y": "mNX9UCBa82GNrvIIHFFNxsw-LPKksbwCMoaIybyWMEY"
}
]
}
If the key set contains more than one key, the first key in the list will be used for signing:
{
set: "example-key-set",
keys: [
// This key will be used for signing:
{
alg: "ES256",
// ...
},
{
alg: "ES256",
// ...
},
],
}