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.pem

IMPORTANT: 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:

  1. Verifies the user is authenticated on your site
  2. Generates a short-lived JWT containing user identity
  3. Signs it with your RSA private key
  4. 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

  1. Follow instructions here to install Arena Comment System in your website
  2. 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>
  1. 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.