* Remove the run-docker-full-stack.sh script to streamline the deployment process and eliminate unnecessary complexity. * fix: update documentation to clarify script behavior for building and pulling images * update docs * fix: update script URL to use classroomio.com for downloads * fix: humanize selfhosting docs and minor amendment * fix: attend to comment * fix: humanize docs * update docs * fix: adjusted the Restarting ClassroomIO... function * fix: update commands and documentation for environment variable handling and upgrades * chore: added space for rebuild
172 lines
5.5 KiB
Plaintext
172 lines
5.5 KiB
Plaintext
---
|
|
title: Token Auth
|
|
description: Sign users in to ClassroomIO from your own app with a short-lived JWT.
|
|
---
|
|
|
|
Token Auth lets an external app sign a user in to ClassroomIO without asking for a ClassroomIO password. Your backend signs a short-lived JWT with your organization's Token Auth secret, then redirects the user's browser to ClassroomIO's token exchange URL.
|
|
|
|
Use Token Auth when you already authenticate users in another product and want a trusted handoff into your ClassroomIO academy.
|
|
|
|
:::info[Enterprise Feature]
|
|
Token Auth requires an **Enterprise** plan.
|
|
|
|
**Cloud:** [Contact us](mailto:support@classroomio.com) to upgrade.
|
|
|
|
**Self-hosted:** Requires an Enterprise license key. Set `LICENSE_KEY` in the API service environment — see [Self Hosting → Enterprise & licensing](/self-hosted/enterprise).
|
|
:::
|
|
|
|
## How It Works
|
|
|
|
1. An organization admin generates a Token Auth signing secret in ClassroomIO.
|
|
2. Your backend authenticates the user in your own app.
|
|
3. Your backend signs a short-lived `HS256` JWT with the ClassroomIO signing secret.
|
|
4. Your app redirects the browser to `/api/auth/token-exchange?token=...&redirect=...`.
|
|
5. ClassroomIO verifies the token, finds or creates the user, adds them to the organization, creates a session, and redirects them to the requested path.
|
|
|
|
## Set Up Token Auth
|
|
|
|
<Steps>
|
|
<Step>
|
|
Sign in to ClassroomIO as an organization admin.
|
|
</Step>
|
|
<Step>
|
|
Open **Settings** → **Authentication** → **Token Auth**.
|
|
</Step>
|
|
<Step>
|
|
Click **Generate secret** and copy the secret immediately. The full secret is shown only once.
|
|
</Step>
|
|
<Step>
|
|
Store the secret in your backend secret manager or environment variables.
|
|
</Step>
|
|
<Step>
|
|
Enable Token Auth after your integration is ready.
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Token Exchange URL
|
|
|
|
Cloud:
|
|
|
|
```text
|
|
https://api.classroomio.com/api/auth/token-exchange
|
|
```
|
|
|
|
Self-hosted:
|
|
|
|
```text
|
|
{PUBLIC_SERVER_URL}/api/auth/token-exchange
|
|
```
|
|
|
|
Query parameters:
|
|
|
|
| Parameter | Required | Description |
|
|
| --- | --- | --- |
|
|
| `token` | Yes | The signed JWT. |
|
|
| `redirect` | No | A ClassroomIO path to open after login. Must start with `/`. Invalid external URLs are ignored and users are sent to `/`. |
|
|
|
|
Example:
|
|
|
|
```text
|
|
https://api.classroomio.com/api/auth/token-exchange?token=eyJ...&redirect=/courses/my-course
|
|
```
|
|
|
|
## JWT Requirements
|
|
|
|
Token Auth accepts `HS256` JWTs signed with your organization's Token Auth secret.
|
|
|
|
Required claims:
|
|
|
|
| Claim | Type | Description |
|
|
| --- | --- | --- |
|
|
| `sub` | string | Stable user identifier from your system. |
|
|
| `email` | string | User email address. ClassroomIO lowercases it before lookup. |
|
|
| `iat` | number | Issued-at timestamp. |
|
|
| `exp` | number | Expiration timestamp. |
|
|
|
|
Optional claims:
|
|
|
|
| Claim | Type | Description |
|
|
| --- | --- | --- |
|
|
| `name` | string | Display name. If omitted, ClassroomIO uses the email username. |
|
|
| `avatar` | string | Public image URL for the user's avatar. |
|
|
|
|
Tokens must be fresh. ClassroomIO rejects tokens older than 5 minutes, so use a short expiration such as 2 minutes.
|
|
|
|
## Node Example
|
|
|
|
```js
|
|
import { SignJWT } from 'jose';
|
|
|
|
const tokenAuthSecret = process.env.CLASSROOMIO_TOKEN_AUTH_SECRET;
|
|
const classroomioAuthUrl = 'https://api.classroomio.com/api/auth/token-exchange';
|
|
|
|
export async function buildClassroomioLoginUrl(user) {
|
|
const secret = new TextEncoder().encode(tokenAuthSecret);
|
|
|
|
const token = await new SignJWT({
|
|
sub: user.id,
|
|
email: user.email,
|
|
name: user.name,
|
|
avatar: user.avatarUrl
|
|
})
|
|
.setProtectedHeader({ alg: 'HS256' })
|
|
.setIssuedAt()
|
|
.setExpirationTime('2m')
|
|
.sign(secret);
|
|
|
|
const url = new URL(classroomioAuthUrl);
|
|
url.searchParams.set('token', token);
|
|
url.searchParams.set('redirect', '/');
|
|
|
|
return url.toString();
|
|
}
|
|
```
|
|
|
|
Redirect the browser to the returned URL after the user clicks "Open ClassroomIO" or any equivalent action in your app.
|
|
|
|
## User Provisioning
|
|
|
|
When the token is valid:
|
|
|
|
- If a ClassroomIO user already exists with the email address, that user is signed in.
|
|
- If no user exists, ClassroomIO creates one with a random password.
|
|
- ClassroomIO adds the user to the organization tied to the signing secret.
|
|
- If the email has a pending invite or pre-created audience row, ClassroomIO links that record first. Otherwise, the user joins with the organization's default role.
|
|
- If `avatar` is present, ClassroomIO updates the user's profile avatar.
|
|
|
|
## Rotating the Secret
|
|
|
|
Rotate the secret from **Settings** → **Authentication** → **Token Auth** when a secret may have been exposed or as part of regular credential rotation.
|
|
|
|
After rotation, update your backend to sign new tokens with the new secret. Old tokens signed with the previous secret stop working.
|
|
|
|
## Troubleshooting
|
|
|
|
### "No active token auth configured"
|
|
|
|
Token Auth is not enabled for the organization. Generate a secret and enable Token Auth in the dashboard.
|
|
|
|
### "Invalid token"
|
|
|
|
Check that:
|
|
|
|
- The token uses `HS256`.
|
|
- The token is signed with the current Token Auth secret.
|
|
- The token has not expired.
|
|
- The token was issued less than 5 minutes ago.
|
|
|
|
### "Invalid token payload"
|
|
|
|
Verify that the JWT includes `sub`, `email`, `iat`, and `exp`, and that `email` is a valid email address.
|
|
|
|
### Redirect sends users to `/`
|
|
|
|
The `redirect` value must be a relative path that starts with `/`. External URLs are ignored for safety.
|
|
|
|
## Security Notes
|
|
|
|
- Sign tokens only on your backend. Never expose the Token Auth secret in browser code.
|
|
- Keep token lifetimes short. Two minutes is usually enough for a browser redirect.
|
|
- Rotate the secret immediately if it is logged, leaked, or committed.
|
|
- Use HTTPS in production.
|