Mailbox API – Authentication and Authorization

Axigen Documentation

Updated: Jul 31, 2026

The Axigen Mailbox API requires every request to be made in the context of an authenticated session. This page describes the ways a client can obtain a session, how to carry it on subsequent requests, and the additional steps that may be required before a session becomes usable.

Auth Methods

The Axigen Mailbox API supports the following authentication and authorization methods:

Method

Axigen's role

Best for

Availability

Axigen OAuth 2.0

Authorization server – Axigen issues the tokens

First party mobile and native apps that must stay signed in across restarts

10.7+

External OAuth 2.0 with OpenID Connect

Resource server – Axigen validates tokens issued by your identity provider

Deployments with a central identity provider; browser based applications and mobile / native apps

All versions

Cookie Authentication

Authenticates the user directly

Browser based clients

All versions

Basic Authentication

Authenticates the user directly

Scripts and server to server integrations, and any case where no OAuth 2.0 provider is available

All versions

Note that using an OAuth 2.0 flow is strongly recommended as it is the most secure option. It avoids handling user passwords in your application and gives you revocable, short lived credentials.

Choosing a Method

  • If your deployment already has an external identity provider, use External OAuth 2.0 with OpenID Connect. Your application obtains a token from the provider and Axigen validates it.

  • If there is no external provider and you are building a mobile or native app that should keep the user signed in, use Axigen OAuth 2.0. Axigen itself issues an access and refresh token pair.

  • Use Cookie Authentication for browser based clients, and Basic Authentication only when neither OAuth option is available.

Sessions

Every method ends with a session identifier (sessid). Each subsequent request must carry two things: the session identifier, and the credential the session was created with.

The session identifier travels in the X-Axigen-Session header, whichever login endpoint produced it:

The credential depends on how the session was created, and is not interchangeable:

Session obtained via

Repeat on every request

POST /api/v1/login (Basic or Bearer)

The same Authorization header used at login

POST /api/v1/login/cookie

The _hmail cookie

POST /api/v1/session (Axigen OAuth 2.0)

The _hmail cookie

A request that presents the session identifier but omits the credential is rejected as an expired session. A cookie backed session used from a client that does not store cookies will therefore appear to expire on the first call after login.

Behind the webmail proxy, the session identifier is returned with a 32 character backend routing suffix appended. Send the value exactly as received – only the leading 32 characters are used.

2-Step Verification and Captcha

2-Step Verification and Captcha are supported in the following scenarios:

Method

2-Step Verification

Captcha

Axigen OAuth 2.0

Handled during the session login that precedes the authorization code request

Handled during the session login that precedes the authorization code request

External OAuth 2.0 with OpenID Connect

If enabled by the Authorization Server

If enabled by the Authorization Server

Cookie Authentication

Supported

Supported

Basic Authentication

Not supported

Not supported

Login

Request Headers

Name

Required

Values

Description

Authorization

*

"Basic <username>:<password>", "Bearer <token>"

“Basic” – used to authenticate against internal user authentication mechanism when OAuth 2.0 and OpenID Connect are not available

“Bearer” – used to authenticate against an external authentication provider (such as OAuth 2.0 and OpenID Connect)

Response

When successful, the endpoint returns the following JSON structure:

All subsequent API calls must use the same authentication method and include the session ID in the X-Axigen-Session header.

Important: If you start with Basic Auth, all subsequent API calls must also include the same Basic Auth header.

Note that when using bearer token authorization, the username is unknown to Axigen until the token is validated against the external authentication provider.

In case the user can't be authenticated (i.e. wrong authentication credentials, invalid token, expired token, unknown user), the endpoint will respond with 401 Unauthorized.

Cookie Login

Request body (JSON)

Name

Type

Required

Values

Description

username

String

*

The username including the domain name when the user does not belong to the primary domain or no primary domain is set

password

String

*

The account password

captchaText

String

The value of the captcha text

captchaId

String

The captcha id

rememberLogin

Boolean

The value set based on user choice

Response

When successful, the endpoint returns the following JSON structure:

Additionally, the response will also include the following headers when applicable:

Name

Type

Present

Values

Description

Set-Cookie

String

*

The _hmail Cookie to be used in all subsequent requests

X-Axigen-2FA

String

required, mandatory

The value is set to required when the a second step is required as part of the 2-Step Verification

The value is set to mandatory when setting up 2-Step Verification must be performed before continuing

All subsequent API calls must send the _hmail cookie and include the session ID in the X-Axigen-Session header.

In case the user can not be authenticated (i.e. wrong authentication credentials, invalid captcha, unknown user), the endpoint will reply back with 401 Unauthorized.

Cookie Login with 2-Step Verification

When 2-Step Verification is administratively enabled and active (i.e. the Cookie Login endpoint includes a X-Axigen-2FA header set to required), the API client must use this endpoint to complete the 2-Step Verification.

