Authentication
Authentication
The Infomaxim API uses JWT (JSON Web Tokens) for authentication. All protected endpoints require a valid JWT access token in the Authorization header.
Authentication Flow
- Login with credentials to receive access and refresh tokens
- Include access token in Authorization header for subsequent requests
- When access token expires (1 hour), use refresh token to obtain a new access token
- Refresh tokens are valid for 30 days
Authentication Headers
Authorization: Bearer <your_jwt_access_token>
Content-Type: application/json
POST/auth/login
Authenticates a user and returns JWT tokens for API access.
Business Logic
- Validates email and password format
- Uses Passport local strategy to authenticate user credentials
- Searches for user in aurora_users or specified authTable
- Verifies password using bcrypt (upgrades legacy encrypted passwords automatically)
- Generates JWT access token (valid for 1 hour) and refresh token (valid for 30 days)
- Returns user profile data along with tokens
Request Body
{
"email": "user@example.com",
"password": "SecurePass123!",
"appID": 1,
"authTable": "aurora_users"
}
Parameters
-
email
string
required
User's email address. Must be a valid email format.
-
password
string
required
User's password. Minimum 8 characters.
-
appID
number
optional
Application ID for the Infomaxim instance. Optional but recommended.
-
authTable
string
optional
Custom authentication table name. Defaults to 'aurora_users'.
Success Response (200 OK)
{
"status": "Success",
"token": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 123,
"email": "user@example.com",
"firstName": "John",
"lastName": "Doe",
"role": "admin"
}
}
}
Error Responses
// 401 Unauthorized - Invalid credentials
{
"status": "Failed",
"message": "Invalid credentials"
}
// 401 Unauthorized - Authentication failed
{
"status": "Failed",
"message": "Authentication failed"
}
// 400 Bad Request - Validation error
{
"status": "Failed",
"message": "Validation error",
"errors": [
{
"field": "email",
"message": "Please provide a valid email address"
}
]
}
Example Usage
// JavaScript Example
const response = await fetch('http://localhost:3001/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'user@example.com',
password: 'SecurePass123!',
appID: 1
})
});
const data = await response.json();
const accessToken = data.data.accessToken;
# cURL Example
curl -X POST http://localhost:3001/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "SecurePass123!",
"appID": 1
}'
POST/auth/sign-up
Registers a new user account in the system.
Business Logic
- Validates all required fields and email format
- Validates password strength (minimum 8 characters with uppercase, lowercase, number, and special character)
- Checks if email already exists in the system
- Hashes password using bcrypt for secure storage
- Inserts new user record using parameterized queries to prevent SQL injection
- Creates version tracking record for audit purposes
- Returns encrypted user ID and user details
Request Body
{
"email": "newuser@example.com",
"password": "SecurePass123!",
"firstname": "Jane",
"lastname": "Smith",
"appID": 1,
"authTable": "aurora_users"
}
Parameters
-
email
string
required
Email address for the new user. Must be unique in the system.
-
password
string
required
Password for the account. Must be minimum 8 characters with at least one uppercase letter, one lowercase letter, one number, and one special character (@$!%*?&).
-
firstname
string
optional
User's first name. Maximum 50 characters.
-
lastname
string
optional
User's last name. Maximum 50 characters.
-
appID
number
optional
Application ID for registration context.
-
authTable
string
optional
Custom authentication table name. Defaults to appropriate table based on context.
Success Response (200 OK)
{
"status": "Success",
"token": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 124,
"email": "newuser@example.com",
"firstName": "Jane",
"lastName": "Smith"
}
}
}
Error Responses
// 409 Conflict - Email already exists
{
"status": "Failed",
"message": "User with this email already exists"
}
// 400 Bad Request - Password validation failed
{
"status": "Failed",
"message": "Password does not meet security requirements",
"requirements": {
"minLength": true,
"hasUpperCase": false,
"hasLowerCase": true,
"hasNumber": true,
"hasSpecialChar": false
}
}
// 400 Bad Request - Validation error
{
"status": "Failed",
"message": "Validation error",
"errors": [
{
"field": "password",
"message": "Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character"
}
]
}
POST/auth/refresh-token
Obtains a new access token using a valid refresh token without requiring the user to log in again.
Business Logic
- Validates the refresh token format and structure
- Decodes the refresh token using the JWT secret
- Extracts user ID from the token payload
- Retrieves current user data from aurora_users table
- Generates new access and refresh token pair
- Returns both tokens for continued authentication
- Access tokens expire after 1 hour; refresh tokens expire after 30 days
Request Body
{
"payload": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
Parameters
-
payload
object
required
Object containing both access_token and refresh_token from previous authentication.
-
payload.access_token
string
required
Current (possibly expired) access token.
-
payload.refresh_token
string
required
Valid refresh token used to generate new access token.
Success Response (200 OK)
{
"status": "Success",
"token": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
Error Responses
// 400 Bad Request - Invalid token format
{
"status": "Failed",
"message": "Invalid token format"
}
// 401 Unauthorized - Token expired
{
"status": "Failed",
"message": "Refresh token has expired"
}
// 500 Internal Server Error - Token processing failed
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
POST/auth/sign-out
Logs out the current user by invalidating their authentication session.
Business Logic
- Accepts request to terminate user session
- Client should discard access and refresh tokens
- Optionally accepts refresh token for server-side invalidation
- Returns success confirmation
- Note: JWT tokens are stateless, so client-side token removal is the primary logout mechanism
Request Headers
Authorization: Bearer <access_token>
Content-Type: application/json
Request Body
{
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Parameters
-
refreshToken
string
optional
Refresh token to be invalidated. Optional parameter for enhanced security.
Success Response (200 OK)
{
"status": "Success",
"message": "Signed out successfully"
}
Example Usage
// JavaScript Example
const response = await fetch('http://localhost:3001/auth/sign-out', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken
},
body: JSON.stringify({
refreshToken: refreshToken
})
});
// Clear tokens from local storage
localStorage.removeItem('accessToken');
localStorage.removeItem('refreshToken');
Notes
- This endpoint always returns success (200 OK) as logout is primarily client-side with JWT tokens
- No authentication is required to call this endpoint
- The client is responsible for discarding tokens from storage
- Server-side token blacklisting is not implemented in the current version
Password Reset Overview
Password reset is a two-step process: first requesting a reset token via email, then using that token to set a new password.
POST/auth/request-pass
Initiates a password reset by sending a secure reset token to the user's email address.
Business Logic
- Validates email format and required fields
- Retrieves application profile using appID
- Searches for user by email in aurora_users table
- Generates secure JWT reset token with user ID and expiration
- Constructs reset URL with domain from application profile
- Sends password reset email with link containing token
- Logs the password reset request for audit purposes
- Returns success message regardless of user existence (security best practice)
Request Body
{
"email": "user@example.com",
"appID": 1,
"url": "https://yourdomain.com/reset-password"
}
Parameters
-
email
string
required
Email address of the user requesting password reset. Must be valid email format.
-
appID
number
required
Application ID to retrieve correct application context and domain.
-
url
string
optional
Custom URL for the password reset page. If not provided, uses default from app profile.
Success Response (200 OK)
{
"status": "Success",
"message": "Email with reset password instructions was sent to user@example.com."
}
Error Responses
// 400 Bad Request - Validation error
{
"status": "Failed",
"message": "Validation error",
"errors": [
{
"field": "email",
"message": "Email is required"
},
{
"field": "appID",
"message": "Application ID is required"
}
]
}
// 500 Internal Server Error
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
POST/auth/reset-pass
Completes the password reset process using the token sent via email.
Business Logic
- Validates password strength requirements (min 8 chars, uppercase, lowercase, number, special character)
- Verifies password and confirmPassword match
- Validates reset token is not expired or tampered with
- Extracts user ID from verified reset token
- Hashes new password using bcrypt
- Updates user password in specified authTable using parameterized query
- Logs password reset completion
- Returns success confirmation
Request Body
{
"password": "NewSecurePass123!",
"confirmPassword": "NewSecurePass123!",
"reset_password_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"authTable": "aurora_users"
}
Parameters
-
password
string
required
New password. Must be minimum 8 characters with at least one uppercase letter, one lowercase letter, one number, and one special character (@$!%*?&).
-
confirmPassword
string
required
Password confirmation. Must exactly match the password field.
-
reset_password_token
string
required
Secure reset token received via email from /auth/request-pass endpoint.
-
authTable
string
optional
Authentication table name. Defaults to 'aurora_users' if not specified.
Success Response (200 OK)
{
"status": "Success",
"message": "Password reset successfully"
}
Error Responses
// 400 Bad Request - Password validation failed
{
"status": "Failed",
"message": "Password does not meet security requirements",
"requirements": {
"minLength": true,
"hasUpperCase": true,
"hasLowerCase": true,
"hasNumber": false,
"hasSpecialChar": true
}
}
// 400 Bad Request - Passwords don't match
{
"status": "Failed",
"message": "Validation error",
"errors": [
{
"field": "confirmPassword",
"message": "Passwords do not match"
}
]
}
// 400 Bad Request - Invalid or expired token
{
"status": "Failed",
"message": "Reset password token has expired or is invalid"
}
// 500 Internal Server Error
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
POST/auth/user-email
Retrieves user email and role information using an encrypted user ID token.
Business Logic
- Decrypts the provided encrypted userId parameter
- Extracts user ID and expiration date from decrypted data
- Validates that the token has not expired
- Queries aurora_users table for user_email and primary_role
- Returns user email and role if token is valid
- Used for user verification flows and access validation
Request Body
{
"userId": "encrypted_user_id_token"
}
Parameters
-
userId
string
required
Encrypted user ID token containing user ID and expiration date. Generated by the system for secure user identification.
Success Response (200 OK)
{
"status": "Success",
"email": "user@example.com",
"role": "admin"
}
Error Responses
// 400 Bad Request - Token expired
{
"status": "Failed",
"message": "Token expired"
}
// 500 Internal Server Error - Decryption failed
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
POST/auth/invite-link
Generates a secure invite link to share folder access with a user.
Business Logic
- Requires JWT authentication - user must be logged in
- Accepts user ID and folder ID parameters
- Creates relationship between user and folder in aurora_related table
- Sets expiry date to 60 days from generation
- Generates encrypted URL token containing user ID and expiration
- Returns encrypted invite link token
- Token can be used to grant folder access to specified user
- Logs invite link generation for audit trail
Request Headers
Authorization: Bearer <access_token>
Content-Type: application/json
Request Body
{
"user": 123,
"folder_id": 456
}
Parameters
-
user
number
required
User ID to whom folder access will be granted.
-
folder_id
number
required
Folder ID that will be shared with the user.
Success Response (200 OK)
{
"status": "Success",
"link": "encrypted_invite_token_string"
}
Error Responses
// 401 Unauthorized - No authentication token
{
"status": "Failed",
"message": "Unauthorized"
}
// 500 Internal Server Error
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
POST/auth/user-sms-code
Sends a one-time SMS verification code to the user's registered mobile number.
Business Logic
- Decrypts encrypted userId parameter to extract user ID
- Validates token has not expired
- Retrieves user's mobile number from aurora_users table
- Validates mobile number exists
- Generates secure 6-digit random verification code
- Hashes verification code using bcrypt and stores in database
- Sends SMS with verification code to user's mobile
- Logs SMS code generation for audit and security monitoring
Request Body
{
"userId": "encrypted_user_id_token"
}
Parameters
-
userId
string
required
Encrypted user ID token containing user ID and expiration. Same format as used in /auth/user-email.
Success Response (200 OK)
{
"status": "Success",
"message": "SMS code sent successfully"
}
Error Responses
// 400 Bad Request - Token expired
{
"status": "Failed",
"message": "Token expired"
}
// 400 Bad Request - No mobile number
{
"status": "Failed",
"message": "Mobile number missing"
}
// 500 Internal Server Error
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
POST/auth/getFolderLimits
Retrieves the list of folders that a specific user has access to.
Business Logic
- Retrieves application user context using appID
- Accepts table name and user ID parameters
- Queries aurora_related table to find folder relationships
- Filters by master_id matching the provided userId
- Joins with aurora_folders to get folder details
- Returns array of folder IDs user has access to
- Used for access control and folder permission management
Request Body
{
"appID": 1,
"table": "aurora_folders",
"userId": 123
}
Parameters
-
appID
number
required
Application ID for retrieving correct application context.
-
table
string
required
Table name for folder relationships (typically "aurora_folders").
-
userId
number
required
User ID to retrieve folder access permissions for.
Success Response (200 OK)
{
"status": "Success",
"data": [
{
"linked": 456
},
{
"linked": 789
}
]
}
Error Responses
// 500 Internal Server Error
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
OAuth / Social Login (AuthKit)
Infomaxim supports social and SSO login via an Auth Facade that keeps Infomaxim's own JWT tokens as the stable client-facing identity. The provider is WorkOS AuthKit (phase 1); the architecture is designed to swap providers without breaking existing sessions or client token shapes.
How it works
- Your client calls
POST /auth/oauth/authkit/startto obtain an authorization URL. - Redirect the user to that URL (system browser or embedded WebView). For Electron or other public clients, generate a PKCE code challenge/verifier pair first.
- WorkOS/AuthKit authenticates the user and redirects back to your
redirectUriwith a short-livedcode(and thestateyou provided). - Your client calls
POST /auth/oauth/authkit/callbackwith thecode(plus thecodeVerifierfor PKCE flows). Infomaxim exchanges the code with WorkOS, creates or links anaurora_identitiesrecord, and returns standard Infomaxim JWT tokens — identical in shape toPOST /auth/login. - Use the returned
access_tokenandrefresh_tokenexactly as you would for password-based login. WorkOS tokens are never exposed to the client.
Identity mapping
A new aurora_identities table links external provider users to rows in aurora_customers (or another configured authTable). Safe auto-linking by email is applied only when:
- The provider asserts the email is verified, and
- Exactly one matching Infomaxim user exists in the same (appID, authTable) scope with that email.
Otherwise a new user row is created. This prevents silent account takeover via email collisions.
PKCE (recommended for Electron / mobile)
// Generate a PKCE pair in the browser / renderer process
const codeVerifier = crypto.getRandomValues(new Uint8Array(32))
.reduce((s,b)=>s+b.toString(16).padStart(2,'0'),'');
const encoded = new TextEncoder().encode(codeVerifier);
const digest = await crypto.subtle.digest('SHA-256', encoded);
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'');
// Pass codeChallenge to /start, codeVerifier to /callback
Configuration
The following environment variables must be set on the API server:
-
WORKOS_API_KEY
WorkOS secret API key (from the WorkOS Dashboard → API Keys).
-
WORKOS_CLIENT_ID
WorkOS client ID (from the WorkOS Dashboard → Configuration).
-
WORKOS_ALLOWED_AUTH_TABLES
Comma-separated list of authTables that may use OAuth login. Defaults to
aurora_customers. Addaurora_usersonly if admin SSO is required.
POST/auth/oauth/authkit/start
Returns an AuthKit authorization URL that the client should redirect the user to in order to begin the OAuth login flow. Supports PKCE for public clients (Electron, mobile).
Business Logic
- Validates that
appIDandredirectUriare present. - Verifies the app exists using the Infomaxim app registry.
- Builds an AuthKit authorization URL via the WorkOS SDK, optionally embedding a PKCE challenge.
- Returns the URL and the echoed
statevalue.
Request Body
{
"appID": 42,
"redirectUri": "https://your-app.com/auth/callback",
"authTable": "aurora_customers",
"state": "random-csrf-state-string",
"codeChallenge": "base64url-encoded-sha256-of-verifier",
"codeChallengeMethod": "S256"
}
Parameters
-
appID
number
required
Infomaxim application ID.
-
redirectUri
string
required
URI that WorkOS will redirect to after authentication. Must match a URI registered in the WorkOS Dashboard.
-
authTable
string
optional
Infomaxim identity table. Defaults to
aurora_customers. Pass this forward to/callback. -
state
string
optional
Opaque client-generated value forwarded unchanged to the callback. Use for CSRF protection — verify it in the callback response matches what you sent here.
-
codeChallenge
string
optional
PKCE code challenge (Base64URL-encoded SHA-256 of the
codeVerifier). Required for public clients. -
codeChallengeMethod
string
optional
PKCE method. Only
"S256"is accepted. Defaults to"S256"whencodeChallengeis provided.
Success Response (200 OK)
{
"status": "Success",
"authorizationUrl": "https://auth.workos.com/sso/authorize?client_id=...&redirect_uri=...&...",
"state": "random-csrf-state-string"
}
Error Responses
// 400 Bad Request - Missing required field
{
"status": "Failed",
"message": "redirectUri is required"
}
// 400 Bad Request - WorkOS not configured
{
"status": "Failed",
"message": "WorkOS clientId (WORKOS_CLIENT_ID) is not configured"
}
Example — web client
// Step 1: get the authorization URL
const { authorizationUrl, state } = await fetch('/auth/oauth/authkit/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
appID: 42,
redirectUri: 'https://your-app.com/auth/callback',
state: crypto.randomUUID() // store this for CSRF check
})
}).then(r => r.json());
// Step 2: redirect the user
window.location.href = authorizationUrl;
Example — Electron (PKCE)
// Generate a PKCE pair before calling /start
const codeVerifier = crypto.getRandomValues(new Uint8Array(32))
.reduce((s,b)=>s+b.toString(16).padStart(2,'0'),'');
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'');
const { authorizationUrl } = await fetch('/auth/oauth/authkit/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
appID: 42,
redirectUri: 'myapp://auth', // deep-link URI registered in WorkOS
codeChallenge,
codeChallengeMethod: 'S256'
})
}).then(r => r.json());
// Open the system browser
shell.openExternal(authorizationUrl); // Electron shell API
POST/auth/oauth/authkit/callback
Exchanges the authorization code returned by WorkOS for a pair of Infomaxim JWT tokens. The response is identical in shape to POST /auth/login, so no client-side changes are needed beyond calling this endpoint instead.
Business Logic
- Validates that
appID,code, andredirectUriare present. - Verifies the app exists using the Infomaxim app registry.
- Exchanges the code with WorkOS (passing
codeVerifierfor PKCE flows) to obtain the WorkOS user object. - Looks up an existing
aurora_identitiesrow for(provider=authkit, providerUserId)within the sameappIDandauthTable. - If none found and the email is verified, checks for a single matching
aurora_customersrow and links it. - If no match, creates a new
aurora_customers(orauthTable) row and a new identity mapping. - Issues Infomaxim JWT access + refresh tokens (same as
/auth/login) for the resolved user. - WorkOS tokens are discarded server-side and never returned to the client.
Request Body
{
"appID": 42,
"code": "01HXYZ...",
"redirectUri": "https://your-app.com/auth/callback",
"authTable": "aurora_customers",
"codeVerifier": "your-pkce-code-verifier",
"state": "random-csrf-state-string"
}
Parameters
-
appID
number
required
Infomaxim application ID.
-
code
string
required
Authorization code returned by WorkOS in the callback redirect (query parameter
?code=…). -
redirectUri
string
required
Must exactly match the
redirectUriused in/auth/oauth/authkit/start. -
authTable
string
optional
Infomaxim identity table. Defaults to
aurora_customers. Must match the value passed to/start. -
codeVerifier
string
optional
PKCE code verifier. Required when
codeChallengewas supplied to/start. -
state
string
optional
Echoed back from WorkOS. Verify this matches the value you sent to
/startbefore calling this endpoint (CSRF protection).
Success Response (200 OK)
{
"status": "Success",
"token": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600
},
"user": {
"_id": "encrypted-user-id",
"email": "user@example.com",
"firstname": "Jane",
"lastname": "Smith",
"displayname": "Jane Smith",
"photourl": "https://workos.com/profile-pic.jpg",
"emailverified": true
}
}
Error Responses
// 400 Bad Request - Missing required field
{
"status": "Failed",
"message": "code is required"
}
// 400 Bad Request - Code invalid or expired
{
"status": "Failed",
"message": "invalid_grant: Authorization code has already been used."
}
// 400 Bad Request - authTable not allowed
{
"status": "Failed",
"message": "OAuth login into authTable 'aurora_users' is not allowed by configuration."
}
// 500 Internal Server Error
{
"status": "Failed",
"message": "An error occurred while processing your request"
}
Example — web client (callback handler)
// On your redirectUri page, extract query params from the URL
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const returnedState = params.get('state');
// CSRF check: verify state matches what you stored before calling /start
if (returnedState !== sessionStorage.getItem('authkit_state')) {
throw new Error('State mismatch – possible CSRF attack');
}
const { status, token, user } = await fetch('/auth/oauth/authkit/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
appID: 42,
code,
redirectUri: 'https://your-app.com/auth/callback'
})
}).then(r => r.json());
if (status === 'Success') {
// Treat exactly the same as a /auth/login response
localStorage.setItem('access_token', token.access_token);
localStorage.setItem('refresh_token', token.refresh_token);
}
Example — Electron (PKCE)
// In your deep-link handler (app.on('open-url') / custom protocol)
app.on('open-url', async (event, url) => {
const params = new URL(url).searchParams;
const code = params.get('code');
const { token, user } = await fetch('http://localhost:3001/auth/oauth/authkit/callback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
appID: 42,
code,
redirectUri: 'myapp://auth',
codeVerifier: store.get('authkit_code_verifier') // saved before calling /start
})
}).then(r => r.json());
// Store Infomaxim tokens in the Electron secure store
secureStore.set('access_token', token.access_token);
secureStore.set('refresh_token', token.refresh_token);
});