Documentation Index
Fetch the complete documentation index at: https://docs.terang.ai/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Terang AI supports Single Sign-On (SSO) via signed JWT tokens. Your organization signs a JWT with your private key, and Terang AI verifies it using your public key. This allows your members to access Terang AI directly from your platform without creating a separate account.Finding Your Server IP
The IP address you need to whitelist is the outbound IP of your server — the IP thatapi.terang.ai sees when your server makes a request.
The IP whitelist is enforced on the direct connection to
api.terang.ai. If your integration redirects the user’s browser with the JWT in the URL (e.g. window.location = "https://api.terang.ai/sso/verify?token=..."), the gateway will see the user’s browser IP, not your server’s IP, and the request will be rejected.To use IP whitelisting you must deliver the JWT server-to-server — for example by proxying the redirect through your backend so that the HTTP request to api.terang.ai originates from your whitelisted server. If this is not possible for your platform, contact us to discuss alternatives.VM / VPS (DigitalOcean, Linode, etc.)
VM / VPS (DigitalOcean, Linode, etc.)
Use the public IP address of your server. You can find it by running:
Google Cloud (GKE / Kubernetes)
Google Cloud (GKE / Kubernetes)
GKE pods use ephemeral IPs by default, which change on restart. Set up Cloud NAT to get a static outbound IP:
- Go to Network Services → Cloud NAT in the GCP Console
- Create a NAT gateway for your VPC and region
- Choose Manual IP and assign a static IP
- Share that static IP with us
AWS (EKS / EC2)
AWS (EKS / EC2)
- EC2: Use the instance’s Elastic IP (public static IP)
- EKS: Set up a NAT Gateway in your VPC with an Elastic IP. All pod traffic will route through it.
- Go to VPC → NAT Gateways in the AWS Console
- Create a NAT Gateway with an Elastic IP
- Update your private subnet route table to route
0.0.0.0/0through the NAT Gateway - Share the Elastic IP with us
Serverless (Vercel, Railway, etc.)
Serverless (Vercel, Railway, etc.)
Most serverless platforms use shared, rotating IPs which cannot be whitelisted. Options:
- Use a proxy service with a static IP (e.g. QuotaGuard, Fixie)
- Move SSO/API calls to a dedicated server with a static IP
- Contact us to discuss alternative authentication methods
How it works
Base URLs
| Environment | URL |
|---|---|
| Production | https://api.terang.ai |
| Development | https://api.dev.terang.ai |
JWT Specification
Header
Use the RS256 algorithm. Thekid field must match the key ID registered with Terang AI (or the kid in your JWKS):
| Field | Type | Max Length | Required | Description |
|---|---|---|---|---|
alg | string | 5 chars | Yes | Must be RS256 |
typ | string | 3 chars | Yes | Must be JWT |
kid | string | 128 chars | Yes | Key ID — used to look up the correct public key from your JWKS. Must match a kid in your registered JWKS, or the key shared directly with Terang AI |
Payload
| Field | Type | Max Length | Required | Description |
|---|---|---|---|---|
iss | string | 253 chars | Yes | Your domain (e.g. iai.or.id). Max 253 per RFC 1035 domain name limit |
aud | string | 9 chars | Yes | Must be exactly terang.ai |
sub | string | 100 chars | Yes | Subject type, e.g. member |
email | string | 254 chars | Yes | Member’s email address. Max 254 per RFC 5321 |
name | string | 255 chars | No | Member’s display name. Used as the user’s name on first login. Falls back to the local part of email if omitted |
membershipId | string | 255 chars | No | Unique member ID in your system. Stored in the LMS user record for cross-system reference |
iat | number | 10 digits | Yes | Issued at (Unix timestamp) |
exp | number | 10 digits | Yes | Expiration (Unix timestamp, max 5 minutes after iat) |
jti | string | 64 chars | Yes | JWT ID. Must be a unique token/session ID generated by your system (e.g., your internal signon MD5 hash = 32 chars, or a UUID = 36 chars). This maps the Terang LMS session directly to your authentication event and prevents replay attacks. |
Public Key Exchange
The Terang AI LMS needs your public key to verify JWT signatures. The gateway itself does not perform cryptographic verification — it only routes requests based on theiss claim.
You have two options for sharing your public key:
Option 1: JWKS Endpoint (Recommended)
Expose your public key at a standard JWKS endpoint. This supports key rotation automatically — when you rotate keys, Terang AI picks up the new key without any manual update.| Field | Type | Max Length | Description |
|---|---|---|---|
kty | string | 3 chars | Key type, must be RSA |
kid | string | 128 chars | Unique key ID — used to match against the JWT header’s kid |
use | string | 3 chars | Must be sig (signature) |
alg | string | 5 chars | Must be RS256 |
n | string | ~342 chars | RSA modulus, Base64url-encoded. For a 2048-bit key: 342 chars |
e | string | 4 chars | RSA exponent, Base64url-encoded. Typically AQAB (4 chars) |
Option 2: Share Public Key Directly
If you cannot host a JWKS endpoint, you can share the PEM-formatted public key directly with the Terang AI team.SSO Redirect
Once the JWT is ready, your backend (not the user’s browser) must call the gateway:Gateway behavior
The gateway (api.terang.ai) does not verify the JWT itself. It:
- Peeks at the
issclaim to identify your organization - Checks that the request comes from a whitelisted IP (your backend’s outbound IP)
- Returns a HTTP 302 response with a
Locationheader pointing to the Terang AI LMS
Location header to the user’s browser (via its own 302 response) so the browser can follow the rest of the redirect chain — that is where the LMS session cookie is set.
LMS behavior
The LMS then:- Verifies the JWT signature using your registered public key
- Validates
iss,aud,exp, andjticlaims - Finds or creates the user account based on
emailandmembershipId - Creates a session (sets a cookie on the user’s browser) and redirects the user to the dashboard
Success response
On success, the redirect chain the user’s browser follows looks like this:/sso/complete) where they can set a permanent password. Subsequent logins go directly to /courses (student’s dashboard).
Error responses
Gateway errors — returned as JSON before the request reaches the LMS:| Scenario | HTTP Status | Body |
|---|---|---|
Missing ?token | 400 | {"error": "token is required"} |
| Malformed JWT | 400 | {"error": "invalid token format"} |
Missing iss claim | 400 | {"error": "missing issuer (iss) claim"} |
| Unknown issuer | 401 | {"error": "unknown issuer: <iss>"} |
| IP not whitelisted | 403 | {"error": "IP x.x.x.x is not whitelisted for issuer <iss>"} |
| Scenario | Redirect URL |
|---|---|
| Invalid JWT signature | /auth/sign-in?error=sso_failed&reason=invalid_token |
Expired token (exp) | /auth/sign-in?error=sso_failed&reason=invalid_token |
| Account creation failed | /auth/sign-in?error=sso_failed&reason=account_creation_failed |
| Session creation failed | /auth/sign-in?error=sso_failed&reason=session_creation_failed |
Implementation Examples
PHP
Node.js
API Requests
All API calls go throughapi.terang.ai with a Bearer JWT token in the Authorization header.
Testing
You can decode and inspect your JWT at jwt.io before sending it to Terang AI. Checklist:- Your domain (
iss) is registered with Terang AI (required for gateway routing) - Your server IP address(es) are whitelisted (required for gateway IP check)
- Public key is shared with Terang AI (via JWKS URL or PEM file, used by the LMS for verification)
- JWT header uses
RS256algorithm - JWT
kidheader is set (and matches thekidin your JWKS if using Option 1) - All required payload fields are present
-
audis set toterang.ai -
expis within 5 minutes ofiat -
jtiis unique per request - The call to
api.terang.ai/sso/verifyis made from your backend, not the user’s browser - Redirect following is disabled (
CURLOPT_FOLLOWLOCATION=false/redirect: 'manual') - The
Locationheader returned by the gateway is forwarded to the user’s browser as a 302
Key Rotation Guide
Rotating your keys regularly is a security best practice. The process differs depending on which option you chose for public key exchange.Rotating with JWKS (Option 1)
With JWKS, you can rotate keys with zero downtime — no coordination with Terang AI needed.Start signing JWTs with the new key
Update your JWT signing code to use the new private key and set
kid to key-2.Rotating with Static PEM (Option 2)
With a static key, rotation requires coordination with the Terang AI team.Send the new public key to Terang AI
Email the new
public_key.pem to founders@terang.ai. Do not start using the new key yet.