SSO Integration Guide
This guide explains how to integrate your website’s authentication system with the Arena widget using a new secure SSO exchange route (SSO v2). This integration allows your authenticated users to automatically sign into Arena when they interact with the embedded widget on your site.
Step 1: Generate an RSA Key Pair
You’ll use your private key to sign JWTs and share the public key with Arena so we can verify them.
🔐 Key Generation (Bash)
# Generate 2048-bit RSA private key
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
# Extract the public key
openssl rsa -pubout -in private_key.pem -out public_key.pemIMPORTANT: Keep private_key.pem secret and secure. Load it from an environment variable. Share only public_key.pem and your JWT endpoint URL with Arena.
Step 2: Implement the Arena JWT SSO Endpoint
Your backend must expose a secure route (e.g. /arena/sso-jwt) that:
- Verifies the user is authenticated on your site
- Generates a short-lived JWT containing user identity
- Signs it with your RSA private key
- Returns the JWT in the response
🧾 JWT Payload Claims
{
"sub": "[email protected]", // Same as email
"email": "[email protected]",
"displayName": "Jane Doe",
"photoURL": "https://example.com/avatar.jpg",
"iat": 1720452000, // Issued at (Unix timestamp)
"exp": 1720452300, // Expires (1 minute from now)
"iss": "your_website_sso_id" // Your website SSO issuer ID, provided by Arena's tech team during onboarding
}
IMPORTANT: Ensure the route is forgery-proof
The custom route /arena/sso-jwt must strictly issue signed JWTs only for the currently authenticated end user, because allowing arbitrary user IDs or names opens a huge security risk: someone could impersonate other users by forging their identity in the payload.
Bad example: The client POSTs { "id": "1234", "name": "Alice" } to /arena/sso-jwt, and the server signs that — this lets a malicious user pretend to be anyone.
OK example: The client sends only its session cookie, the server validates that session, looks up the user in the database to get their real id and name, and then signs a JWT for that user.
🔧 Node.js Example (using jsonwebtoken)
const jwt = require('jsonwebtoken');
const express = require('express');
const app = express();
// must contain the contents of private_key.pem generated in step 1
const PRIVATE_KEY = process.env.ARENA_SSO_PRIVATE_KEY;
// provided by Arena's tech team during onboarding
const ARENA_SSO_ISSUER_ID = process.env.ARENA_SSO_ISSUER_ID;
app.get('/arena/sso-jwt', (req, res) => {
// replace whis validation with your website's own auth validation
const user = req.authenticatedUser;
if (!user) return res.status(401).json({ error: 'Unauthorized' });
const payload = {
sub: user.id, // must be a string
email: user.email,
displayName: user.name,
photoURL: user.avatar,
// handle is a nick name unique to your website
// handle must pass the following regex: ^[a-z0-9_]{1,32}$
handle: user.handle,
joinedAt: user.joinedAt, // in unix-milli (e.g., 1761256322000)
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 60, // 1-minute expiry
iss: ARENA_SSO_ISSUER_ID
};
const token = jwt.sign(payload, PRIVATE_KEY, { algorithm: 'RS256' });
res.json({ token });
});🔧 PHP Example (using firebase/php-jwt)
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
// must contain the contents of private_key.pem generated in step 1
$privateKey = getenv('ARENA_SSO_PRIVATE_KEY');
// provided by Arena's tech team during onboarding
$ssoIssuerID = getenv('ARENA_SSO_ISSUER_ID');
// replace whis validation with your website's own auth validation
$user = get_authenticated_user();
if (!$user) {
http_response_code(401);
echo json_encode(['error' => 'Unauthorized']);
exit;
}
$payload = [
'sub' => $user['id'], // must be a string
'email' => $user['email'],
'displayName' => $user['name'],
'photoURL' => $user['avatar'],
// handle is a nick name unique to your website
// handle must pass the following regex: ^[a-z0-9_]{1,32}$
'handle' => $user['handle'],
'joinedAt' => $user['joinedAt'], // in unix-milli (e.g., 1761256322000)
'iat' => time(),
'exp' => time() + 60,
'iss' => $ssoIssuerID
];
$jwt = JWT::encode($payload, $privateKey, 'RS256');
echo json_encode(['token' => $jwt]);Step 3: Send Information to Arena
Send the following to the Arena team:
- Your public key (contents of
public_key.pem)
Arena will register your public key and endpoint to verify JWTs issued by your system.
Step 4: Setup Arena snippets into your website HTML
- Follow instructions here to install Arena Comment System in your website
- Insert the following code below the Comment System
<div>:
<script>
class ArenaSSO {
constructor() {
// Configuration - replace with your values
this.ssoBackendUrl = "https://your-backend.com/arena/sso-jwt";
this.isArenaLoaded = false;
}
async init() {
// Wait for Arena widget to load
document.addEventListener("arena-loaded", () => {
this.isArenaLoaded = true;
});
}
async getJWTToken() {
// Request JWT token from your backend
const response = await fetch(this.ssoBackendUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const data = await response.json();
return data.token;
}
async authenticateUser() {
// Check if Arena is loaded before proceeding
if (!this.isArenaLoaded) return;
// Get JWT token from backend
const jwtToken = await this.getJWTToken();
// Call Arena's SSO v2 Exchange method
const result = await window.arena.auth.ssoV2Exchange(jwtToken);
}
// Public method to authenticate a specific user
async login() {
await this.authenticateUser();
}
// Public method to logout
logout() {
if (window.arena && window.arena.auth && window.arena.auth.logout) {
window.arena.auth.logout();
}
}
}
// Initialize SSO when page loads
document.addEventListener("DOMContentLoaded", () => {
window.arenaSSO = new ArenaSSO();
});
</script>- In your application use the exposed methods:
// Login a specific user
window.arenaSSO.login();
// Logout current user
window.arenaSSO.logout();Your users are now seamlessly authenticated through your own system without needing to sign in manually.
Updated 3 days ago