Skip to main content
This page specifies the two tokens a license server issues, the authorization token and the session token, the algorithm a generation tool uses to verify them, and the tlp-json-1 canonical form that terms_digest and request_digest are computed over.

Common format

TLP-TOK-1. A license server MUST sign every token with ES256, and MUST set alg, kid and typ in the protected header and no other key-locating header (jwk, jku, x5u, x5c). TLP-TOK-2. A license server MUST publish each signing key in its JWK Set at least 30 days before it signs anything, MUST never reuse a kid, and MUST sign test-mode tokens with keys distinct from live keys. Key rotation is specified with receipt keys.

Authorization token

A check that returns allow carries an authorization token. The platform passes it to the generation tool, which verifies it before it runs the model. TLP-TOK-3. A license server MUST issue an authorization token only for an allow, with exactly the claims above, and MUST NOT issue one for deny or escalate.

Example (informative)

The authorization for Ridgeline’s campaign check, run on Northlight. Protected header:
Payload:

Session token

A session carries a session token, renewed while the session runs. TLP-TOK-4. A license server MUST issue session tokens with exactly the claims above and an exp 300 seconds after iat, and MUST stop issuing them for a session that is ended or terminated. A renewed token MUST keep the jti, tlp.licenses and tlp.facets of the token it replaces.

Several licenses

A decision can rest on several licenses, one for each talent whose license applies. Tokens and receipts name them all in one claim, tlp.licenses. TLP-TOK-5. A license server MUST set tlp.licenses to an array with one entry for each talent whose license the decision relied on, in the order of tlp.talent, and to an empty array when no license applied. Each entry MUST hold talent (the tal_ ID), license (the lic_ ID), revision (the lrv_ ID of the signed revision relied on) and terms_digest (that revision’s terms digest). A talent whose posture allows the use without a license has no entry. A verifier that relies on the terms behind a decision MUST compare each entry’s terms_digest with the terms_digest of the revision the entry names, and MUST NOT rely on an entry whose digests differ. The authorization token example above carries one entry, for Maya Okafor’s license.

Verifying a token

TLP-TOK-6. A generation tool MUST verify a token with the steps below before it generates for a request that carries a token, or that TLP-DSC-10 would require a platform to check, and MUST NOT generate when any step fails. A platform that runs its own model is a generation tool for this rule.
1

Parse

Split the token into its three base64url parts. Decode the header as JSON. Reject anything that is not a JWS Compact Serialization.
2

Check the header

alg MUST be ES256 and typ MUST be tlp-auth+jwt for an authorization or tlp-session+jwt for a session. Reject a token with jwk, jku, x5u or x5c in its header.
3

Find the key

Look up kid in the JWK Set of an issuer you are configured to trust, fetched over HTTPS from the jwks_uri of its discovery document. If kid is unknown, fetch the JWK Set once more. If it is still unknown, reject.
4

Verify the signature

Verify the ES256 signature over the first two parts. Reject on failure.
5

Check the issuer and audience

iss MUST equal the trusted issuer whose key verified the token. aud MUST equal the account ID of the platform the request comes from.
6

Check the time

Reject when the current time is later than exp plus 60 seconds, or earlier than iat minus 60 seconds.
7

Check the content

tlp.ver MUST have major version 1. For an authorization, tlp.decision MUST be allow, and tlp.execution.model MUST equal the model about to run. For a session, tlp.session MUST equal the session you are running.
8

Check the count

For an authorization, count the generations you have run under this jti. Reject when this one would exceed tlp.max_generations. Record it.
9

Check the obligations

For an authorization, reject when tlp.obligations holds a type that is not registered in a protocol version you implement (TLP-OBL-2).
TLP-TOK-7. A generation tool MUST keep its count of generations for each jti until at least 60 seconds after the token’s exp, and MUST count a generation it started even if it failed. TLP-TOK-8. A generation tool MUST NOT accept a receipt, an RSL license token or any token whose typ differs from the one the step expects, in place of an authorization or session token. TLP-TOK-9. A party that caches a JWK Set MUST respect its Cache-Control max-age, and MUST NOT fetch it again on an unknown kid more than once for the same kid within that max-age. A license server that receives a token failing these steps answers with the token_invalid error.

Canonical form

tlp-json-1 is the canonical JSON serialization that every TLP digest is computed over. TLP-TOK-10. To serialize a value in tlp-json-1, an implementation MUST:
  1. encode the output in UTF-8, with no byte order mark;
  2. write no whitespace outside strings;
  3. write object members sorted by key, comparing keys as sequences of Unicode code points;
  4. reject any input object with a duplicate key, rather than serialize it;
  5. write strings as RFC 8785 does: escape " and \, write U+0008, U+0009, U+000A, U+000C and U+000D as \b, \t, \n, \f and \r, write other characters below U+0020 as \u and four lowercase hex digits, and write every other character as itself;
  6. write numbers in the shortest form that reads back as the same IEEE 754 double, as RFC 8785 does, with no -0;
  7. write true, false and null as themselves, and keep the order of array elements.
For keys made only of characters below U+10000, which includes every key TLP defines, rule 3 orders keys the same way as RFC 8785. TLP-TOK-11. A digest MUST be sha256: followed by the 64 lowercase hex characters of the SHA-256 of the canonical bytes. A license revision’s terms_digest is the digest of its terms.

Request digest

TLP-TOK-12. A license server MUST compute a check’s request_digest over this object, in tlp-json-1:
  • inputs holds the check’s inputs in the order sent. A text input becomes { "role", "text" }. A media input becomes { "role", "sha256", "media_type" }, where sha256 is the 64-hex digest of its bytes, however they were sent.
  • use is the use object as sent, with absent fields left out.
  • execution holds provider and model as sent, with absent fields left out. Other execution fields are not part of the digest.
The digest covers the request as checked, before any generation_instructions are added (TLP-DEC-26).

Worked example (informative)

A check for one spoken line in Maya Okafor’s voice, under Northlight’s platform license:
Its canonical bytes:
Its request digest:
Request digest objects contain no numbers, so Python’s standard library produces the same bytes:

End-user claim

TLP-TOK-13. tlp.eu MUST be the lowercase hex HMAC-SHA256 of the end user’s ID under a key the license server holds for the platform. A license server MUST NOT put an end user’s ID, or any other identifier of a person, in a token in the clear. The claim lets the license server and the platform relate decisions about one end user; it reveals nothing to anyone else.

Authorization token format

The token as the Talent API issues it.

Session token format

Claims and renewal of the session token.

Receipts

The third token type, and key rotation.

Security

The threats these rules answer.