Integrating an External Identity Provider with Monosign Multi-Factor Authentication

Audience: Integration engineers and solution architects connecting a third-party Identity Provider (IdP) to Monosign

Applies to: Monosign v2026.09 and later (code-entry mode for the API Service Authenticator: v2026.10 and later)


Purpose

This guide explains how an external Identity Provider can use Monosign as its multi-factor authentication (MFA) service. The Identity Provider keeps ownership of the sign-in experience and the final access decision; Monosign verifies the user's second factor and reports the outcome through its REST API.

Two verification modes are supported:

Mode

How the user confirms

Typical use

Approval request (default)

The user approves or rejects a request on the registered authenticator (Monofor Identity push notification, or the external service behind the API Service Authenticator).

Interactive sign-in where the user has the device at hand.

Code entry (disablePushRequest)

No request is sent to the device. The user reads a one-time code from the authenticator application and enters it in the Identity Provider's sign-in page.

Environments where push delivery is not possible or not desired, such as restricted networks or devices without notification access.

The integration can be built in one of two variants, depending on where the user's password is validated:

Variant

Password validated by

Monosign session

Described in

A — With a Monosign session

Monosign (step 1)

Opened by the login call and sent in every MFA call

Steps 1–4

B — Without a Monosign session

The Identity Provider itself, or not required

Not needed; the MFA calls carry isPasswordless: true

Variant B — Without a Monosign Session

Both verification modes are available in both variants.


Prerequisites

Before starting the integration, confirm the following:

  1. Application registration. The Identity Provider is registered as an application in Monosign, and its App ID and App Key are available. Every API call carries them in the Monosign-AppId and Monosign-AppKey headers.

  2. API permissions. The application's API key is granted the permissions listed in the table below.

  3. User readiness. The user exists in Monosign and has at least one enrolled, enabled authenticator (for example Monofor Identity or API Service Authenticator).

  4. Base URL. The Monosign API base URL of the target environment, referred to below as {ApiUrl}.

Permission

Required for

System.API.Users.Login

Step 1 — primary sign-in

System.API.MFA.Options

Step 2 — listing the user's authenticators

System.API.MFA.CreateAuthenticationRequest

Steps 3 and 4 — creating requests, checking their status, submitting Monofor Identity codes

System.API.MFA.Verify

Submitting codes through v1.3/mfa/verify — required for the API Service Authenticator in code-entry mode, optional otherwise

Security note: The App Key is a credential. Store it in the Identity Provider's secret store, never in client-side code, and rotate it according to your organisation's policy.

Conventions

  • Request bodies are JSON (Content-Type: application/json). Field names are case-insensitive; this guide uses camelCase.

  • All fields not marked Required are optional. Omitted fields take the default shown.

  • Unknown fields are ignored, so sending an optional field to an older release does not cause an error.


Integration Flow at a Glance (Variant A)

Step

Identity Provider calls

Monosign returns

Keep for later

1

POST {ApiUrl}/v1.4/users/login

User and session identifiers

UserId, SessionId

2

GET {ApiUrl}/v1.3/mfa/options/{UserId}

The user's active authenticators

UserAuthenticatorId

3

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}

A final result, or a pending transaction

UsageId

4

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}/{UsageId}

The current result (repeated until final)

—

From step 2 onwards, every call includes the Monosign-SessionId header with the SessionId returned in step 1.


Step 1 — Establish the User Session

The Identity Provider validates the user's primary credentials against Monosign. Monosign opens a session for the user and returns the identifiers required for the MFA steps.

The client details sent in this call are stored on the session. The Monofor Identity approval request shows them to the user (IP address, browser, device type and location derived from the IP), so the Identity Provider should forward the end user's details rather than its own.

Request

POST {ApiUrl}/v1.4/users/login
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Content-Type: application/json

{
  "userName": "jane.doe",
  "password": "{Password}",
  "isPasswordEncrypted": false,
  "permanent": false,
  "userIp": "203.0.113.24",
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
  "browserName": "Chrome",
  "browserVersion": "129.0",
  "operatingSystem": "Windows",
  "operatingSystemVersion": "11",
  "deviceType": 1,
  "culture": "en"
}

