API Authentication

Authenticate requests to the MaxRMM REST API using JWT access and refresh tokens.

Base URL

https://api.maxrmm.com

All API endpoints are served over HTTPS. HTTP requests are rejected.

Authentication Flow

MaxRMM uses a JWT (JSON Web Token) authentication flow with short-lived access tokens and long-lived refresh tokens.

1. Login

POST /api/auth/login
Content-Type: application/json

{
  "email": "admin@company.com",
  "password": "your-password"
}

Response (no MFA):

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
  "mfaRequired": false
}

Response (MFA enabled):

{
  "mfaRequired": true,
  "mfaToken": "eyJhbGciOiJIUzI1NiIs..."
}

2. MFA Verification (if required)

If the login response includes mfaRequired: true, send the TOTP code:

POST /api/auth/mfa-verify
Content-Type: application/json

{
  "mfaToken": "eyJhbGciOiJIUzI1NiIs...",
  "code": "123456"
}

Response is the same as a successful login (accessToken + refreshToken).

Note: The mfaToken expires after 5 minutes. If it expires, the user must log in again.

3. Using the Access Token

Include the access token in the Authorization header for all API requests:

GET /api/agents
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

4. Refreshing Tokens

Access tokens expire after a short period. Use the refresh token to get a new pair without re-entering credentials:

POST /api/auth/refresh
Content-Type: application/json

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...(new)",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs...(new)",
  "mfaRequired": false
}

Important: Each refresh token can only be used once. After refreshing, the old refresh token is invalidated and a new one is returned. Store the new refresh token for future use.

Token Lifecycle

Token Lifetime Storage Recommendation
Access Token 15 minutes In-memory only. Do not persist to disk or localStorage in browsers.
Refresh Token 7 days Secure HTTP-only cookie or encrypted storage. Never expose in client-side code.
MFA Token 5 minutes In-memory only. Discard after MFA verification.

Access Token Payload

The JWT access token contains these claims:

{
  "technicianId": "cl8f2k9x0001abcdef012345",
  "companyId": "cl8f2k9x0002abcdef012345",
  "role": "admin",
  "iat": 1711234567,
  "exp": 1711235467
}
Claim Description
technicianIdUnique identifier of the authenticated technician
companyIdTenant/company the technician belongs to
rolePermission level: admin, technician, or readonly
iatIssued-at timestamp (Unix epoch)
expExpiration timestamp (Unix epoch)

Error Responses

Status Error Meaning
400Email and password requiredMissing required fields in login request
401Invalid email or passwordCredentials do not match
401Invalid or expired MFA tokenMFA token has expired (5-minute window)
401Invalid TOTP codeThe 6-digit MFA code is wrong
401Invalid or expired refresh tokenRefresh token was already used or expired

Example: Full Auth Flow in cURL

# 1. Login
ACCESS=$(curl -s -X POST https://api.maxrmm.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@company.com","password":"your-password"}' \
  | jq -r '.accessToken')

# 2. Use the token
curl -s https://api.maxrmm.com/api/agents \
  -H "Authorization: Bearer $ACCESS" \
  | jq '.[].hostname'