The API client should call the List Account Security Methods endpoint with scope=2fa to obtain the list of available methods. When using either an email or sms method, a totpToken must be obtained by calling Send Token.

Alternatively, a recoveryCode can be used to complete the 2-Step Verification. Recovery codes are generated automatically when activating the 2-Step Verification. They can also be regenerated by calling Regenerate Recovery Codes.

Request body (JSON)

Name

Type

Required

Values

Description

methodId

String

*

The id of the 2-Step Verification method being used

totpToken

String

*

The TOTP code

recoveryCode

String

*

One of the recovery codes received when activating 2-Step Verification or after manually regenerating the recovery codes.

Either of methodId and totpToken or recoveryCode is required.

Response

If successful, the response will be empty.

Password Expiration 10.7+

Applies starting with Axigen X7 (10.7)

When logging in with a password that has expired (i.e. the login endpoint includes a X-Axigen-Expired-Password header set to true), the API client must use the password reset endpoint in order to change the password before doing anything else. They can check the password policy details using the account info endpoint. This happens after the 2-Step Verification, if it is configured.

Captcha

This API is only available when using cookie login.

Get Status

Query parameters

Name

Type

Required

Values

Description

username

String

*

The username (including the domain name) for which the captcha requirement should be checked.

Response

When successful, the endpoint returns the following JSON structure:

Get Captcha

Query parameters

Name

Type

Required

Values

Description

username

String

*

The username (including the domain name) for which the captcha requirement should be checked.

t

String

Typically set to the current timestamp. This is used to work around browser level caching of the captcha image.

Response

When successful, the endpoint returns the captcha image as PNG in case captcha is required.

Additionally, the response will also include the following headers when applicable:

Name

Type

Present

Values

Description

X-Captcha-Id

String

*

The captcha id to be sent when calling cookie login.

Axigen OAuth 2.0 10.7+

Applies starting with Axigen X7 (10.7)

Axigen can act as its own OAuth 2.0 authorization server, issuing access and refresh tokens for registered first party clients. This lets an application keep a user signed in without storing their password and without an external identity provider.

The flow differs from a classic third party OAuth 2.0 authorization: rather than redirecting the user to a consent screen, the client starts from an already authenticated session and exchanges it for a durable token pair. Use one of the session login methods described above to obtain that initial session.

The exchange is one way. POST /api/v1/login/code consumes the session it is called from – the session is discarded and its cookie expired as the authorization code is issued. Plan for the client to hold tokens from that point on, and to obtain any further session from POST /api/v1/session.

Flow Overview

  1. Sign the user in with a session login method to obtain a session.

  2. Call POST /api/v1/login/code from that session to obtain a short lived authorization code. This ends the session.

  3. Exchange the code for an access and refresh token pair at POST /api/v1/auth/token. No session is required for this call.

  4. Call POST /api/v1/session with the access token to obtain a session.

  5. When the access token expires, obtain a fresh pair at POST /api/v1/auth/token using the refresh token, then repeat step 4.

  6. On logout, revoke the refresh token with POST /api/v1/auth/revoke.

A 401 on an ordinary API call means the session expired, not that the user must sign in again – obtain a new session at step 4. Only refresh token expiry or revocation requires a full sign in.

PKCE

Every authorization code is bound to a PKCE verifier (RFC 7636). Before requesting a code, generate a random code_verifier of 43 to 128 characters from [A-Za-z0-9-._~] and derive the challenge as BASE64URL(SHA256(code_verifier)). Send the challenge to /api/v1/login/code and the original verifier to /api/v1/auth/token.

Only the S256 method is supported. plain is rejected.

Token Lifetimes

Item

Lifetime

Notes

Authorization code

10 minutes

Single use. Only one code may be pending per account – issuing a new one invalidates the previous.

Access token

15 minutes

Stateless and multi use. Verified by signature alone.

Refresh token

30 days

Single use; rotated on every refresh.

Signing keys

60 days

The three most recent periods (previous, current and next) are accepted at any time.

Access and refresh tokens are also rejected if they were issued at or before the account's last password change or last session invalidation, regardless of their remaining lifetime.

Registered Clients

clientId

redirectUri

com.axigen.app

axigen://auth

Client registration is static. The redirectUri presented on a request must match the registered value for that clientId exactly.

Request an Authorization Code

Requires an authenticated session. Consumes it.

Request body (JSON)

Name

Type

Required

Values

Description

clientId

String

*

Currently only com.axigen.app is registered

The OAuth 2.0 client id

redirectUri

String

*

Currently only axigen://auth is registered

The OAuth 2.0 redirect uri. Must exactly match the registered URI for the given clientId

codeChallenge

String

*

The PKCE code challenge, BASE64URL(SHA256(code_verifier))

codeChallengeMethod

String

*

Must be S256

The PKCE code challenge method. Only S256 is accepted

state

String

*