Body fields

Field

Type

Default

Description

userName

string

—

Required. The user's Monosign user name.

password

string

—

Required. The user's password.

isPasswordEncrypted

boolean

false

true when password is encrypted with the Monosign client encryption. Monosign decrypts it before validation; a value that cannot be decrypted is rejected.

permanent

boolean

false

Session lifetime. false uses the application's Session Timeout; true uses its Max Session Timeout.

userIp

string

—

IP address of the end user. Stored on the session and shown in the approval request. Recommended.

userAgent

string

—

User agent of the end user's browser or client. Stored on the session.

browserName, browserVersion

string

—

Browser of the end user. Shown in the approval request.

operatingSystem, operatingSystemVersion

string

—

Operating system of the end user. Stored on the session.

deviceType

integer

0

Device category of the end user: 1 = Computer, 2 = Mobile. Shown in the approval request.

deviceName, deviceBrand, deviceModel

string

—

Device details. Stored on the session.

culture

string

—

Preferred language, for example en or tr. Saved as the user's language when none is set and the language is enabled.

includeProfile

boolean

false

true adds the user's profile attributes to the response.

Successful response — code 10188

JSON
{
  "Message": "Login successful.",
  "Code": 10188,
  "Success": true,
  "Data": {
    "UserId": "9ca71310-eddf-4976-b684-f9204fd62b74",
    "Session": { "SessionId": "a7bc6ea0-360b-49fe-84b8-f3a31cb44cc3" }
  }
}

Retain Data.UserId and Data.Session.SessionId.


Step 2 — Select the User's Authenticator

The Identity Provider retrieves the user's active authenticators and selects the one to use for this sign-in. This call has no request body.

Request

GET {ApiUrl}/v1.3/mfa/options/{UserId}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Monosign-SessionId: {SessionId}

Path parameter

Description

UserId

Required. Data.UserId from step 1.

The same list is also available by user name: GET {ApiUrl}/v1.3/mfa/options/by-username/{UserName}.

Successful response — code 10131

JSON
{
  "Message": "There are active authenticators for this user.",
  "Code": 10131,
  "Success": true,
  "Data": [
    { "Id": "b47d6b96-2adc-412b-b6c8-f70eb2017eca", "Name": "Service", "Title": "API Service Authenticator" },
    { "Id": "5d0f3c1e-7a42-4b8e-9f61-2c4d8e0a9b17", "Name": "Mobile",  "Title": "Monofor Identity" }
  ]
}

Select the entry by its Name, which is stable across languages and tenants. Title is a display label and may be customised.

Name

Authenticator

Mobile

Monofor Identity

Service

API Service Authenticator

The selected entry's Id is the UserAuthenticatorId used in steps 3 and 4. If the response code is 10130, the user has no active authenticator; the Identity Provider should direct the user to enrolment rather than continue.


Step 3 — Create the Verification Request

The Identity Provider creates a verification transaction for the selected authenticator. The body is optional; an empty body ({}) starts a standard approval request.

Request — approval mode (default)

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Monosign-SessionId: {SessionId}
Content-Type: application/json

{
  "deviceName": "Corporate VPN",
  "expiresInMinutes": 3
}

Request — code-entry mode

JSON
{
  "disablePushRequest": true,
  "expiresInMinutes": 3
}

Path parameter

Description

UserAuthenticatorId

Required. Id of the authenticator selected in step 2.

Body fields

Field

Type

Default

Applies to

Description

disablePushRequest

boolean

false

Monofor Identity, API Service Authenticator

true selects code-entry mode: nothing is sent to the device and the call returns immediately. See Code-Entry Mode.

disableResponseWait

boolean

false

Monofor Identity, API Service Authenticator

true returns as soon as the request is sent, without the five-second wait for the user's answer. The response carries UsageId; continue with step 4.

expiresInMinutes

integer

Authenticator's configured lifetime; 3 if none

All

Validity of this transaction in minutes. After expiry, status checks return 10114.

deviceName

string

—

Monofor Identity

Shown in the approval request after the application name, for example "Access Portal - Corporate VPN". Use it to tell the user which system is asking.

