Push Enrollment Flow

Here is the sequence diagram displays the flow of when a user tries to login with push notification or faces with Push MFA.

sequenceDiagram participant User participant Authenticator App participant PlusAuth User-->>+PlusAuth: signin alt User does not have push credentials PlusAuth->>User: (1) Displays QRCode User->>+Authenticator App: Scans QrCode Authenticator App->>-PlusAuth: (2) \[POST] /push-authenticator/enroll User->>PlusAuth: Clicks to continue end PlusAuth-->>Authenticator App: (3) Send Push Notification to all registered devices alt type = "code" Authenticator App-->>User: Display numbers to choose from User->>Authenticator App: Selects number Authenticator App->>PlusAuth: (4) \[POST] /push-authenticator/resolve else type = "prompt" Authenticator App-->>User: Prompt user to accept/reject User->>Authenticator App: Answers prompt Authenticator App->>PlusAuth: (4) \[POST] /push-authenticator/resolve end PlusAuth-->>-User: signin success

Flow Steps

1) QRCode contents

QRCode is composed of an uri consisting several parameters. For offline validation, push enrollment also behaves as TOTP authenticator.

Other than TOTP parameters, QRCode uri would contain context_token and enrollment_url field.

Here is an example:

otpauth://push/MyApp:[email protected]?issuer=MyApp&secret=SOMESECRET&algorithm=SHA256&digits=6&period=30&context_token=SOME_TOKEN&enrollment_url=https%3A%2F%2Fmytenant.plusauth.com%2Fpush-authenticator%2Fenroll

2) Enrollment Request

After QRCode is scanned, authenticator application should enroll the user to PlusAuth.

For enrollment Authenticator application must satisfy these requirements:

  • A JWK KeyPair for validation of context signature
  • Have a unique device identifier (Usually generated in first installation)
  • Is registered to push service (gcm or apns)

Here is the enrollment request:

Public and private key must be in JWK format.
curl --request POST \
  --url 'https://{{TENANT_ID}}.plusauth.com/push-authenticator/enroll' \
  --header 'User-Agent: {{USER_AGENT}}' \
  --header 'Authorization: Bearer {{CONTEXT_TOKEN}}' \
  --header 'Content-Type: application/json' \
  --data '{
  "public_key": {  },
  "private_key": {  },
  "device_identifier": "{{UNIQUE_DEVICE_ID}}",
  "credentials": {
    "service": "fcm",
    "device_token": "{{FIREBASE_TOKEN}}"

3) Push Notification Content

Push Notifications sent by PlusAuth will have an empty title and content but in its payload there will be a context field. The context value is a JWT signed with the private key provided in the enrollment request.

Before checking the contents of the JWT make sure you have verified signature with the public key on your device.

Here is an example of the attributes inside JWT:

Nested json values can be empty or null. For example, in some cases settings.bind_sim, info.agent or info.agent.device can be undefined or null. Make sure you check the existence of the key before you try to access them
Common Properties
  "exp": 1702250257,
  "iat": 1702243057,
  "context_token": "CONTEXT_TOKEN",
  "resolve_url": "https://mytenant.plusauth.com/push-authenticator/resolve",
  "settings": {
    "bind_sim": false
  "info": {
    "application": "Application Name",
    "ip": "",
    "user_identifier": "[email protected]", // Could be phone number or username or any other user property
    "agent": {
      "ua": "",
      "browser": {
        "name": "",
        "version": "",
        "major": ""
      "cpu": {
        "architecture": ""
      "device": {
        "type": "",
        "vendor": "",
        "model": ""
      "engine": {
        "name": "",
        "version": ""
      "os": {
        "name": "",
        "version": ""
    "location": {
      "city": "Istanbul", // English city name
      "country": "TUR", // Country ISO Code
      "postal_code": "34000", // Postal code of location
      "coordinates": {
        "accuracy_radius": 1,
        "latitude": 41.091384,
        "longitude": 29.062315,
        // The time zone associated with location, as specified by the IANA Time Zone Database
        "time_zone": "Europe/Istanbul"


If settings object contains bind_sim value and it is set to true the authenticator application should prevent receiving push notification or generating otp code if end-user's SIM card changes.

You can use fields details.is_sim_bound and details.sim_card_identifiers per-account in account scheme. See related api docs from Accounts / Save Account

4) Resolving Push Interaction

After user interacts with push notification (answers prompt or selects code), authenticator application must inform PlusAuth with the interaction result.

To do so, application must create a JWT signed with private key and with corresponding claim containing the action response.

Your JWT must contain following claims depending on the push notification type:

Common values
   // If user rejects interaction
  "reject_reason": "ignore", // or "fraud_suspicion"

Here is the responding request:

curl --request POST \
  --url 'https://{{TENANT_ID}}.plusauth.com/push-authenticator/resolve-challenge' \
  --header 'User-Agent: {{USER_AGENT}}' \
  --header 'Authorization: Bearer {{CONTEXT_TOKEN}}' \
  --header 'Content-Type: application/json' \
  --data '{
  "context": "{{GENERATED_JWT}}",
  "device_identifier": "{{UNIQUE_DEVICE_ID}}"