An opaque value used to correlate the request with the redirect. Verify it on return

Response

When successful, the endpoint returns the following JSON structure:

The redirect URL is the registered redirectUri with the authorization code and your state appended as percent encoded query parameters, for example axigen://auth?code=<code>&state=<state>. Confirm the returned state matches the one you sent before using the code.

The response also expires the _hmail session cookie.

Errors

Status

Condition

401 Unauthorized

No valid session

403 Forbidden

Unknown clientId, or redirectUri does not match the registered value

501 Not Implemented

codeChallengeMethod is not S256

This endpoint returns the standard Mailbox API error envelope, not the OAuth 2.0 error format used by the endpoints below.

Exchange the Code for Tokens

Public endpoint – no session or prior authentication required. The request body must be application/x-www-form-urlencoded; any other content type is rejected.

Request body (application/x-www-form-urlencoded)

Name

Type

Required

Values

Description

grant_type

String

*

Must be authorization_code

The OAuth 2.0 grant type

code

String

*

The authorization code from the /api/v1/login/code redirect

code_verifier

String

*

43–128 characters from [A-Za-z0-9-._~]

The original PKCE verifier whose SHA-256 hash was sent as codeChallenge

client_id

String

If present, must match the value stored at /api/v1/login/code

Optional. When present it is validated; a mismatch is an error

redirect_uri

String

If present, must match the value stored at /api/v1/login/code

Optional. When present it is validated; a mismatch is an error

Response

When successful, the endpoint returns the following JSON structure:

Responses carry Cache-Control: no-store.

Refresh the Token Pair

Public endpoint. Same endpoint as the code exchange, distinguished by grant_type.

Request body (application/x-www-form-urlencoded)

Name

Type

Required

Values

Description

grant_type

String

*

Must be refresh_token

The OAuth 2.0 grant type

refresh_token

String

*

A valid refresh JWT

Response

Identical in shape to the code exchange response.

Refresh tokens are rotated: each refresh returns a new pair and invalidates the token presented. Persist the new refresh token before using it, and discard the old one.

Presenting a refresh token that has already been rotated is treated as a compromise: the entire rotation family is revoked, and every token descended from that original sign in stops working. The user must sign in again. Clients should therefore serialise refresh calls and never retry a refresh with a token whose replacement has already been stored.

Open a Session

Exchanges a valid access token for a Mailbox API session. No request body.

Request Headers

Name

Required

Values

Description

Authorization

*

Bearer <JWTAccessToken>

An access token previously issued by /api/v1/auth/token

This endpoint is Bearer only. A request that also carries an _hmail session cookie is rejected rather than resolved in favour of one credential.

Response

When successful, the endpoint returns the following JSON structure:

Additionally, the response will also include the following header

Name

Type

Present

Description

Set-Cookie

String

*

The _hmail cookie, valid for 30 days. Required on all subsequent requests

All subsequent API calls must send the _hmail cookie and include the session ID in the X-Axigen-Session header.

Sessions created this way are treated as having completed 2-Step Verification – it was completed during the sign in that produced the authorization code.

Errors

401 Unauthorized with a WWW-Authenticate: Bearer header and an OAuth 2.0 error body. error is invalid_token when the token is missing, malformed, unverifiable, refers to an unknown user, or predates a password change or session invalidation; invalid_request when a session cookie is present; server_error when session creation fails.

Revoke a Refresh Token

Public endpoint, per RFC 7009. Call this on logout. The request body must be application/x-www-form-urlencoded.

Request body (application/x-www-form-urlencoded)

Name

Type

Required

Description

token

String

*

The refresh token to revoke. Revokes the entire rotation family

Response

If successful, the response will be empty, with 200 OK.

Per RFC 7009 the endpoint also returns 200 for tokens that are invalid, expired, or unknown, so a success response is not confirmation that a token existed. Only a missing token parameter (400) or a storage failure (500) return a non-200 status.

Verify Token Signatures

Public endpoint. Returns the public keys used to verify Axigen issued tokens, allowing a client or resource server to check them offline.

Response

When successful, the endpoint returns the following JSON structure:

Keys are derived per 60 day period, and the set covers the previous, current and next period. Cache the key set and refetch it when a token presents an unknown kid. Tokens without a kid, or with a kid outside the accepted set, are rejected.

Error Responses

/api/v1/auth/token and /api/v1/auth/revoke return RFC 6749 error bodies rather than the standard Mailbox API error envelope:

error

Meaning

invalid_request

Wrong content type, or a required parameter is missing

invalid_grant

The code, verifier, or refresh token was rejected – invalid, expired, replayed, revoked, or mismatched against the values recorded at authorization time

unsupported_grant_type

grant_type is neither authorization_code nor refresh_token

server_error

Internal failure

invalid_grant is deliberately undifferentiated: the specific reason is logged server side but not returned, to avoid aiding enumeration.