Note: The end user's IP address, browser and device details are taken from the session created in step 1, not from this call. Send them in the login request.

Responses in approval mode

After the request is created, Monosign holds the call open for approximately five seconds while the user responds (unless disableResponseWait is true).

Outcome

HTTP status

Code

Identity Provider action

User approved

200

10117

Grant access.

User rejected

200

10118

Deny access.

No answer yet

499

499

Retain Data.UsageId and continue with step 4.

Request sent, no wait (disableResponseWait)

200

10124 (API Service Authenticator) or the delivery result code (Monofor Identity)

Retain Data.UsageId and continue with step 4.

Pending response example

JSON
{
  "Message": "Warning",
  "Code": 499,
  "Success": false,
  "Data": {
    "UsageId": "a76dc5ea-0981-4068-b67f-53be6666905c",
    "IsInteractive": true,
    "IsCompleted": false
  }
}

Implementation note: HTTP status 499 is not an error. HTTP clients that raise exceptions for non-2xx responses must be configured to read the response body for this status.


Step 4 — Retrieve the Result

While the transaction is pending, the Identity Provider queries its status using the UsageId from step 3. The body may be empty ({}).

Request

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}/{UsageId}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Monosign-SessionId: {SessionId}
Content-Type: application/json

{}

Path parameter

Description

UserAuthenticatorId

Required. The same value used in step 3.

UsageId

Required. Data.UsageId returned in step 3.

Body fields

Field

Type

Default

Description

code

string

—

One-time code entered by the user. When present, Monosign verifies the code instead of returning the status. Used in code-entry mode with Monofor Identity.

Each status call waits up to about five seconds and returns one of the outcomes below. The Identity Provider repeats the call while it receives 499, until a final outcome is returned or the transaction expires.

Outcome

Code

Identity Provider action

Approved

10117

Grant access.

Rejected

10118

Deny access.

Still pending

499

Call again.

Expired

10114

Deny access, or start a new request from step 3.

Cancelled

10291

Deny access.

Failed

10298

Deny access; see the Troubleshooting section.

Because each call already waits up to five seconds on the server, no additional client-side delay is required between calls. Requests are rate-limited per transaction; a single sequential polling loop stays well within the limit.


Variant B — Without a Monosign Session

Use this variant when the Identity Provider validates the user's password itself (for example against its own directory) and needs Monosign only for the second factor. The login call is skipped, and no Monosign-SessionId header is sent. Instead, every MFA call carries "isPasswordless": true, and Monosign identifies the user from the UserAuthenticatorId.

Responsibility: In this variant Monosign does not verify the user's password. The Identity Provider must complete its own primary authentication before starting the MFA request.

Flow

Step

Identity Provider calls

Body

Keep for later

B1

GET {ApiUrl}/v1.3/mfa/options/by-username/{UserName}

—

UserAuthenticatorId

B2

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}

isPasswordless: true plus the end user's client details

UsageId

B3

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}/{UsageId}

isPasswordless: true (and code in code-entry mode)

—

All calls carry only the Monosign-AppId and Monosign-AppKey headers.

B1 — Select the user's authenticator

GET {ApiUrl}/v1.3/mfa/options/by-username/{UserName}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}

The response and the selection rule are identical to step 2. When the user is known by its Monosign ID, GET {ApiUrl}/v1.3/mfa/options/{UserId} can be used instead. If user names are not unique across user sources, add ?source={UserSourceName}. Code 10129 means the user was not found.

B2 — Create the verification request

Because there is no login call, the end user's client details are sent here. Monosign records them for the request and shows them in the approval request.

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Content-Type: application/json

{
  "isPasswordless": true,
  "userIp": "203.0.113.24",
  "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...",
  "deviceType": 1,
  "operatingSystem": "Windows",
  "operatingSystemVersion": "11",
  "deviceName": "Corporate VPN"
}

Body fields — in addition to those of step 3

Field

Type

Default

Description

isPasswordless

boolean

false

Required in this variant. true allows the call without a Monosign session.

userId

GUID

—

Optional safeguard. When sent, Monosign rejects the call if the authenticator belongs to a different user.

userIp

string

—

