Identity for teams that read the docs first.
Algebrix Identity is a standards-based authentication and user management platform. This document covers everything needed to integrate sign-in, single sign-on, multi-factor authentication, and programmatic management of users, sessions, invitations, and the audit trail.
01 Overview
Algebrix Identity handles the parts of authentication that are expensive to build and dangerous to get wrong: credential storage, session management, multi-factor enrolment, token issuance, and an auditable record of administrative change.
The platform implements OAuth 2.0 and OpenID Connect as published. There is no proprietary SDK requirement and no custom handshake. Any conformant OIDC client library works against it, so integration effort is measured in configuration rather than in code, and migrating away is a matter of repointing an authority URL.
What this version covers
- Sign-in for single-page, native or mobile, and server-side web applications, using the authorization code flow
- Machine-to-machine access to your own services using the client credentials grant
- Single sign-on across every application in one organization
- Time-based one-time password (TOTP) multi-factor authentication, enforceable for administrators or for everyone
- Self-service applications created from four templates, with an integration view for each
- A management API for users, roles, required actions, password reset emails, invitations, CSV import and export, sessions, sign-in branding, the audit log, and sign-in activity
- Configurable sign-in security: password policy, brute-force protection, session and token lifetimes
- A hosted administration console for every organization, requiring no build effort of your own
Integration requires an organization. Create one at https://identity.algebrix.co/signup. You choose an identifier, the platform provisions the organization, and you create the applications you need from templates in the console. Section 03 covers signup and section 06 takes you from there to a first authenticated call. If you prefer to start from working code, section 06 also lists runnable sample applications for each application type.
Every example in this document uses {organization} as a placeholder for the identifier you choose.
The hosted console
There are two sign-in addresses for the console, one for each kind of administrator:
| Address | Who signs in there |
|---|---|
https://identity.algebrix.co | Account administrators. They manage the account: its organizations, subscription, and usage, plus their own profile, password, and multi-factor enrolment. They can also administer every organization in the account. |
https://identity.algebrix.co/{organization} | Organization administrators, meaning users of that organization who hold the admin role. |
In the console, administrators can do the following:
- Manage users, roles, invitations, and sessions.
- Create and configure applications.
- Set authentication policy.
- Upload a sign-in logo.
- Review the audit log and sign-in activity.
- See usage against the plan.
The management API in section 08 covers user-facing operations programmatically. Automate what you want and leave the rest to the console.
02 Core concepts
Accounts, organizations, applications, users
| Concept | What it is |
|---|---|
| Account | The commercial entity that holds the subscription. Plan allowances belong to the account and are shared across all of its organizations. A billing restriction on the account applies to every organization in it. |
| Organization | The isolation boundary. Users, credentials, sessions, roles, signing keys, and audit records belong to exactly one organization and are invisible to every other. Addressed by a permanent identifier. |
| Application | A client registered in an organization, created from one of four templates. It has a client ID, and a secret if it is confidential. See section 04. |
| User | A person in an organization's directory. They hold exactly one role: admin, manager, or end-user. |
Roles
| Role | Grants |
|---|---|
admin | Access to the organization console and to every endpoint under /api/admin |
manager | An application-level role for your own authorization decisions. It carries no access to the management API. |
end-user | Standard access. No management API access. |
Roles are exclusive: assigning one replaces the previous one.
Two surfaces
Algebrix Identity exposes two separate HTTP surfaces. They serve different purposes and are scoped differently. Confusing them is the most common cause of a failed first integration.
Token issuance, sign-in, sign-out, key publication. Every path carries an organization segment, and the segment is mandatory.
Administration of users, sessions, invitations, branding, and the audit trail. The organization is read from the access token, and every operation is scoped to it.
On the identity surface you state the organization, in the URL. On the management surface you do not: it is derived from the iss claim of the token you present, and every read and write is confined to that organization before any handler runs. There is no organization parameter to pass, and no way to reach another organization's data by changing one.
The same base URL, paths, and code serve every organization you run. Which organization you act on is decided entirely by which token you send.
One exception carries an identifier in the path: the anonymous public endpoint under /api/public/organizations/{organization}, which returns only a sign-in logo. It does not weaken the scoping guarantee, because it exposes nothing beyond a public image. See section 08.
Which credential reaches what
| Credential | Reaches |
|---|---|
A signed-in user holding admin, through any application in the organization | Every endpoint under /api/admin documented in section 08, for that organization only |
A signed-in user holding manager or end-user | No management endpoint. Calls return 403. |
| A machine-to-machine application (client credentials) | No management endpoint in this version. Calls return 403. Machine tokens are for your own services. |
| An account administrator | The console, including account-level operations: organizations, billing, usage, and entitlements. These operations are console-only in this version. An organization token, whatever its role, is refused on them with 403. |
How a request flows
Your application never handles user credentials. The browser is redirected to the identity surface, the user authenticates there, and your application receives an authorization code, which it exchanges for tokens. Calls to the management surface carry the resulting access token as a bearer credential. The platform validates its signature against the organization's published key set before any handler runs.
03 Getting started
Signup
Signup at https://identity.algebrix.co/signup begins with the organization identifier. Because the identifier is permanent, decide on it before you start. There are two paths:
| Path | What happens |
|---|---|
| Free | You choose an identifier and give an email address. The identifier is reserved for 24 hours and a verification email is sent. Nothing else is created until you verify. After you verify, the account and organization are provisioned and you set your password directly. No second email is sent. |
| Paid | You choose an identifier. It is reserved for 30 minutes while you complete payment details. If the reservation lapses first, the identifier returns to the pool. Nothing is created until payment details are accepted. |
Payment details are handled entirely by Stripe. Card numbers never reach Algebrix systems.
Identifier format
| Property | Value |
|---|---|
| Pattern | [a-z][a-z0-9-]{2,39} |
| Length | 3 to 40 characters |
| Case | Lowercase only. Requests using uppercase are not matched. |
| Reserved | Infrastructure hostnames, the Algebrix brand, master, and the console's own route names are refused |
| Mutability | Permanent once issued |
The identifier is embedded in the iss claim of every token the platform signs. Changing it would invalidate every token already issued and break every application configured against it. Treat it with the same permanence as a domain name.
If an organization is deleted, its identifier is never released to another account. Only the account that owned it can claim it again. This means a client still configured against the old issuer can never present credentials to a different customer.
Two behaviours to expect
Identifiers are case-sensitive. A request to /ACME-CORP/oauth2/keys returns 404, while /acme-corp/oauth2/keys succeeds. If a first attempt returns 404 on every endpoint, check the case of the identifier first.
An unknown identifier still returns a discovery document. Discovery for an organization that does not exist returns 200, because the platform does not confirm or deny which organizations exist. The endpoints inside that document return 404. If discovery succeeds but every later call fails, the identifier is misspelled.
What arrives with an organization
A new organization contains no customer applications. You create the applications you need from templates in the console (section 04).
The organization also holds one platform-managed application, which the hosted console uses to sign administrators in. It is not listed in the console, cannot be edited or deleted, and must not be used by your own applications.
Organizations created from this version onward enforce the Medium password policy and have brute-force protection off. Section 12 covers both settings.
More organizations, and deleting one
Account administrators can create further organizations from the console, up to the plan's organization allowance (section 11). At the allowance, creation is refused with a 409 that names the plan which lifts it.
Deletion is also driven from the console by an account administrator.
- It is a hard delete. The organization's users, applications, sessions, and settings are removed, and so are its audit records and sign-in activity. Its active-user figures for the current period are removed too. If you have retention obligations, export the audit log first (section 08).
- The last organization in an account cannot be deleted. To leave a paid plan, cancel the subscription instead.
04 Applications
An application is a client that signs users in, or that authenticates as itself. You create applications in the console from four templates. Each template fixes the grant, whether the application is confidential, and which addresses it accepts, so you choose a template rather than configuring raw client settings.
| Template | Type | Grant | Secret | PKCE |
|---|---|---|---|---|
| Single-page app | Public | Authorization code | None | Required, S256 only |
| Native or mobile app | Public | Authorization code | None | Required, S256 only |
| Server-side web app | Confidential | Authorization code | Yes | Optional, recommended |
| Machine-to-machine | Confidential | Client credentials | Yes | Not applicable |
Sign-in redirect URIs
The redirect URI in an authorization request must match an address registered on the application, including scheme and port.
| Template | Accepted addresses |
|---|---|
| Single-page, server-side web | https:// addresses. http:// is accepted only for localhost and 127.0.0.1, for development. |
| Native or mobile | A custom scheme such as com.example.app://callback, or a loopback address such as http://127.0.0.1:8080/callback. https:// is refused, because a native application cannot receive an https redirect. A custom scheme starts with a letter and contains only letters, digits, +, - and .. |
| Machine-to-machine | None. The application never sends anyone to a browser. |
The same rules apply to every template:
- Wildcards may appear in the path only, never in the host. For example,
https://app.example.com/*is accepted andhttps://*.example.com/cbis refused. - The value
+on its own is reserved and refused. A+inside a path is accepted. - Empty values, values containing spaces, addresses with no host, and duplicates are refused.
- A list holds at most 20 addresses.
- There is no separate post-logout list. A post-logout redirect must be one of the application's sign-in redirect URIs. Register your signed-out landing page, for example your home page, as an additional sign-in redirect URI alongside your callback.
Each refusal names the rule, for example: Sign-in redirect URIs: 'https://*.example.com/cb' is not allowed. A wildcard may only appear in the path, never in the address itself.
Allowed origins
Only single-page applications have allowed origins, which are used for cross-origin requests to the identity surface. Each origin is a bare origin with no path, such as https://app.example.com. A list holds at most 20 origins. Server-side web and machine-to-machine applications do not accept origins.
Lifecycle
- The client ID is derived from the display name at creation and is permanent. For example, "Billing Portal" becomes
billing-portal. The display name can be changed at any time; the client ID cannot. Always read the client ID from the console, not from a naming pattern. - Secrets can be revealed and rotated in the console. Rotating a secret invalidates the previous one immediately. There is no period in which both are valid. Requests made with the old secret fail with
unauthorized_clientuntil every deployment uses the new one, so plan rotation for a maintenance window. - An application can be deactivated.
- Deleting an application is permanent and ends its active sessions. The console shows the number of affected sessions before you confirm.
- Every application counts against the account's application allowance, machine-to-machine applications included (section 11).
Integration view
Each application has an integration view in the console. It shows the discovery URL, the exact issuer value to use as the authority, the client ID, and copy-ready curl and JavaScript snippets with your organization filled in. It is the quickest way to configure a client library.
In this version, creating, configuring, and deleting applications, and revealing or rotating their secrets, are console operations. There is no published API for them.
05 Authentication and tokens
Grants
| Grant | Use when | Acts as |
|---|---|---|
authorization_code | A person signs in through a browser or a native app. Used by single-page, native or mobile, and server-side web applications. | The signed-in user |
client_credentials | A backend service acts on its own behalf with no user present, and calls your own APIs. Used by machine-to-machine applications. | The application |
refresh_token | Renewing an access token without sending the user back through sign-in. | The original user |
To reach the management API, a token must be a user token carrying the admin role in realm_access.roles. The user can be signed in through any application in your organization. The management API checks the issuer, signature, expiry, and role. It does not check which application the token was issued to. Machine tokens are refused with 403.
Configuring an OIDC client library
Most libraries need only an authority and a client ID, and discover everything else. The discovery document is at:
GET https://auth.algebrix.co/{organization}/.well-known/openid-configuration
Libraries that enforce strict OpenID Connect Discovery validation compare the issuer field of that document with the authority they were configured with, and refuse to start if the two differ. Configure these libraries with the exact published issuer value, which is also shown in each application's integration view:
// issuer value, use verbatim as the authority
https://auth.algebrix.co/realms/{organization}
Libraries differ here. Some accept the path form as an authority, and others, such as openid-client and angular-auth-oidc-client, refuse it with an issuer mismatch. The exact issuer value works with every library, so use it as the authority. Discovery returns the same document from either form, and the endpoints it lists are the documented /{organization}/oauth2/… paths.
Libraries in common use
The platform works with any conformant OIDC library. There is nothing to install from Algebrix. These are widely used and actively maintained:
| Platform | Library |
|---|---|
| Angular | angular-auth-oidc-client |
| React | react-oidc-context, which wraps oidc-client-ts |
| Vue and plain JavaScript | oidc-client-ts |
| Node.js | openid-client |
| .NET | Microsoft.AspNetCore.Authentication.OpenIdConnect |
| Java and Spring | Spring Security OAuth2 Client |
| Python | Authlib |
| iOS and Android | AppAuth |
Scopes
Request openid profile email. Other scopes advertised in the discovery document are not covered by support. See the note in section 07.
Client authentication
Confidential applications authenticate at the token endpoint with client_secret_basic (HTTP Basic) or client_secret_post (credentials in the form body). Both are accepted. Keep the secret server-side and out of source control.
Token claims
Access tokens are RS256-signed JWTs. Validate them against the key set published at the keys endpoint, and never trust an unverified token. Claims relevant to integration:
| Claim | Meaning |
|---|---|
iss | Issuer, https://auth.algebrix.co/realms/{organization}. This is the only claim that identifies the organization, and the management API reads it to scope every call. |
sub | Stable, permanent identifier of the user, or of the machine application's service identity. Use it as the foreign key in your own database, never the email address or username. |
azp | The client ID of the application the token was issued to |
aud | Always account, whatever application issued the token. Do not use it to tell applications apart; use azp. |
exp, iat | Expiry and issue time, as Unix timestamps |
sid | The session the token was issued from. It matches the id returned by the sessions endpoints. |
realm_access.roles | The assigned role, alongside built-in platform roles such as offline_access, uma_authorization, and default-roles-{organization}. Check that the role you need is present; never assume the array has one entry. Machine tokens carry only the built-in roles. Management endpoints require admin here. |
preferred_username | Username. Mutable, so do not key on it. |
email | Email address. Mutable, so do not key on it. |
Validating tokens in your own API
When your service accepts Algebrix Identity tokens, it should:
- Verify the signature against the keys endpoint. Select the key by the token's
kidand accept onlyRS256signatures; the key set also contains an encryption key, which is not for signature checks. Cache the keys and refresh them when you see an unknownkid. - Verify that
issequals your organization's issuer value exactly. - Verify
exp. - If only certain applications may call your API, check
azpagainst their client IDs. Becauseaudis the same on every token, it cannot do this job.
Validate tokens locally in this way. Token introspection is not available in this version. The resource-server/node-express sample (section 06) implements these checks.
Token lifetimes
| Token | Lifetime |
|---|---|
| User access token | 300 seconds by default. Administrators can change it from 60 to 3,600 seconds in the console (section 12). |
| Machine-to-machine access token | 3,600 seconds. No refresh token is issued; request a new token when it expires. |
| Refresh token | Valid for the organization's idle sign-out period, which is 1,800 seconds by default. Each refresh restarts that period, up to the maximum session length (36,000 seconds by default), after which the user must sign in again. |
Read expires_in from the token response rather than hardcoding a duration. An administrator can change the user token lifetime at any time.
Refresh tokens are not rotated. Each refresh returns a new refresh token value, and the previous one also stays valid until the session ends or is revoked. Store the latest one. Keep refresh tokens server-side, and never in browser-accessible storage.
Sign-out is shared across the organization. When a user signs out of any application in the organization, or the session reaches its idle or maximum limit, the next refresh in every application fails with invalid_grant and Session not active. Send the user back through sign-in.
Revocation
Know what each kind of revocation does before you rely on it:
- Revoking a refresh token through
POST /oauth2/revokestops it immediately. The next refresh fails with400 invalid_grant. - Revoking an access token does not stop the management API accepting it. The API validates tokens by signature and does not query the identity server on each request. A revoked access token stays usable until its
exp. - Revoking a session (section 08) signs the user out and stops their refresh token. An access token already issued from that session stays valid until it expires, which is at most the organization's access token lifetime.
Revoke the user's sessions and disable the user. The access token lifetime is your revocation window, so keep it short if this matters to you.
06 Quickstarts
Every path starts the same way: create an application of the right type in the console, register its addresses, and copy its client ID from the integration view. These examples use the path form of the identity endpoints. Section 05 explains when to use the issuer value instead.
Sample applications
Runnable starter apps are published at github.com/algebrix/algebrix-identity-samples. They use the standard open-source OIDC libraries listed in section 05. They are not an SDK: there is nothing Algebrix-specific to install, and the code applies exactly the configuration this document describes. Each sample runs locally, uses placeholders for your organization and client ID, and states the documentation version it was tested against.
| Application type | Stack | Folder |
|---|---|---|
| Single-page app | React | spa/react |
| Single-page app | Angular | spa/angular |
| Server-side web app | Node.js, Express | server-side-web/node-express |
| Machine-to-machine | Node.js | machine-to-machine/node |
| Protecting your own API | Node.js, Express | resource-server/node-express |
Download a single sample without cloning the whole repository:
npx degit algebrix/algebrix-identity-samples/<type>/<stack> my-app
# for example
npx degit algebrix/algebrix-identity-samples/spa/react my-app
Then follow the sample's README: create the matching application in the console, register the addresses it lists, and fill in your organization and client ID. Samples for further stacks and for native applications will be listed here as they become available.
Path A: sign a user in (single-page or native app)
Create the application
Create a single-page app or a native or mobile app, and register the redirect URI your application will use, plus the page users should land on after signing out. An unregistered redirect URI is refused before the user sees a sign-in screen. The identity server shows its own error page, and no error is returned to your callback.
Send the user to the authorization endpoint
Generate a PKCE code verifier and its S256 challenge, store the verifier, then redirect:
GET https://auth.algebrix.co/{organization}/oauth2/authorize
?client_id={client_id}
&redirect_uri=https://app.example.com/callback
&response_type=code
&scope=openid profile email
&code_challenge={challenge}
&code_challenge_method=S256
&state={random_value}
Without code_challenge_method, or with plain, the request is refused with invalid_request.
Exchange the code for tokens
The user signs in, completes multi-factor authentication if required, and returns to your redirect URI with a code. Check that state matches the value you sent, then exchange the code:
POST https://auth.algebrix.co/{organization}/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id={client_id}
&code={code}
&redirect_uri=https://app.example.com/callback
&code_verifier={verifier}
Read the response
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzUxMiIs...",
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 300,
"refresh_expires_in": 1800
}
expires_in reflects the organization's configured lifetime; 300 is the default.
Sample: spa/react and spa/angular implement this path end to end, including sign-out.
Path B: sign a user in (server-side web app)
Create a server-side web app and register its redirect URI. The flow is Path A, with two differences:
- The token exchange happens on your server and authenticates with the client secret, using either HTTP Basic or
client_secretin the form body. - PKCE is optional. Using it is recommended.
curl -X POST https://auth.algebrix.co/{organization}/oauth2/token \
-u "{client_id}:{client_secret}" \
-d "grant_type=authorization_code" \
-d "code={code}" \
-d "redirect_uri=https://app.example.com/callback"
Sample: server-side-web/node-express.
Path C: authenticate a service to your own API
Create a machine-to-machine application and copy its client ID and secret from the console. No addresses need registering.
curl -X POST https://auth.algebrix.co/{organization}/oauth2/token \
-d "grant_type=client_credentials" \
-d "client_id={client_id}" \
-d "client_secret={client_secret}"
The response carries an access token with expires_in: 3600 and no refresh token. Your API validates the token as described in section 05, checking azp if it should accept only this application.
- Machine tokens are metered per calendar month against the account's allowance (section 11).
- They cannot call the management API.
- The secret must never reach a browser or a mobile binary.
Samples: machine-to-machine/node obtains and uses a machine token, and resource-server/node-express is an API that validates it.
Path D: call the management API
Sign in a user who holds admin through any application in your organization, using Path A or B. Then call the management API from server-side code with the resulting access token:
curl https://api.algebrix.co/api/admin/users?page=1&size=25 \
-H "Authorization: Bearer {access_token}"
How to read the response:
200returns one page of users in your organization, and only yours. No organization parameter is sent; the platform reads it from the token.403means the token is valid but the user does not holdadmin, or the token is a machine token.401means the token was rejected before authorization. Read theWWW-Authenticateheader for the reason.
Every administrative change is recorded under the administrator who made it, in an audit trail scoped to your organization. Because management API calls are always made as a signed-in user, each change is traceable to an individual.
07 OIDC endpoints
All paths below are relative to https://auth.algebrix.co/{organization}. The organization segment is required on every one of them.
Discovery document. Publishes the issuer, endpoint locations, supported scopes, and signing algorithms. Fetch it at startup rather than hardcoding endpoints.
Authorization endpoint. The browser redirect target that begins sign-in.
Token endpoint. Exchanges an authorization code, a refresh token, or client credentials for tokens.
Returns claims about the authenticated user. Requires a bearer access token.
JSON Web Key Set. It holds a signing key (use: sig, RS256) and an encryption key (use: enc). Verify signatures with the key matching the token's kid. Cache the keys, and refresh when you see an unknown key ID.
Ends the session. Sign-out is shared across every application in the organization. A post_logout_redirect_uri is accepted only if it is registered as one of the application's sign-in redirect URIs; otherwise the identity server shows an "Invalid redirect uri" page and does not redirect.
Revokes a refresh token so it can no longer be used. Revoking an access token does not stop the management API accepting it before it expires. See section 05.
The discovery document advertises the full capability of the underlying authorization server, which is broader than what is documented here. For example, it lists a registration endpoint, additional scopes, and additional client authentication methods. Endpoints, grants, and scopes absent from this document are not covered by support. If you need one of them, raise it with Algebrix before building against it.
08 Management API
Base URL https://api.algebrix.co. Every endpoint under /api/admin requires a user access token carrying the admin role (section 05). Every operation is scoped to the organization the token was issued for. Paths carry no organization segment, and none should be added. An identifier belonging to another organization resolves to 404, never to someone else's record.
Authorization: Bearer {access_token}
Conventions
| Topic | Behaviour |
|---|---|
| Content type | Request bodies are application/json; any other content type returns 415. File uploads are multipart/form-data with the field name file. JSON responses are application/json; charset=utf-8, and CSV downloads are text/csv. |
| Field names | Responses use camelCase. Request property names are matched case-insensitively. |
| Unknown fields | Unknown request properties and query parameters are ignored, not rejected. A misspelled field produces a success that changes nothing, so check responses rather than status codes alone. |
| Timestamps | UTC, ISO 8601, with a Z suffix. Sub-second precision varies (for example 2026-09-25T08:10:50.42Z), and session timestamps are whole seconds. Parse with a standard ISO 8601 parser rather than a fixed pattern. |
| Date filters | yyyy-MM-dd, interpreted as UTC |
| Paging | 1-based page. The page-size parameter and its limits are given per endpoint. Out-of-range values are clamped to the nearest valid value rather than refused. |
| Rate limits | None are applied to the management API or the OIDC endpoints in this version. Limits may be introduced later, so handle 429 with backoff. |
Users
Lists users. The response shape depends on whether any query parameter is sent. With no parameters, it returns a bare array of every AdminUser in the organization, unpaged. With any parameter, it returns an AdminUserPage. Use the paged form for any directory of meaningful size.
| Parameter | Type | Notes |
|---|---|---|
page | integer | 1-based, default 1 |
size | integer | Default 25, maximum 200 |
search | string | Case-insensitive substring match across username, first name, last name, and email. A term in double quotes, "david.lee", matches exactly. |
status | string | enabled, disabled, or all (the default). Any other value returns 400. |
role | string | admin, manager, or end-user. Cannot be combined with search or status; the combination returns 400. When role is sent, totalCount and totalPages are null, so paginate with hasNextPage. |
Paged results are ordered by username, ascending. There is no filter for multi-factor state; read mfaEnabled on each user instead.
Creates a user. The body is CreateUserRequest. Returns 201 with the created AdminUser. The temporary password must be changed by the user at first sign-in, and it must satisfy the organization's password policy.
Refusals:
409for a duplicate username or email.409withupgradeLifts: truewhen a plan user limit is reached (section 11).400when the identity server rejects the user, for example a username below the minimum length or a password that fails the policy.
Returns one AdminUser. The id is the sub claim of that user's tokens.
Returns UserDetail: the user, together with whether they are the organization's last administrator and which applications they have used.
Returns audit and sign-in entries concerning this user, as an AuditPage, within the retention window. Parameters: page, and pageSize (default 20). An identifier with no recorded activity returns an empty page rather than 404, and this includes an identifier that does not exist.
Updates profile fields. The body is UpdateUserRequest. Returns the updated AdminUser. The username cannot be changed.
Permanently removes the user, together with their sign-in record. Returns 204. Prefer disabling where a record of the account must survive.
Enables or disables sign-in. The body is {"enabled": boolean}. Returns the updated AdminUser. A disabled user cannot authenticate, but keeps their record, role, and multi-factor enrolment.
Assigns a role. The body is {"role": "admin" | "manager" | "end-user"}. Returns the updated AdminUser. Roles are exclusive, so assigning one replaces the previous one.
Clears the user's authenticator, for recovery when a device is lost. Returns the updated AdminUser. Returns 409 if the user has no authenticator to clear.
Clearing does not by itself make the user enrol again. They can then sign in with a password alone. Unless multi-factor enforcement applies to their role, follow the clear with a CONFIGURE_TOTP required action.
Required actions and password reset
Requires the user to complete an action at their next sign-in. The body is {"action": "UPDATE_PASSWORD" | "CONFIGURE_TOTP"}. Values are case-sensitive, and any other value returns 400. Returns 200 with {"userId": "…", "pending": ["UPDATE_PASSWORD", "CONFIGURE_TOTP"]}, listing every action the user now owes.
- Actions are additive: requiring a second action keeps the first.
- The identity server decides the order in which pending actions are shown.
- Each action clears itself once completed.
- Actions can be set on a disabled user, so you can queue a password change before enabling the account.
Emails the user a link to set a new password. There is no request body. Returns 204.
- The link is valid for 24 hours, and the previous password stops working once the new one is set.
- The email is the account-action email (section 12), not the "Forgot password?" email.
- A disabled user returns
400; enable the account first. 502means the mail relay did not accept the message, so nothing was sent.
Invitations
Inviting someone creates their user account immediately, with no password, and emails them a link to choose one. They appear in the users list from that moment. Following the link proves the email address, so the account is marked verified when they finish. An invitation's status is derived from the account: pending until the password is set, accepted after, and revoked if withdrawn. Invitation links are valid for 72 hours.
Returns a bare array of Invitation. status is pending (the default), accepted, or revoked. Capped at 100 per status.
Invites a person. The body is {"email": "…", "role": "admin" | "manager" | "end-user"}; role defaults to end-user. Returns 200 with the Invitation.
Refusals, each 400 with a message naming the cause:
- a pending invitation already exists for the address, so resend it instead;
- a user with the address already exists;
- the role is invalid.
An address whose earlier invitation was revoked can be invited again. The invitation counts against the stored-user limit (section 11).
Sends the email again to the existing account. It never creates a second account. Returns 200 with the Invitation, with lastSentAt updated.
Revokes a pending invitation. This deletes the account the invitation created, the emailed link stops working, and the stored-user allowance is released.
An accepted invitation cannot be revoked, because it is now a working account; disable or delete the user instead. An unknown id returns 404.
Import and export
Downloads a sample import file with the header username,email,firstName,lastName,role.
A dry run. It validates the uploaded file and creates nothing. Returns CsvPreview, which gives the total and valid rows, the room remaining under the stored-user limit, any shortfall, and a failure for each invalid row. The dry run does not refuse a file for exceeding the limit; the commit refuses the rows that do not fit.
Commits the file. Partial success is the defined behaviour. Valid rows are created and failed rows are reported, and the response is always 200 with CsvCommit. Each row goes through the same validation and plan limits as POST /api/admin/users. failureReportCsv holds the failed rows with an error column, ready to correct and import again.
Exports every user as CSV, with the columns username,email,firstName,lastName,role,status,mfa,createdAt. The export is designed to round-trip: the importer ignores the read-only columns. Existing users in a re-imported file are refused as duplicates rather than updated, so a round trip adds new rows only. The last sign-in time is not exported.
Import file rules
| Rule | Value |
|---|---|
| Format | RFC 4180 CSV. Quoted fields may contain commas and line breaks. |
| Columns | username, email, and role are required; firstName and lastName are optional. role must be admin, manager, or end-user. A blank or unknown role fails that row and is never defaulted. There is no password column. |
| File size | Under 1,024 KB |
| Rows | At most 500 data rows. The limit is enforced while parsing, because a quoted field can contain a line break, so counting lines in advance would miscount. Larger files are refused before any user is touched. |
| Line numbers | Failures report the file line: the header is line 1, and the first data row is line 2. |
An imported user is created with no password, owing UPDATE_PASSWORD, and with an unverified email address. No email is sent. Imported users cannot sign in until you send each of them a password reset email (POST /api/admin/users/{id}/password-reset). This version has no way to email all imported users at once. Imported users do not appear as invitations.
Sessions
Returns SessionList: every active session in the organization, capped at 500. truncated is true when the cap is reached.
Returns SessionList for one user. This list is complete.
Ends one session. Returns 204, including for a session that has already ended.
Ends every session for the user. Returns 200 with {"revoked": n}.
Revoking a session signs the user out and stops its refresh token immediately. An access token already issued from that session remains valid until it expires, which is at most the organization's access token lifetime (accessTokenLifespanSeconds in the list response). For a suspected compromise, revoke the sessions and disable the user.
Some further details:
- A session used across several applications appears once.
- Offline sessions are not included.
- A session's
idequals thesidclaim of tokens issued from it.
Branding
Returns LogoInfo for the organization's sign-in logo.
Uploads the logo as multipart field file, replacing any existing logo. Returns 200 with LogoInfo.
Rules, each refused with 400 and a message naming the limit:
- PNG or JPG only, detected from the file's contents rather than its name or declared type;
- SVG is refused, because an SVG can carry script;
- at most 512 KB;
- at most 2,000 by 2,000 pixels.
Removes the logo. Returns 200. Returns 409 if there is no logo to remove.
Returns the organization's sign-in logo image, with no authentication. If no logo is uploaded, it returns the default Algebrix mark as SVG.
An unknown identifier also returns the default mark, byte-identical, so the endpoint cannot be used to discover which organizations exist.
An uploaded logo carries ETag and Cache-Control: no-cache, must-revalidate, so a replacement shows promptly. The default mark is cacheable for 300 seconds.
The logo appears on the organization's sign-in and multi-factor enrolment pages, at a fixed height. It does not appear in emails, which carry a text header only. Colours, backgrounds, and wording are configured by Algebrix on request.
Audit log and sign-in activity
Two separate trails are kept:
- The audit log records administrative actions, such as creating a user, changing a role, rotating a secret, or changing billing.
- Sign-in activity records authentication events.
Both are kept for the plan's retention window (section 11). Each response carries retentionDays, so read the window from there rather than hardcoding it.
Returns an AuditPage of administrative actions.
| Parameter | Notes |
|---|---|
actor | Case-insensitive substring of the acting administrator's username. % and _ are matched literally. |
action | Exact action name, from the actions endpoint below |
target | Substring of the target's username |
from | Date, inclusive, UTC |
to | Date, exclusive, UTC. from=2026-09-25&to=2026-09-25 returns nothing; to include the 25th, send to=2026-09-26. This failure is silent, so it is worth getting right. |
page, pageSize | pageSize defaults to 20, maximum 100 |
Returns a bare array of every administrative action name. Use this list rather than a hardcoded catalogue, because new actions are added as the platform grows.
Downloads the audit log as CSV. It takes the same filters as the list and honours every one, so the file matches the filtered view row for row. The columns are Timestamp,ActorUsername,Action,TargetUsername,Metadata, with Metadata as a CSV-quoted JSON object.
Returns an AuditPage of sign-in activity. Filters: actor, action, from, to, with the same semantics and paging as the audit log.
- There is no outcome filter; filter by
action=LOGIN_SUCCESSoraction=LOGIN_FAILUREinstead. - Events are collected every 30 seconds (
ingestionIntervalSeconds), so a new sign-in can take up to that long to appear. This is not a live feed. - There is no CSV export for sign-in activity.
Returns the sign-in action names: LOGIN_SUCCESS, LOGIN_FAILURE, LOGOUT, MFA_ENROLLED. A failed sign-in carries the reason in metadata.error, for example invalid_user_credentials.
More about both trails:
- Every entry names the person who acted. Refused or failed operations write no entry.
- Metadata keys are camelCase.
- A user's own activity (
/api/admin/users/{id}/activity) deliberately shows both kinds together: their sign-ins alongside the actions taken on them.
Audit and session records include an ipAddress value. In this version it can record an address inside the Algebrix network rather than the originating client, so do not rely on it to identify a caller.
09 Schemas
AdminUser
{
"id": "a87a5de8-1ab3-4716-b86a-3104f3f277f2",
"username": "david.lee",
"email": "[email protected]",
"firstName": "David",
"lastName": "Lee",
"enabled": true,
"roles": ["end-user"],
"mfaEnabled": false,
"createdAt": "2026-09-18T08:15:54.42Z",
"lastSignInAt": "2026-09-19T11:02:10.503Z"
}
| Field | Notes |
|---|---|
id | Stable and permanent. Equal to the sub claim. |
roles | An array holding the user's single role |
mfaEnabled | Whether a TOTP authenticator is enrolled |
lastSignInAt | The most recent successful sign-in, or null. It is kept independently of audit retention. null does not mean "never signed in": it means no sign-in has been recorded since sign-in tracking began for the organization. |
AdminUserPage
{
"items": [ /* AdminUser */ ],
"page": 1,
"size": 25,
"totalCount": 312, // null when filtered by role
"totalPages": 13, // null when filtered by role
"hasNextPage": true,
"signInHistoryDays": 90 // the per-user activity window
}
CreateUserRequest
| Field | Type | Notes |
|---|---|---|
username | string | Required. The sign-in identifier. It cannot be changed later. |
email | string | Required |
firstName | string | |
lastName | string | |
temporaryPassword | string | Required. Must satisfy the organization's password policy, and must be changed by the user at first sign-in. |
A new user holds no role until one is assigned with PUT /api/admin/users/{id}/role.
UpdateUserRequest
| Field | Type | Notes |
|---|---|---|
email | string | Required |
firstName | string | Optional |
lastName | string | Optional |
UserDetail
{
"user": { /* AdminUser */ },
"isLastAdministrator": false,
"signInHistoryDays": 90,
"applicationsInUse": ["billing-portal", "mobile-app"]
}
applicationsInUse lists client IDs. Check isLastAdministrator before disabling, deleting, or changing the role of an administrator, so the organization is not left without one.
Invitation
{
"id": "7a5a5053-8d98-4909-bde7-d4e3e3dddc10",
"email": "[email protected]",
"role": "end-user",
"status": "pending",
"invitedBy": "[email protected]",
"createdAt": "2026-09-25T08:18:18.7939597Z",
"lastSentAt": "2026-09-25T08:18:18.7939601Z",
"acceptedAt": null,
"revokedAt": null,
"emailDelivered": true
}
SessionList
{
"sessions": [
{
"id": "w9rZQFadZ0Zyqo8_t7PJsLq_",
"userId": "a87a5de8-1ab3-4716-b86a-3104f3f277f2",
"username": "david.lee",
"ipAddress": "203.0.113.10",
"startedAt": "2026-09-25T08:16:14Z",
"lastAccessAt": "2026-09-25T08:16:14Z",
"applications": ["billing-portal"]
}
],
"accessTokenLifespanSeconds": 300,
"truncated": false
}
applications lists client IDs.
AuditPage
This shape is returned by the audit log, sign-in activity, and per-user activity endpoints.
{
"items": [
{
"id": "cd147816-…",
"timestamp": "2026-09-25T08:21:11.764Z",
"actorUserId": "a87a5de8-…",
"actorUsername": "david.lee",
"action": "LOGIN_FAILURE",
"targetUserId": null,
"targetUsername": null,
"metadata": { "error": "invalid_user_credentials" }
}
],
"totalCount": 15,
"page": 1,
"pageSize": 20,
"totalPages": 1,
"retentionDays": 90,
"ingestionIntervalSeconds": 30 // 0 on the administrative log, written synchronously
}
CsvPreview
{
"fileName": "users.csv",
"totalRows": 4,
"validRows": 3,
"remainingStoredUsers": 9992,
"shortfall": null,
"failures": [
{ "line": 3, "username": "g.two", "email": "not-an-email", "firstName": "G",
"lastName": "Two", "role": "end-user", "reason": "'not-an-email' is not a valid email address." }
],
"failureReportCsv": null
}
CsvCommit
{
"fileName": "users.csv",
"totalRows": 3,
"created": 2,
"failed": 1,
"failures": [ /* as in CsvPreview */ ],
"failureReportCsv": "username,email,firstName,lastName,role,error\r\n…"
}
LogoInfo
{
"hasLogo": true,
"contentType": "image/png",
"width": 240,
"height": 80,
"byteSize": 296,
"updatedAt": "2026-09-25T08:33:17.5027867Z"
}
10 Errors
Response bodies differ by failure type. Handle every shape below rather than assuming a single envelope, and branch on the status code and on the machine-readable fields, not on message text. Messages are written for people and may be reworded.
| Status | Meaning | Body |
|---|---|---|
200, 201, 204 | Success | The documented resource, or empty for 204 |
400 | Invalid input, or a business rule refused the request | A message body, or a validation Problem Details object for malformed input |
401 | Missing, expired, or otherwise invalid token | Empty. The reason is in the WWW-Authenticate header. |
402 | Administrative write blocked because the subscription is unpaid | message and billingState |
403 | Valid token without the required privilege: no admin role, a machine token, or an account-level operation | Empty, with no WWW-Authenticate header. The status code is the signal. |
404 | No such resource in your organization | A message body, or a Problem Details object. An unrouted path returns an empty body. |
409 | Conflict: a duplicate, nothing to remove, or a plan limit reached | A message body. upgradeLifts is true for plan limits. |
415 | The request body is not application/json | Problem Details |
429 | Too many requests | Empty. Not applied to the management API in this version; handle it anyway. |
500 | Unexpected server-side failure | Quote the traceId, if present, when contacting support |
502 | An email could not be handed to the mail relay, so nothing was sent | A message body |
Message body
This shape is used for business-rule refusals with 400, 404, 409, and 502:
{
"message": "Your plan (Free) includes 3 applications and you have 3. Starter includes 10.",
"upgradeLifts": true
}
upgradeLifts is true only when moving to a higher plan removes the refusal, and false for every other refusal. Use it to decide whether to route a person to upgrading.
Validation Problem Details
This shape is returned for malformed input, such as an invalid email format, a missing required field, a missing upload, or malformed JSON:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": { "Email": ["The Email field is not a valid e-mail address."] },
"traceId": "00-cdb2562e8941de77...-86ee0d1ec5ff51e3-00"
}
404 Not Found
Most not-found responses use the message body, for example {"message": "User not found.", "upgradeLifts": false}. GET /api/admin/users/{id} returns an RFC 9457 Problem Details object instead:
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
"title": "Not Found",
"status": 404,
"traceId": "00-df7c6aa7...-00"
}
Handle both shapes by status code.
401 Unauthorized
The body is empty. The diagnostic is in the response header, per RFC 6750:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token",
error_description="The issuer '...' is invalid"
With no token at all, the header is simply Bearer. An empty body here is expected behaviour, not a fault.
402 Payment Required
{
"message": "A payment failed and the grace period has ended, so administrative changes are paused. Update your payment details in Billing to resume, or contact [email protected].",
"billingState": "grace_expired"
}
billingState is one of trial_failed, grace_expired, or canceled. See section 11.
Diagnosing a failed call
| Symptom | Likely cause |
|---|---|
404 on every identity endpoint | Uppercase characters in the organization identifier, or a misspelling |
Discovery returns 200, everything else 404 | The organization identifier does not exist |
404 on /{organization}/protocol/openid-connect/… | Under the organization prefix, the endpoints are /{organization}/oauth2/…. See section 07. |
| Library refuses to start, with an issuer mismatch | The authority is configured with the path form instead of the published issuer value. See section 05. |
| Sign-in shows an error page reading "Invalid parameter: redirect_uri" and never returns to the callback | The redirect URI is not registered on the application, or does not match it exactly. Nothing is sent to the unregistered address. |
| Sign-out shows "Invalid redirect uri" | The post_logout_redirect_uri is not registered as a sign-in redirect URI. There is no separate post-logout list. |
invalid_request: "Missing parameter: code_challenge_method" or "code challenge method is not matching the configured one" | A single-page or native application sent no PKCE challenge, or sent plain. Use S256. |
401 unauthorized_client on the token endpoint | Wrong client secret, or a secret that has since been rotated |
401 invalid_client on the token endpoint | The client ID does not exist in this organization |
login_required, with no description, on a prompt=none request | The user has no active session. Send them through interactive sign-in. |
Refresh fails with invalid_grant, "Session not active" | The session ended: idle sign-out, maximum session length, or sign-out from any application in the organization |
400 on the token endpoint | The redirect URI differs from the one used at authorization, or the PKCE verifier does not match the challenge |
401 with an issuer message | The token was not issued by Algebrix Identity, or its organization is not recognised |
403 on /api/admin | The user does not hold admin, or the token is a machine-to-machine token. Machine tokens cannot call the management API. |
403 on an account-level route | Organizations, billing, and usage are console-only for account administrators |
404 on a user you know exists | The user belongs to a different organization than the token. Operations never cross organizations. |
401 on the token endpoint for a machine application, while others work | The account's monthly machine token allowance is exhausted and machine token issuance is paused. See section 11. |
409 with upgradeLifts: true | A plan limit has been reached |
402 on a write that used to succeed | The subscription is unpaid. Reads still work. |
| A request succeeds but changes nothing | A misspelled field. Unknown fields are ignored, not rejected. |
| Audit query returns nothing for today | to is exclusive. Send the following day. |
| Password refused at the set-password page although it looks strong | The organization's password policy requires a rule the password misses. The page lists every rule. |
| Correct password refused after several failures | Brute-force protection has locked the account temporarily. An administrator can unlock it from the console. |
| Users are unexpectedly prompted to enrol an authenticator | Multi-factor enforcement was turned on for their role |
11 Plans, limits, and billing
Allowances belong to the account and are shared across all of its organizations. Current usage against every allowance is shown in the console.
| Free | Starter | Growth | Scale | |
|---|---|---|---|---|
| Organizations | 2 | 5 | 25 | 50 |
| Applications (all types) | 3 | 10 | 50 | 100 |
| Machine-to-machine tokens per calendar month | 500 | 2,000 | 5,000 | 15,000 |
| Monthly active users | 10,000 | 25,000 | 50,000 | 100,000 |
| Console administrators | 1 | 3 | 10 | 25 |
| SSO connections | 3 | 5 | 10 | 25 |
| Audit and sign-in retention | 7 days | 30 days | 90 days | 365 days |
Scale is a negotiated plan: its figures are included amounts, not ceilings, and never block.
How each allowance is measured and enforced
| Allowance | Behaviour |
|---|---|
| Organizations | Creation is refused at the allowance with 409, upgradeLifts: true. |
| Applications | Every customer application counts, machine-to-machine included. The platform-managed console application does not. Creation is refused at the allowance with 409. |
| Monthly active users | Distinct users who signed in during the current calendar month. Machine applications are excluded.
|
| Stored users (Free) | Free organizations can hold up to 10,000 users in the directory. At that limit, creating, inviting, or importing a user is refused with 409, naming the plan that lifts the limit. Invitations and imported users count, because they create directory users. |
| Machine-to-machine tokens | Tokens issued through the client credentials grant in the calendar month. A warning is shown at 80% of the allowance, and the account is emailed at 100%.
|
| Console administrators, SSO connections | Published allowances. They are not enforced at creation in this version. Enterprise SSO is set up with Algebrix assistance. |
| Retention | Audit and sign-in activity records older than the window are removed. Aggregated sign-in statistics are kept, so usage figures are unaffected, and lastSignInAt is not bounded by the window. Organizations on an invoiced agreement retain records for 45 days. If you have compliance retention requirements, export within your window. Read retentionDays from the audit responses rather than relying on this table. |
Plan changes
Plan changes are made in the console by an account administrator. You can move between paid plans and switch between monthly and annual billing.
- A downgrade is refused if current usage exceeds the target plan, and the refusal names the dimension.
- Moving from a paid plan to Free is not possible. Cancelling is the exit from a paid plan.
Billing restrictions
If a subscription goes unpaid, administrative changes are paused. Nothing else is. Understand this before you build, because it determines what your integration can and cannot do in that state.
Your users keep signing in. Token issuance and every OIDC endpoint are unaffected in every unpaid state. No token is revoked and no session is ended. A billing problem is never allowed to take down authentication for people who have no idea one exists.
Reads keep working. Every GET under /api/admin continues to return data, so you can still list users and export the audit log.
What pauses is every write under /api/admin: creating, updating, disabling, or deleting users; roles and required actions; password reset emails; invitations; CSV import, including the dry run; session revocation; logo changes; and clearing multi-factor enrolment. Each returns 402. Writes resume automatically, within about a minute of a successful payment.
- The restriction is account-wide. One unpaid subscription pauses writes in every organization of the account.
- A trial that ends without a successful payment restricts writes immediately, reported as
trial_failed. - When an established subscription's payment fails, there is a seven-day grace period from the first failure, during which everything works normally. After that, it is reported as
grace_expired. Retries do not extend the grace period. - A cancelled subscription is reported as
canceled. - Organizations on an invoiced agreement, including Enterprise, are billed separately and are never restricted.
Administrators see the current state, and the date on which access will be restricted, in the console. If your operations team monitors integrations rather than the console, treat a 402 as the signal to check billing.
12 Security settings and the end-user experience
Administrators configure these settings per organization in the console. Changes take effect immediately and are recorded in the audit log. They are not available through the API in this version, but they change what your users and your integration experience, so they are documented here.
Password policy
| Rule | Weak | Medium | Strong |
|---|---|---|---|
| Minimum length | 8 | 10 | 12 |
| Upper case, lower case, digit | Not required | 1 of each | 1 of each |
| Special character | Not required | Not required | 1 |
| Must differ from the username | Yes | Yes | Yes |
| Cannot repeat recent passwords | No | Last 3 | Last 5 |
| Expiry | None | None | None |
- New organizations use Medium. Organizations created before this default was introduced have no password policy until an administrator selects one, and the console says so.
- A policy applies when a password is next set or changed. Existing passwords are not re-checked, and nobody is forced to change theirs.
- Rules beyond the three levels, such as a longer minimum or a blocklist, are configured by Algebrix on request.
Brute-force protection
Brute-force protection is off by default. When it is on, an account is locked temporarily after a number of consecutive failed sign-ins, and while it is locked even the correct password is refused. Each further failure doubles the lockout, up to the maximum. Administrators see locked accounts in the console and can unlock them. The list can lag by up to 30 seconds.
| Setting | Range | Default when first enabled |
|---|---|---|
| Failures before lockout | 3 to 100 | 30 |
| First lockout | 10 to 3,600 seconds | 60 seconds |
| Maximum lockout | 60 to 86,400 seconds | 900 seconds |
| Permanent lockout | On or off | Off |
Session and token lifetimes
| Setting | Range | Default |
|---|---|---|
| Access token lifetime | 60 to 3,600 seconds | 300 seconds |
| Idle sign-out | 300 to 2,592,000 seconds | 1,800 seconds |
| Maximum session length | 600 to 2,592,000 seconds | 36,000 seconds |
Some constraints link these settings:
- The maximum session length cannot be shorter than the idle sign-out.
- An access token never outlives its session.
- The access token lifetime is also how long a revoked session's last access token remains usable, which is why it is capped at one hour.
Multi-factor authentication
| Enforcement | Effect |
|---|---|
| Off (default) | No one is required to enrol |
| Administrators | Every user holding admin must enrol a TOTP authenticator at their next sign-in |
| Everyone | Every user must enrol at their next sign-in |
- Turning enforcement off does not remove anyone's authenticator.
- Enforcement is independent of the per-user
CONFIGURE_TOTPrequired action, which works in every mode. - A TOTP code is single-use. The code used to enrol cannot also be used to sign in within the same 30-second window, which can look like a failed sign-in during testing.
Self-registration
Self-registration is off by default. When it is on, a Register link appears on the organization's sign-in page, and people who register count towards the plan's user allowances. Email verification can be required for people who register. Invited people already prove their address by following the emailed link.
What your users see
- Sign-in and enrolment pages carry the organization's logo, if one is uploaded.
- There is no end-user account page.
https://auth.algebrix.co/realms/{organization}/accountreturns404. Users change their password through the "Forgot password?" link, a password reset email, or anUPDATE_PASSWORDrequired action. - Users enrol an authenticator only when enforcement or a
CONFIGURE_TOTPrequired action asks them to. They cannot enrol or remove one on their own initiative; an administrator clears an authenticator for recovery. Managing your own authenticator in Account settings is available to account administrators only. - The set-password page lists the organization's rules before the person types.
- A dead, expired, or revoked link shows a plain message asking for a new link. A mistyped password at sign-in shows the same message.
- After setting a password, the person sees a Back to the application link. It goes to one of the organization's applications that has a concrete, non-wildcard redirect URI registered. Without one, it goes to the organization's console address, which a non-administrator cannot use. Register at least one concrete redirect URI so that invited and reset users land in your application.
- A person invited with an email address only is asked for their name before finishing. They are not signed in automatically; they sign in afterwards.
Emails your users receive
| Sent when | Subject | |
|---|---|---|
| Password reset | The user chooses "Forgot password?" | Reset your password |
| Account action | An administrator sends a password reset or an invitation, or the user owes an action | Action needed on your account |
| Email verification | Verification is required | Confirm your email address |
- The sender name is the organization's display name, from
[email protected], with replies going to[email protected]. - Every body names the organization, but subjects cannot include it, which is a platform constraint.
- The set-password email includes the full sign-in address for the user's organization and their username, as they will type it.
- Emails carry no remote images.
- Signup verification and account administrator emails are sent by Algebrix Identity and do not name an organization.
13 Scope and behaviour
What the platform does and does not do, stated plainly so that evaluation does not turn up surprises.
Not available in this version
| Capability | Status |
|---|---|
| Machine-to-machine access to the management API | Not available. Call the management API as a signed-in administrator. |
| API management of applications, organizations, billing, and authentication settings | Console only |
| SAML federation to a corporate IdP | On the roadmap |
| SCIM provisioning | Not available. Use the management API or CSV import. |
| Token exchange, RFC 8693 | On the roadmap. Not supported for integration. |
| Dynamic client registration, RFC 7591 | Not supported, although the discovery document lists a registration endpoint. Create applications in the console. |
| Passkeys and WebAuthn | Not available. Multi-factor authentication is TOTP only. |
| End-user self-service account page | Not available |
| Token introspection, RFC 7662 | Not available, although the discovery document lists the endpoint. Validate tokens locally against the keys endpoint (section 05). |
| Refresh token rotation | Not enabled |
| Overlapping client secrets during rotation | Not available. Rotation takes effect immediately. |
| Platform SDKs | None. Use the standard OIDC libraries in section 05, or start from a sample application (section 06). |
| Forced password expiry, or forcing a reset after a policy change | Not offered |
| Sign-in activity export | Not available. The audit log exports. |
| Filtering users by multi-factor state | Not available |
| Emailing many users at once | Not available |
| Self-service branding beyond the logo | Colours, backgrounds, and wording are configured by Algebrix on request |
| Webhooks, API keys, directory sync | On the roadmap |
| Enterprise SSO, custom domains | Available with Algebrix assistance |
Operational notes
- HTTPS only. Plaintext HTTP is not served on any endpoint.
- Organizations share nothing. Users, credentials, sessions, roles, signing keys, and audit records belong to exactly one organization.
- User identifiers are stable. The
idfield and thesubclaim are the same value and never change. Usernames and email addresses can change, so do not key on them. - Client IDs are permanent. Display names can change.
- Disable rather than delete where the audit trail must keep resolving an account. User deletion is permanent, and there is no undelete.
- Deleting an application ends its sessions. Deleting an organization destroys its audit trail, so export first.
- Authentication is never gated on billing or on machine token allowances. User sign-in continues in every subscription and quota state.
- Sign-in activity arrives within 30 seconds, not in real time.
Standards implemented
OAuth 2.0 (RFC 6749), Bearer Token Usage (RFC 6750), PKCE (RFC 7636), Token Revocation (RFC 7009), JSON Web Token (RFC 7519), OpenID Connect Core 1.0, and OpenID Connect Discovery 1.0. The authorization core is Apache-2.0 licensed and standards-conformant. No proprietary protocol extension is required for integration, and there is no lock-in at the protocol layer.
Versioning and support
API paths carry no version segment, and this document is versioned instead. Version 2.1 describes the platform as of September 2026. Changes that would break an existing integration are published as a new major version of this document; minor versions add guidance and clarifications.
Version 2.1 adds the sample applications and clarifies secret rotation, post-logout redirects, the roles claim, refresh token behaviour, signing key selection, and common error responses. Token introspection is no longer listed as available.
For support, write to [email protected]. For a specific failed call, include the traceId where one is returned.