21 KiB
SSO Manager API Documentation
Overview
API documentation for the SSO Manager Node application. Provides endpoints for authentication, user management, group management, token management, notifications, and OAuth 2.0 / OpenID Connect.
Base URL: https://your-domain.com
Content Type: application/json (all request and response bodies)
Authentication
Getting a Token
Login via POST /api/auth/login to receive an auth token.
Using the Token
Include the token in every protected request:
auth-token: <token>
Protected Routes
/api/user/*— user management/api/group/*— group management/api/token/*— token management/api/notification/*— notifications/api/oauth/client/*— OAuth client management
Permission Groups
| Group | Grants |
|---|---|
app_sso_admin |
Full user/group/notification management |
app_sso_oauth_admin |
Register and manage OAuth clients |
| Group owner | Manage membership of that specific group |
Self-service: users can always read and modify their own account without admin membership.
Rate Limits
| Endpoint | Limit |
|---|---|
POST /api/auth/login |
10 requests / 15 min |
POST /api/auth/resetpassword |
5 requests / hour |
POST /api/auth/otp/request |
5 requests / 15 min |
POST /api/auth/otp/verify |
10 requests / 15 min |
POST /api/auth/invite/* |
20 requests / hour |
Limits are per IP. The server must be behind a trusted proxy for these to apply correctly.
Authentication Endpoints
Base path: /api/auth
Login
POST /api/auth/login — No auth required
Request:
{ "uid": "username", "password": "user_password" }
Response:
{ "login": true, "token": "auth_token_string", "message": "username logged in!" }
Logout
ALL /api/auth/logout — No auth required
Response:
{ "message": "Bye" }
Username Suggestions
Returns available username suggestions based on name and optional date of birth.
GET /api/auth/username-suggestions — No auth required
Query Parameters:
givenName— First namesn— Last namedob(optional) — Date of birth (used to generate year-variant suggestions)
Response:
{ "suggestions": ["jsmith", "jsmith1990", "johnsmith"] }
Request Password Reset
POST /api/auth/resetpassword — No auth required
Request:
{ "mail": "user@example.com" }
Response:
{ "message": "If the emaill address is in our system, you will receive a message." }
The same response is returned whether or not the email exists. Reset tokens expire after 24 hours.
Complete Password Reset
POST /api/auth/resetpassword/:token — No auth required
URL Parameters: token — from the reset email
Request:
{ "password": "new_password", "confirm": "new_password" }
Response:
{ "message": "Password has been changed." }
The token is invalidated after a successful reset.
Request OTP Code
Send a one-time login code via email or SMS.
POST /api/auth/otp/request — No auth required
Request:
{ "login": "username_or_email", "method": "email" }
method must be email or sms. For sms, the account must have a mobile number on file.
Response:
{ "message": "Code sent", "method": "email", "expires_at": 1234567890000 }
Verify OTP Code
Verify a one-time code and receive an auth token. Also marks the corresponding contact method (email or phone) as verified on the account.
POST /api/auth/otp/verify — No auth required
Request:
{ "login": "username_or_email", "code": "123456" }
Response:
{ "login": true, "token": "auth_token_string" }
Returns 401 if the code is invalid or expired.
Accept Invite (with Email Verification)
Create an account from an invite token after verifying email.
POST /api/auth/invite/:token/:mailToken — No auth required
URL Parameters: token — invite token, mailToken — email verification token
Request:
{
"uid": "username",
"password": "user_password",
"givenName": "First Name",
"sn": "Last Name",
"mail": "user@example.com"
}
Response:
{ "user": "username", "token": "auth_token_string" }
Send Invite Verification Email
Send an email verification link for an invite token.
POST /api/auth/invite/:token — No auth required
URL Parameters: token — invite token
Request:
{ "mail": "user@example.com" }
Response:
{ "message": "sent" }
Impersonate User (Admin)
Creates a temporary password for a target user and returns it. Allows admins to log in as another user for support purposes.
POST /api/auth/impersonate/:uid — Auth required, app_sso_admin
URL Parameters: uid — target username
Response:
{
"uid": "target_username",
"temp_password": "random_temp_password",
"expires_at": 1234567890000
}
The temp password is short-lived. Any previous impersonation session for the same target is revoked first.
End Impersonation (Admin)
Revoke all active impersonation sessions for a user.
DELETE /api/auth/impersonate/:uid — Auth required, app_sso_admin
URL Parameters: uid — target username
Response:
{ "message": "Impersonation ended for username", "revoked": 1 }
User Management Endpoints
Base path: /api/user
All endpoints require authentication.
List All Users
GET /api/user/ — app_sso_admin required
Query Parameters:
detail(optional) — return full user objects instead of a minimal list
Response:
{
"results": [
{ "uid": "username", "mail": "user@example.com", "givenName": "First", "sn": "Last" }
]
}
Create User
POST /api/user/ — app_sso_admin required
Request:
{
"uid": "username",
"password": "user_password",
"givenName": "First Name",
"sn": "Last Name",
"mail": "user@example.com"
}
Response:
{ "results": { "uid": "username", "dn": "uid=username,ou=people,dc=..." } }
Admin-created accounts have password_must_change set automatically.
Get Current User
GET /api/user/me — Any authenticated user
Returns the full user object for the authenticated user, including onboarding state.
Response:
{
"uid": "username",
"mail": "user@example.com",
"givenName": "First",
"sn": "Last",
"dn": "uid=username,ou=people,dc=...",
"onboardingRequired": "yes",
"onboardingNeeds": ["tos", "dob", "password"],
"memberOf": ["cn=group_name,ou=groups,dc=..."]
}
onboardingRequired is "yes" when onboardingNeeds is non-empty. Needs can be "tos", "dob", or "password".
Accept Terms of Service
Mark TOS as accepted for the authenticated user.
POST /api/user/accept-tos — Any authenticated user
Response:
{ "success": true }
Get Admin Stats
Returns user and group counts, recent signups, and inactive users.
GET /api/user/stats — app_sso_admin required
Response:
{
"totalUsers": 42,
"activeUsers": 38,
"inactiveUsers": 4,
"totalGroups": 10,
"recentSignups": [
{ "uid": "newuser", "givenName": "New", "sn": "User", "mail": "new@example.com", "createTimestamp": "20240101000000Z" }
],
"inactiveList": [
{ "uid": "lockeduser", "givenName": "Locked", "sn": "User", "mail": "locked@example.com" }
]
}
Export Users CSV
Download all users as a CSV file.
GET /api/user/export — app_sso_admin required
Response: Content-Type: text/csv, attachment download
Columns: uid, givenName, sn, mail, mobile, uidNumber, isActive, createTimestamp
Get User Verification Status
GET /api/user/:uid/verification — app_sso_admin required
Response:
{
"uid": "username",
"emailVerified": true,
"emailVerifiedAt": 1234567890000,
"phoneVerified": false,
"phoneVerifiedAt": null,
"tosAccepted": true,
"tosAcceptedAt": 1234567890000
}
Get User
GET /api/user/:uid — Any authenticated user
Response:
{ "results": { "uid": "username", "mail": "user@example.com", "givenName": "First", "sn": "Last" } }
Update User
PUT /api/user/:uid — Own account, or app_sso_admin for others
Request: Any subset of editable fields:
{
"givenName": "New First Name",
"sn": "New Last Name",
"mail": "newemail@example.com",
"dateOfBirth": "1990-01-15",
"mobile": "+15551234567",
"sshPublicKey": "ssh-rsa AAAA..."
}
Response:
{ "results": { <updated user object> }, "message": "Updated username user" }
Set User Active/Inactive
Lock or unlock a user account.
PUT /api/user/:uid/active — app_sso_admin required
Request:
{ "active": true }
Response:
{ "uid": "username", "active": true, "message": "User username activated" }
Delete User
DELETE /api/user/:uid — Own account, or app_sso_admin for others
Response:
{ "uid": "username", "results": true }
Change Own Password
PUT /api/user/password — Any authenticated user
Request:
{ "password": "new_password", "confirm": "new_password" }
Response:
{ "results": true }
Clears password_must_change on the account.
Change User Password (Admin)
PUT /api/user/:uid/password — Own account, or app_sso_admin for others
Request:
{ "password": "new_password", "confirm": "new_password" }
Response:
{ "results": true, "message": "User username password changed." }
When an admin changes another user's password, password_must_change is set on that account.
Generate Invite Token
POST /api/user/invite — Any authenticated user
Response:
{ "token": "invite_token_string" }
Add SSH Key
POST /api/user/key — Any authenticated user
Request:
{ "key": "ssh-rsa AAAAB3NzaC1yc2E... user@host" }
Response:
200—{ "message": true }400—{ "message": "error description" }
Group Management Endpoints
Base path: /api/group
All endpoints require authentication.
List Groups
GET /api/group/ — Any authenticated user
Query Parameters:
detail(optional) — return full group objectsmember(optional) — filter to groups containing this UID as a member
Response:
{ "results": [{ "cn": "group_name", "description": "Group description" }] }
Create Group
POST /api/group/ — app_sso_admin required
Request:
{ "name": "group_name", "description": "Group description" }
Response:
{ "results": { "cn": "group_name" }, "message": "group_name was added!" }
The authenticated user is automatically set as the group owner.
Get Group
GET /api/group/:name — Any authenticated user
Response:
{
"results": {
"cn": "group_name",
"description": "Group description",
"member": ["uid=user1,ou=people,dc=...", "uid=user2,ou=people,dc=..."],
"owner": ["uid=owner,ou=people,dc=..."]
}
}
Add Group Owner
PUT /api/group/owner/:group/:uid — app_sso_admin or group owner
Response:
{ "results": true, "message": "Added owner uid to group group." }
Remove Group Owner
DELETE /api/group/owner/:group/:uid — app_sso_admin or group owner
Response:
{ "results": true, "message": "Removed Owner uid from group group." }
Add User to Group
PUT /api/group/:group/:uid — app_sso_admin or group owner
Response:
{ "results": true, "message": "Added user uid to group group." }
Remove User from Group
DELETE /api/group/:group/:uid — app_sso_admin or group owner
Response:
{ "results": true, "message": "Removed user uid from group group." }
Delete Group
DELETE /api/group/:group — app_sso_admin or group owner
Response:
{ "removed": true, "results": { "cn": "group_name" }, "message": "Group group_name Deleted" }
Token Management Endpoints
Base path: /api/token
All endpoints require authentication.
List Token Types
GET /api/token/ — Any authenticated user
Response:
{ "results": ["InviteToken", "PasswordResetToken"] }
List Tokens by Type
GET /api/token/:name — Any authenticated user
Query Parameters: detail (optional) — include full token objects
Response:
{
"results": [
{ "token": "token_string", "created_by": "username", "created_on": 1234567890000, "is_valid": true }
]
}
Get Specific Token
GET /api/token/:name/:token — Any authenticated user
Response:
{ "results": { "token": "token_string", "created_by": "username", "created_on": 1234567890000, "is_valid": true } }
Notification Endpoints
Base path: /api/notification
All endpoints require authentication and app_sso_admin membership.
Notifications send email blasts to filtered groups of users and record history.
Send Notification
POST /api/notification — app_sso_admin required
Request:
{
"subject": "Maintenance window tonight",
"message": "<p>We will be performing maintenance starting at midnight.</p>",
"filter_type": "group",
"filter_value": "host_hec-bot_admin, app_sso_admin",
"active_only": true
}
filter_type values:
| Value | Description |
|---|---|
all_active |
All active (unlocked) users |
all |
All users including inactive |
group |
Members of one or more LDAP groups |
users |
Specific users by UID |
filter_value:
- For
group: comma-separated group names (e.g."host_hec-bot_admin, app_sso_admin") - For
users: JSON array of UIDs (e.g.'["wmantly","jsmith"]') - Unused for
all_activeandall
active_only (boolean, default false): when true with group or all filter types, only active (unlocked) users receive the notification. Has no effect on all_active (which is always active-only).
Response:
{
"results": {
"notification_id": "uuid",
"created_by": "wmantly",
"created_on": 1234567890000,
"subject": "Maintenance window tonight",
"message": "<p>...</p>",
"filter_type": "group",
"filter_value": "host_hec-bot_admin",
"active_only": true,
"status": "sent",
"sent_count": 5,
"failed_count": 0,
"sent_at": 1234567890123
}
}
External API usage example:
# Login once, store token
TOKEN=$(curl -s -X POST https://sso.example.com/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"uid":"monitor","password":"..."}' | jq -r .token)
# Send notification to a group
curl -X POST https://sso.example.com/api/notification \
-H "auth-token: $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"subject": "hec-bot maintenance",
"message": "<p>The hec-bot VM will restart at 3am.</p>",
"filter_type": "group",
"filter_value": "host_hec-bot_admin",
"active_only": true
}'
List Notification History
GET /api/notification — app_sso_admin required
Response:
{
"results": [
{
"notification_id": "uuid",
"subject": "Maintenance window",
"filter_type": "group",
"filter_value": "host_hec-bot_admin",
"active_only": true,
"status": "sent",
"sent_count": 5,
"failed_count": 0,
"created_by": "wmantly",
"created_on": 1234567890000,
"sent_at": 1234567890123
}
]
}
Results are sorted by created_on descending (most recent first).
Get Notification Record
GET /api/notification/:id — app_sso_admin required
Response: { "results": { <notification object> } }
OAuth 2.0 / OpenID Connect
The SSO Manager acts as an OAuth 2.0 Authorization Server and OpenID Connect Provider.
Discovery
GET /.well-known/openid-configuration — No auth required
Returns the OIDC discovery document with endpoint URLs, supported scopes, and signing algorithms.
Authorization Endpoint
GET /oauth/authorize — No auth required (redirects to login if not authenticated)
Query Parameters:
response_type— Must becodeclient_id— Registered OAuth client IDredirect_uri— Must exactly match a URI registered for the clientscope— Space-separated:openid,profile,emailstate— Opaque value returned unchanged in the redirectcode_challenge— PKCE challenge (SHA-256 of code_verifier, base64url-encoded)code_challenge_method— Must beS256
Renders the consent screen. On approval, redirects to redirect_uri?code=<code>&state=<state>.
Token Endpoint
POST /oauth/token — No auth required (client authenticates via credentials)
Content-Type: application/x-www-form-urlencoded or application/json
Client Authentication: client_id + client_secret in the request body, or HTTP Basic Auth.
Authorization Code Grant
grant_type=authorization_code
&code=<auth_code>
&redirect_uri=<redirect_uri>
&client_id=<client_id>
&client_secret=<client_secret>
&code_verifier=<pkce_verifier>
Refresh Token Grant
grant_type=refresh_token
&refresh_token=<refresh_token>
&client_id=<client_id>
&client_secret=<client_secret>
Refresh tokens are rotated on each use — the old token is invalidated and a new one is returned.
Response:
{
"access_token": "uuid",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "uuid",
"id_token": "<jwt>"
}
UserInfo Endpoint
GET /oauth/userinfo — Bearer token required (Authorization: Bearer <access_token>)
Response (claims vary by granted scopes):
{
"sub": "username",
"name": "First Last",
"given_name": "First",
"family_name": "Last",
"preferred_username": "username",
"email": "user@example.com"
}
OAuth Client Management
Base path: /api/oauth/client
All endpoints require authentication and app_sso_oauth_admin membership.
List Clients
GET /api/oauth/client/
Response:
{
"results": [
{
"client_id": "uuid",
"name": "Home Assistant",
"description": "Home automation",
"redirect_uris": ["https://ha.example.com/auth/external/callback"],
"scopes": ["openid", "profile", "email"],
"token_lifetime": { "access_token": 3600, "refresh_token": 2592000 },
"created_by": "wmantly",
"created_on": 1234567890000
}
]
}
Register Client
POST /api/oauth/client/
Request:
{
"name": "Home Assistant",
"description": "Home automation dashboard",
"redirect_uris": ["https://ha.example.com/auth/external/callback"],
"scopes": ["openid", "profile", "email"],
"token_lifetime": { "access_token": 3600, "refresh_token": 2592000 }
}
redirect_uris may also be a newline-separated string. scopes may also be a space-separated string.
Response:
{
"results": { "client_id": "uuid", "name": "Home Assistant" },
"client_secret": "raw-secret-shown-once",
"message": "OAuth client 'Home Assistant' created. Save the client secret — it will not be shown again."
}
The client_secret is shown only once. Store it immediately.
Get Client
GET /api/oauth/client/:client_id
Response: { "results": { <client object> } }
Update Client
PUT /api/oauth/client/:client_id
Request: Any subset of name, description, redirect_uris, scopes, token_lifetime, is_valid.
Response: { "results": { <updated client> }, "message": "..." }
Delete Client
DELETE /api/oauth/client/:client_id
Response: { "client_id": "uuid", "message": "OAuth client '...' deleted." }
Rotate Client Secret
POST /api/oauth/client/:client_id/rotate
Response:
{
"client_secret": "new-raw-secret-shown-once",
"message": "Client secret rotated for '...'. Save it — it will not be shown again."
}
The old secret is invalidated immediately. The new secret is shown only once.
Token Lifetimes
Configurable per-client via token_lifetime. Global defaults (in seconds):
{ "access_token": 3600, "refresh_token": 2592000 }
Error Responses
All endpoints return errors in this format:
{ "name": "ErrorName", "message": "Error message description" }
HTTP Status Codes
| Code | Meaning |
|---|---|
200 |
Success |
400 |
Bad Request — invalid input |
401 |
Unauthorized — auth required, token invalid, or insufficient permission |
404 |
Not Found |
429 |
Too Many Requests — rate limit exceeded |
500 |
Internal Server Error |
502 |
Bad Gateway — upstream service failure (e.g. SMS delivery) |