IP address of the end user. Recorded and shown in the approval request. Recommended.

userAgent

string

—

User agent of the end user's browser or client.

deviceType

integer

0

1 = Computer, 2 = Mobile.

operatingSystem, operatingSystemVersion

string

—

Operating system of the end user.

disablePushRequest, disableResponseWait, expiresInMinutes and deviceName work exactly as in step 3, and the responses are the same: 10117, 10118, 499 with UsageId, or 10120 in code-entry mode.

B3 — Retrieve the result or submit the code

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}/{UsageId}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Content-Type: application/json

{
  "isPasswordless": true
}

Repeat while the response is 499, as in step 4. In code-entry mode with Monofor Identity, add "code": "{Code entered by the user}". For the API Service Authenticator in code-entry mode, submit the code to v1.3/mfa/verify as described in Code-Entry Mode; that endpoint does not require a session.

Important: isPasswordless: true must be sent on every call of this variant. Without it, and without a Monosign-SessionId header, Monosign rejects the call because no session is present.

Session created by Monosign

To track the request, Monosign opens a session for the user in the Identity Provider's application. On approval (10117), its identifier is returned in Data.SessionId. The Identity Provider may ignore it; it expires according to the application's Session Timeout.


Code-Entry Mode (disablePushRequest)

In code-entry mode, Monosign creates the verification transaction but sends nothing to the user's device. The user obtains a one-time code from the authenticator application and enters it in the Identity Provider's sign-in page, and the Identity Provider submits that code to Monosign.

When to use it

  • The user's device cannot receive push notifications (no connectivity, notification access disabled, restricted network).

  • The organisation's policy requires the user to type a code rather than approve a prompt.

  • The Identity Provider offers the user an "Enter a code instead" option on its MFA page.

Behaviour by authenticator

Authenticator

Effect of disablePushRequest: true

Where the user finds the code

Available from

Monofor Identity (Mobile)

No push notification is sent.

One-time code shown in the Monofor Identity app.

v2026.09

API Service Authenticator (Service)

Monosign does not call the external service's Request endpoint.

The external service's own application. The code is checked through the service's Validation endpoint, or locally when Validate OTP First is enabled on the authenticator.

v2026.10

Other authenticators

The field is ignored and the authenticator behaves as usual.

—

—

1. Create the transaction

Call step 3 with "disablePushRequest": true. Monosign responds immediately with code 10120:

JSON
{
  "Message": "No need to create an action. Just type the code from your Identity app.",
  "Code": 10120,
  "Success": true,
  "Data": {
    "UsageId": "e3b9a7d2-4f1c-4c6b-8a0e-71d2f5c9b384",
    "ExpirationDate": "2026-10-20T13:05:00"
  }
}

Retain Data.UsageId. ExpirationDate is in UTC; the user must enter the code before this time.

2a. Submit the code — Monofor Identity

Send the code to the status endpoint from step 4:

POST {ApiUrl}/v1.3/mfa/request/{UserAuthenticatorId}/{UsageId}
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Monosign-SessionId: {SessionId}
Content-Type: application/json

{
  "code": "482913"
}

2b. Submit the code — API Service Authenticator

The code is passed to the external service through the input fields designed on the authenticator (Service Settings → Input Requirement). Submit it to the verification endpoint, keyed by the input field name:

POST {ApiUrl}/v1.3/mfa/verify
Monosign-AppId: {AppId}
Monosign-AppKey: {AppKey}
Monosign-SessionId: {SessionId}
Content-Type: application/json

{
  "userId": "9ca71310-eddf-4976-b684-f9204fd62b74",
  "userAuthenticatorId": "b47d6b96-2adc-412b-b6c8-f70eb2017eca",
  "userAuthenticatorUsageId": "e3b9a7d2-4f1c-4c6b-8a0e-71d2f5c9b384",
  "payload": {
    "Form": { "otp": "482913" }
  }
}

When Validate OTP First is enabled on the authenticator, also send the code in code; Monosign checks it locally first and calls the external service only if the local check fails.

Body fields — v1.3/mfa/verify

Field

Type

Description

userId

GUID

Required. Data.UserId from step 1.

