Push Notification Authentication

A push notification displayed on a mobile device.

Push notification authentication uses device credentials to securely authenticate users through their mobile devices. This method leverages public key cryptography where private keys are securely stored on the user’s device.
This method uses the Device SDK to sign a challenge with the user’s device credentials.Device enrollment required: Users must have a device that they can use to complete the challenge. This can be done by adding device credentials via our mobile SDK.

Sequence diagram

Configure push notification auth in Authsignal Portal

Enable the Device credential authentication method for your tenant and configure a push notification webhook.

Grab your Authsignal credentials

Head to Settings and grab your Tenant ID, API URL and API secret key. Add them as environment variables in your project:
AUTHSIGNAL_API_URL=your_region_api_url
AUTHSIGNAL_TENANT_ID=your_tenant_id
AUTHSIGNAL_SECRET_KEY=your_secret_key

Implementation

1. Backend – Track an action

When a user performs an action that requires authentication, your backend should track the action. You can use our Server SDK or Server API to track the action. The code snippets in this guide references the SDKs.
import { Authsignal } from "@authsignal/node";

const authsignal = new Authsignal({
  apiSecretKey: process.env.AUTHSIGNAL_SECRET_KEY,
});

// Track the sign-in action
const trackResponse = await authsignal.track({
  userId: "dc58c6dc-a1fd-4a4f-8e2f-846636dd4833",
  action: "signIn",
});

// Handle different action outcomes
if (trackResponse.state === "CHALLENGE_REQUIRED") {
  // User needs to complete Push challenge
  return { token: trackResponse.token };
} else if (trackResponse.state === "ALLOW") {
  // Proceed with the action - no challenge needed
  return { success: true };
} else if (trackResponse.state === "BLOCK") {
  // Block the action for security reasons
  return { error: "Action blocked for security reasons" };
}
Understanding action statesWhen you track an action, Authsignal returns one of four possible states:
  • CHALLENGE_REQUIRED - User must complete an authentication challenge (proceed to step 2)
  • ALLOW - Action is permitted without additional authentication
  • BLOCK - Action is blocked for security reasons
  • REVIEW - Action requires manual review
Learn more about action outcomes.

2. Frontend – Challenge the user

Use our Browser SDK or Client API to initiate a push challenge. This will trigger the push notification to be sent via the configured settings.

Start a push challenge

import { Authsignal } from '@authsignal/browser';

const authsignal = new Authsignal({
  tenantId: 'YOUR_TENANT_ID',
});

// Set the token from the track response
authsignal.setToken(token);

// Send the push challenge
const challengeResponse = await authsignal.push.challenge();

Poll for the challenge result

Poll for the challenge result using our Browser SDK or Client API. We recommend polling every 1-2 seconds.
// Poll for the challenge result
const verifyResponse = await authsignal.push.verify({ 
  challengeId: challengeResponse.data.challengeId 
});

// Get the verification token to validate on your backend
if (verifyResponse.data?.isVerified) {
  const verificationToken = verifyResponse.data.token;
}
Poll states:
1

Declined

isConsumed is true, isVerified is falseThe challenge has been declined by a user. Show an error message to the user and provide a way to retry the challenge.
{
  "isConsumed": true,
  "isVerified": false
}
2

Verified

isConsumed is true, isVerified is true and an accessToken is returned.The challenge has been verified by a user. Show a success message to the user and proceed with the next step.
{
  "isConsumed": true,
  "isVerified": true,
  "accessToken": "access_token"
}
Note this model assumes push notification delivery is not guaranteed or required. I.e., Even if a push notification is not delivered, it is recommended that you present a message to the user on your frontend to inform them that the challenge has been initiated and to open their mobile app.

3. Mobile – Present challenge

When the app is foregrounded, use the mobile sdk getChallenge method to check if there is a challenge. If there is a challenge, present a dialog to allow the user to approve or decline the challenge.
let response = await authsignal.device.getChallenge()

if let error = result.error {
    // The credential stored on the device is invalid
} else if let challenge = result.data {
    // A pending challenge request is available
    // Present the user with a prompt to approve or deny the request
    let challengeId = challenge.challengeId
} else {
    // No pending challenge request
}
To approve or decline the challenge, use the mobile SDK’s updateChallenge method.
await authsignal.device.updateChallenge(
    challengeId: challengeId,
    approved: true
)

4. Backend – Validate the challenge

Once the challenge is approved, the challenge verify api being polled in step 2 will return a token that should be passed to your backend to validate the challenge prior to completing the authentication flow.
const request = {
  token: "eyJhbGciOiJ...",
};

const response = await authsignal.validateChallenge(request);

if (response.state === "CHALLENGE_SUCCEEDED") {
  // The user completed the challenge successfully
  // Proceed with authenticated action or integrate with IdP to create authenticated session
} else {
  // The user did not complete the challenge successfully
}
If the challenge is declined, the api will return isConsumed as true and isVerified as false. The UI should be updated to reflect that the challenge was declined. You’ve successfully implemented device credential authentication with Authsignal using push notifications!

Next steps

  • Adaptive MFA - Set up smart rules to trigger authentication based on risk
  • QR code - Implement QR code authentication
  • Trusted device - Implement trusted device authentication
  • Passkeys - Offer the most secure and user-friendly passwordless authentication