Authentication
The B12 SIS API uses JWT (JSON Web Tokens) for authentication with access and refresh token rotation.
Overview
Access Token: Short-lived token for API access (default: 24 hours)
Refresh Token: Long-lived token for obtaining new access tokens (default: 7 days)
Token Rotation: Each refresh generates a new token pair
Endpoints
Login
Authenticate with email and password.
Endpoint: POST /api/auth/login
Request:
{
"email": "user@school.edu",
"password": "your-password"
}
Response:
{
"token": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400
},
"user": {
"id": "user-uuid",
"email": "user@school.edu",
"name": "User Name",
"avatar": "https://...",
"teams": [
{
"id": "team-uuid",
"name": "Main Campus"
}
],
"roles": [
{
"id": "role-uuid",
"name": "Admin"
}
]
}
}
Error Responses:
=== “Invalid Credentials”
json { "error": "Invalid email or password" }
Status: 401 Unauthorized
=== “Account Disabled”
json { "error": "Account is disabled" }
Status: 401 Unauthorized
Refresh Token
Get a new access token using a valid refresh token.
Endpoint: POST /api/auth/refresh
Request:
{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 86400
}
!!! warning “Token Rotation” Each refresh invalidates the old refresh token and issues a new pair. Store the new refresh token for future use.
Get Current User
Retrieve the authenticated user’s profile and permissions.
Endpoint: GET /api/auth/me
Headers:
Authorization: Bearer <access_token>
Response:
{
"success": true,
"message": "user",
"data": {
"user": {
"id": "user-uuid",
"email": "user@school.edu",
"name": "User Name",
"avatar": "https://...",
"teams": [...],
"roles": [...]
},
"permissions": {
"Student": ["list", "read", "create", "update", "delete"],
"Teacher": ["list", "read"],
"Class": ["list", "read", "create", "update"]
}
}
}
Change Password
Change the authenticated user’s password.
Endpoint: POST /api/auth/change-password
Headers:
Authorization: Bearer <access_token>
Request:
{
"current_password": "old-password",
"new_password": "new-password",
"confirm_password": "new-password"
}
Response:
{
"success": true,
"message": "Password changed successfully"
}
Validation Rules:
New password must be at least 8 characters
New password must contain uppercase, lowercase, and numbers
New password must be different from current password
Logout
Invalidate the user’s refresh token.
Endpoint: POST /api/auth/logout
Headers:
Authorization: Bearer <access_token>
Response:
{
"message": "Successfully logged out"
}
Reset Password (Admin)
Reset a user’s password to the default. Requires admin role.
Endpoint: POST /api/admin/reset-password/:userid
Headers:
Authorization: Bearer <admin_access_token>
Response:
{
"success": true,
"message": "Password reset successfully"
}
Using Tokens
Token Structure
The JWT contains these claims:
{
"sub": "user-uuid",
"email": "user@school.edu",
"exp": 1704067200,
"iat": 1703980800,
"type": "access"
}
Claim |
Description |
|---|---|
|
User ID |
|
User email |
|
Expiration timestamp |
|
Issued at timestamp |
|
Token type ( |
Security Features
Token Blacklisting
Logout invalidates the refresh token
Changing password invalidates all tokens
Admin can revoke all user tokens
Rate Limiting
Login attempts are rate limited:
5 failed attempts: 1-minute lockout
10 failed attempts: 5-minute lockout
20 failed attempts: Account temporary lock
Security Audit
All authentication events are logged:
Login attempts (success/failure)
Token refresh
Logout
Password changes
Code Examples
JavaScript/TypeScript
class AuthService {
private accessToken: string | null = null;
private refreshToken: string | null = null;
async login(email: string, password: string): Promise<void> {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (!response.ok) {
throw new Error('Login failed');
}
const data = await response.json();
this.accessToken = data.token.access_token;
this.refreshToken = data.token.refresh_token;
}
async refreshTokens(): Promise<void> {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: this.refreshToken })
});
if (!response.ok) {
// Refresh failed, need to re-login
this.accessToken = null;
this.refreshToken = null;
throw new Error('Session expired');
}
const data = await response.json();
this.accessToken = data.access_token;
this.refreshToken = data.refresh_token;
}
getAuthHeaders(): Record<string, string> {
return {
'Authorization': `Bearer ${this.accessToken}`
};
}
}
Axios Interceptor
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.yourschool.edu/api'
});
// Request interceptor - add token
api.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// Response interceptor - handle token refresh
api.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response?.status === 401) {
const refreshToken = localStorage.getItem('refresh_token');
if (refreshToken) {
try {
const response = await axios.post('/api/auth/refresh', {
refresh_token: refreshToken
});
localStorage.setItem('access_token', response.data.access_token);
localStorage.setItem('refresh_token', response.data.refresh_token);
// Retry original request
error.config.headers.Authorization = `Bearer ${response.data.access_token}`;
return api.request(error.config);
} catch {
// Refresh failed, redirect to login
window.location.href = '/login';
}
}
}
return Promise.reject(error);
}
);
SSO / OIDC Login
The system also supports Single Sign-On via OIDC providers. See OIDC Setup Guide for configuration.
OIDC Flow
Redirect to
/api/oidc/login?provider=<provider-id>User authenticates with identity provider
Callback to
/api/oidc/callbackwith authorization codeSystem exchanges code for tokens and creates/updates user
Returns JWT tokens for API access