userAuthenticatorId

GUID

Required. Id of the authenticator selected in step 2.

userAuthenticatorUsageId

GUID

Required. Data.UsageId from the create call.

code

string

One-time code entered by the user. Required for Monofor Identity; for the API Service Authenticator, used only when Validate OTP First is enabled.

payload.Form

object

API Service Authenticator only. Values of the authenticator's input fields, keyed by field name (in the example, otp). At least one field must carry a value.

Results

Outcome

Code

Identity Provider action

Code accepted

10117

Grant access.

Code incorrect

10136

Ask the user to re-enter the code.

Transaction expired

10114

Start a new request.

Transaction already used

10290

Start a new request.

External service rejected the code

10298

Deny access, or start a new request.

Limitation for the API Service Authenticator

Code-entry mode is not available when the external service's validation depends on an identifier that only its Request call returns (an Identifier Path is configured under Request Settings). In that case Monosign rejects the create call with HTTP 400 and code 10300, and the Identity Provider should fall back to approval mode for that authenticator.


Response Code Reference

Code

Meaning

Final?

10188

Primary sign-in succeeded

—

10131

Active authenticators listed

—

10129

User not found (authenticator list)

Yes

10130

User has no active authenticator

Yes

10117

Verification succeeded

Yes

10118

User rejected the request

Yes

499

Waiting for the user (HTTP 499)

No

10124

Request sent without waiting (disableResponseWait)

No

10120

Code-entry transaction created; awaiting code

No

10136

Code incorrect

No — user may retry

10114

Transaction expired

Yes

10290

Transaction already processed

Yes

10291

Transaction cancelled

Yes

10298

Transaction failed or errored

Yes

10112

Transaction not found

Yes

10113

Transaction does not belong to this user, authenticator or session

Yes

10299

External service rejected or could not process the request (API Service Authenticator)

Yes

10300

Code-entry mode not supported by this service configuration

Yes

Integrations built against releases earlier than v2026.10 may have handled 10116 for external service failures. From v2026.10 this condition returns 10299; accept both during the transition.


  • Treat every non-final result as "not authenticated". Grant access only on 10117.

  • Bind the flow to one session (Variant A). Use the same SessionId for steps 2–4. Monosign rejects status checks made with a different session (10113).

  • Forward the end user's details. Send userIp, userAgent and deviceType in step 1 (Variant A) or step B2 (Variant B) so that the approval request and the audit trail show the user's real origin, not the Identity Provider's server.

  • Name the requesting system. Use deviceName in step 3 so that users can recognise legitimate requests.

  • Offer a fallback. When approval mode stays pending, consider offering the user code-entry mode in the same sign-in page instead of restarting the flow.

  • Do not log secrets. Exclude the App Key, passwords and one-time codes from Identity Provider logs.


Troubleshooting

Symptom

Likely cause

Resolution

10130 in step 2

The user has no enrolled or enabled authenticator.

Enrol the user, or verify that the authenticator is enabled under Security → Authenticators.

HTTP 403 on any call

The application's API key lacks a required permission.

Grant the permissions listed under Prerequisites.

Status checks return 10113

A different session or authenticator ID is used than in step 3.

Reuse the SessionId from step 1 and the UserAuthenticatorId from step 3.

Status checks keep returning 499 until 10114

The user did not respond in time, or the push notification did not reach the device.

Ask the user to check device connectivity, or offer code-entry mode.

The approval request shows the Identity Provider's IP address

The login request did not carry the end user's details.

Send userIp and the browser fields in step 1.

10299 with the API Service Authenticator

The external service returned an error or a response that did not match the configured validation.

Review the user's audit entries and use Test on the authenticator to reproduce the call.

Variant B calls are rejected with HTTP 400

isPasswordless: true is missing from the body, so Monosign expects a session.

Send "isPasswordless": true on every MFA call of Variant B.

10300 with disablePushRequest

The external service requires its Request call for validation.

Use approval mode for this authenticator.

API Service Authenticator code is never accepted in code-entry mode

The code was sent in code without Validate OTP First, or under a field name that does not match the authenticator's input field.

Send it in payload.Form under the input field's exact name.