Secret keys
Test keys start withrk_test_; live keys start with rk_live_. Both are sent as
Authorization: Bearer. Each is a
256-bit secret, shown once when you create it in the dashboard.
Reflections stores only a hash, so a lost key cannot be shown again; create a new one.
- Keep keys on your servers, in a secret manager. Never put one in a web page, a mobile app, a browser extension or a repository.
- Use a separate key for each service. Keep live credentials separate from test keys.
- Do not log keys. Redact the
Authorizationheader in your request logs.
Rotate a key
1
Create the new key
Create it in the dashboard with the same scopes.
2
Deploy it
Roll it out to every instance of the service and confirm traffic uses it.
3
Revoke the old key
Revoke it in the dashboard. Requests with it then fail with
401 invalid_api_key.Restricted keys
A restricted key carries only the scopes you give it. A call outside them returns403 insufficient_scope.
The authentication reference lists the endpoints
each scope is intended to cover. A scope does not make an unserved endpoint available; see
Sandbox for test support and live reads
for the three live endpoints. A live license reader needs
licenses:read only.
Give each service the least it needs. A generation worker needs files:write, checks:write and
generations:write. A revocation worker needs revocations:write. Only your admin tooling needs
webhooks:manage.
Acting for licensees
Connected-licensee access is not served in either mode. The API accepts your own account ID and rejects another account withaccount_not_connected. The following requirements apply to
the planned connection flow.
A platform acts for a connected licensee by sending its account ID in Reflections-Account. The
call then runs under that licensee’s licenses, within the connection’s scopes and licenses.
Without an active connection that allows the call, it fails with 403 account_not_connected.
The header is a statement that this request is the licensee’s work. Treat it that way:
- Set it from your own record of which licensee the signed-in user acts for. Never take it from a request parameter, a form field or anything the user can change.
- Send a licensee’s account only for that licensee’s work. Running another customer’s request, or your own, under Ridgeline’s account uses Ridgeline’s licenses for work they did not commission.
- When you receive
connection.revoked, stop sending that account at once.
acct_2q8v1m3n7p4r6s9t0wxyhk5zba, and every check
records both the licensee and the platform.
Verify tokens
An authorization token (typ: tlp-auth+jwt) or a session token (typ: tlp-session+jwt) tells a
generation tool what was authorized. The sandbox issues test authorization tokens only; it does
not serve sessions or clear real talent. Verify every token before relying on it in its intended
environment:
1
Signature
ES256, against the key with the token’s
kid in https://app.reflections.ai/.well-known/jwks.json.2
Header and issuer
typ is the type you expect, and iss is https://app.reflections.ai.3
Audience
aud is the platform account you serve. A token issued to another platform fails here.4
Time
exp has not passed and iat is not in the future, each with at most 60 seconds of leeway.5
Version and obligations
tlp.ver has major version 1, and every type in tlp.obligations is one you handle.6
Model and count
For an authorization token,
tlp.execution.model is the model about to run, and you have run
fewer than tlp.max_generations generations for this jti. For a session token,
tlp.session is the session you are running; it carries no count and is replaced by renewal
every minute.jose for Node.js and PyJWT for Python:
reserve(jti, n, max, exp) stands for an atomic increment in a store every instance of your
tool shares: it adds n to the count for jti and returns false if that would pass max. Keep
each count until 60 seconds after exp, and count a generation you start even if it fails.
Cache the JWKS
Cache the key set for theCache-Control max-age of its response. When a token names a kid you
do not have, refetch once; if it is still unknown, reject the token. The production protocol
requires new keys to be published 30 days before signing, retired public keys to remain available,
and each kid to be unique. These are production requirements, not evidence that a sandbox key
has completed that publication period. The current sandbox uses rfl-test-… signing key IDs.
Webhook signatures
Hosted webhook delivery and secret rotation are not served by the current sandbox. The following is the required verification and rotation contract for the planned service. Every delivery is signed with your endpoint’swhsec_… secret under the
Standard Webhooks scheme. The handler in
Handle revocations shows the full check. The rules:
- Verify against the raw body, before any JSON parsing changes it.
- Compute HMAC-SHA256 with the secret’s base64 part over
webhook-id.webhook-timestamp.body, and accept the delivery if it matches anyv1,entry inwebhook-signature. Compare in constant time. - Reject a
webhook-timestampmore than 5 minutes from your clock. - Use only HTTPS endpoint URLs.
POST /v1/webhook_endpoints/{endpoint_id}/rotate_secret.
For 24 hours, deliveries carry signatures from both the old and the new secret, so you can deploy the
new one without dropping events. Rotate at once if a secret leaks.
Data you send
Send end users as opaque platform IDs, never emails or names, and keep personal data out ofmetadata. Session tokens may reach a client to open the session stream; secret keys never do. See
Privacy modes.
Report a vulnerability
Email security@reflections.ai. Include what you found, the steps to reproduce it, the request IDs involved, and what an attacker could do with it. Test only in test mode, with your own account and the sandbox talent. Do not access other accounts’ data, real talent’s material or other platforms’ outputs, and do not degrade the service for others. Keep the details private until Reflections has fixed the issue.Related
Authentication
Keys, scopes,
Reflections-Account and OAuth.Authorization token
Every claim of the check token.
Security in the Standard
The threat model and its requirements.
Webhooks
Signing, retries and replay.