Launch Tokens
Mint visitor and player JWTs for Phoenix Prediction iframe launch
Your backend mints Phoenix Prediction launch tokens. The browser receives a ready-to-use token, but it never sees your private signing key.
Phoenix Prediction launch tokens are EdDSA JWTs signed with your Ed25519 private key. Phoenix verifies them with the Ed25519 public key registered on your operator account.
Required Claims
| Claim | Required | Description |
|---|---|---|
iss | Yes | Your Phoenix Prediction operator code |
typ | Yes | visitor or player |
aud | Yes | Audience value assigned for your Phoenix Prediction integration |
iat | Yes | Issued-at time, Unix seconds |
exp | Yes | Expiry time, Unix seconds |
sub | Player only | Your player ID for this user |
name | Player only | Display name Phoenix can show in player-facing UI |
avatar | Player only | Avatar object |
Use short-lived tokens. A practical starting point is minutes, not hours. Phoenix can confirm the exact TTL target for your environment.
Visitor Token
Use a visitor token when the user is not authenticated or should only browse.
{
"iss": "acme",
"typ": "visitor",
"aud": "acme_phoenix_prediction",
"iat": 1779100000,
"exp": 1779100900
}Visitor tokens must not include sub.
Player Token
Use a player token after your site has authenticated the user.
{
"iss": "acme",
"typ": "player",
"sub": "operator-player-123",
"aud": "acme_phoenix_prediction",
"iat": 1779100000,
"exp": 1779100300,
"name": "Player Name",
"avatar": { "kind": "none" }
}sub is your stable player identifier. Your integration continues to use that ID when investigating wallet and support questions.
Avatar Values
Use none when you do not want to show an avatar:
{ "kind": "none" }If image avatars are enabled for your operator, Phoenix will provide the accepted image shape and validation rules.
Node.js Example
import { SignJWT, importPKCS8 } from 'jose';
const privateKeyPem = process.env.PHOENIX_PREDICTION_OPERATOR_PRIVATE_KEY_PEM!;
const key = await importPKCS8(privateKeyPem, 'EdDSA');
const now = Math.floor(Date.now() / 1000);
export async function mintPlayerToken(player: {
id: string;
name: string;
}) {
return new SignJWT({
typ: 'player',
sub: player.id,
name: player.name,
avatar: { kind: 'none' },
})
.setProtectedHeader({ alg: 'EdDSA' })
.setIssuer('acme')
.setAudience('acme_phoenix_prediction')
.setIssuedAt(now)
.setExpirationTime(now + 5 * 60)
.sign(key);
}Token Rotation
When a token is close to expiry, the iframe can ask the parent page for a replacement. Your site should mint a fresh token for the same visitor or player session and send it to the iframe with phoenix:setToken.