Identity Verification

Authenticate External User IDs, SMS, and emails sent to OneSignal.

Overview

OneSignal supports an enhanced security feature called Identity Verification, which helps prevent user impersonation. This method uses JSON Web Tokens (JWTs), which are securely generated on your server and passed to your app and our API to verify user identities. We highly recommend enabling identity verification for:

  • Logging in users via OneSignal Mobile SDK
  • Adding emails
  • Adding SMS subscriptions
  • Modifying Aliases

Setting Up Identity Verification

1. Create a Key Pair

Log in to your OneSignal account and navigate to Settings > Keys & IDs.

Identity Verification configuration

Identity Verification configuration

Click Generate New Keys to create a new key pair.

Creating new key pair

Creating new key pair

Download the PEM file or copy the private key, making sure to store the private key securely.

Identity Verification key pair

Identity Verification key pair

📘

Security Tip

Always store your private keys in a secure environment, such as a key management system. Never expose private keys in your front-end code or version control systems.

2. Generate JWT on Your Backend

Identity verification requires authenticating the end-user with your authentication server before logging them into OneSignal. When the end-user authenticates with your backend, generate the OneSignal JWT and include it in the auth response to the device. If your app doesn’t run on its own backend servers, consider setting up a lightweight server dedicated to verifying users and generating OneSignal JWTs. We recommend a JWT Library to sign your JWTs.

Signing the JWT

The JWT must be signed using the ES256 algorithm. Ensure your backend is configured to use this signing method to avoid verification issues when sending the JWT to OneSignal.

Example using the ES256 signing algorithm:

import jwt from 'jsonwebtoken';

function signOneSignalIdentityVerificationJWT(appId, externalId, subscriptions) {
  return jwt.sign({
    iss: appId,
    exp: Math.floor(Date.now() / 1000) + 3600, // 1-hour expiration
    identity: {
      'external_id': externalId,
    },
    subscriptions
  },
  	process.env['ONESIGNAL_IDENTITY_VERIFICATION_SECRET_KEY'],
    { algorithm: 'ES256' });
}

const onesignalJWT = signOneSignalIdentityVerificationJWT('APP_ID', 'EXTERNAL_ID');

Remember that the private key used for signing JWT is generated in the OneSignal dashboard.

OneSignal JWT Payload

PropertyRequiredDescription
issYour Onesignal App ID.
expThe token expiration date.
identityThe user's alias.
subscriptionsOptional; required only when adding Email and SMS subscriptions to a user.

Handling Subscriptions

If you need to manage email and SMS subscriptions, you need to pass the subscriptions, which can be modified in the JWT payload. If you know all this information up-front, you can include it when authenticating the user. Otherwise, you'll need to send the emails and phone numbers from the front end of your app and respond with the proper JWT on-demand or create the records using out REST API.

Example: Generating JWT to add subscriptions

const subscriptions = [
  {
      "type": "Email",
      "token": "[email protected]"
  },
  {
      "type": "SMS",
      "token": "+12345678"
  }
]
const onesignalJWT = signOneSignalIdentityVerificationJWT('APP_ID', 'EXTERNAL_ID', subscriptions)

3. Pass JWT to OneSignal Login Method

Once your backend generates the JWT, pass it to the OneSignal SDK when logging in the user via the login method. The JWT ensures the user’s identity is verified before any changes, such as adding an email or SMS subscription, can be made.

Example of logging in:

// The External ID comes from your backend
String externalId = "123456789";

// The JWT is generated on your backend using the authenticated user's
// External ID or any other custom aliases you may have set.
String onesignalJWT = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3OGUzMjA4Mi1lYTI3LTQyZTMtYTg5OC1jNzJlMTQxODI0ZWEiLCJleHAiOjE2NTc3NzU4NzIsImlkZW50aXR5Ijp7ImFsaWFzX2xhYmVsX2V4YW1wbGUiOiJhbGlhc19pZF9leGFtcGxlIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoidGVzdEBkb21haW4uY29tIn0seyJ0eXBlIjoiU01TIiwidG9rZW4iOiIrMTIzNDU2NzgifV19._iazvUy6krturWicV1eXqPzptzIB8y_GmvDXfFp6OXNxiLvI2wRkWS5iH_gJWPmyZc48KLpJXgR2RT6Jn8_5Aw"

OneSignal.login(externalId, onesignalJWT);

// The External ID comes from your backend
val externalId = "123456789" 

// The JWT is generated on your backend using the authenticated user's
// External ID or any other custom aliases you may have set.
val onesignalJWT = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3OGUzMjA4Mi1lYTI3LTQyZTMtYTg5OC1jNzJlMTQxODI0ZWEiLCJleHAiOjE2NTc3NzU4NzIsImlkZW50aXR5Ijp7ImFsaWFzX2xhYmVsX2V4YW1wbGUiOiJhbGlhc19pZF9leGFtcGxlIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoidGVzdEBkb21haW4uY29tIn0seyJ0eXBlIjoiU01TIiwidG9rZW4iOiIrMTIzNDU2NzgifV19._iazvUy6krturWicV1eXqPzptzIB8y_GmvDXfFp6OXNxiLvI2wRkWS5iH_gJWPmyZc48KLpJXgR2RT6Jn8_5Aw"

OneSignal.login(externalId, onesignalJWT)

// The External ID comes from your backend
let externalId = "123456789"

// The JWT is generated on your backend using the authenticated user's
// External ID or any other custom aliases you may have set.
let onesignalJWT = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3OGUzMjA4Mi1lYTI3LTQyZTMtYTg5OC1jNzJlMTQxODI0ZWEiLCJleHAiOjE2NTc3NzU4NzIsImlkZW50aXR5Ijp7ImFsaWFzX2xhYmVsX2V4YW1wbGUiOiJhbGlhc19pZF9leGFtcGxlIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoidGVzdEBkb21haW4uY29tIn0seyJ0eXBlIjoiU01TIiwidG9rZW4iOiIrMTIzNDU2NzgifV19._iazvUy6krturWicV1eXqPzptzIB8y_GmvDXfFp6OXNxiLvI2wRkWS5iH_gJWPmyZc48KLpJXgR2RT6Jn8_5Aw"

OneSignal.login(externalId, onesignalJWT)

// The External ID comes from your backend
NSString* externalId = @"123456789";
  
// The JWT is generated on your backend using the authenticated user's
// External ID or any other custom aliases you may have set.
NSString* onesignalJWT = @"eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI3OGUzMjA4Mi1lYTI3LTQyZTMtYTg5OC1jNzJlMTQxODI0ZWEiLCJleHAiOjE2NTc3NzU4NzIsImlkZW50aXR5Ijp7ImFsaWFzX2xhYmVsX2V4YW1wbGUiOiJhbGlhc19pZF9leGFtcGxlIn0sInN1YnNjcmlwdGlvbnMiOlt7InR5cGUiOiJFbWFpbCIsInRva2VuIjoidGVzdEBkb21haW4uY29tIn0seyJ0eXBlIjoiU01TIiwidG9rZW4iOiIrMTIzNDU2NzgifV19._iazvUy6krturWicV1eXqPzptzIB8y_GmvDXfFp6OXNxiLvI2wRkWS5iH_gJWPmyZc48KLpJXgR2RT6Jn8_5Aw";

OneSignal.login(externalId, onesignalJWT);
  

Example of adding an email:

OneSignal.getUser().addEmail(emailAddress);

OneSignal.getUser().addEmail(emailAddress)

OneSignal.getUser().addEmail(emailAddress)

[OneSignal addEmail:emailAddress];

Example of adding an SMS subscription:

OneSignal.getUser().addSms(smsNumber);

OneSignal.getUser().addSms(smsNumber)

OneSignal.getUser().addSms(smsNumber)

[OneSignal addSms:smsNumber];

4. Handle JWT Lifecycle Events

You’ll need to implement a dedicated endpoint on your backend to handle scenarios like token invalidation. This endpoint should provide a refreshed JWT when OneSignal requests an update.

Example of handling token invalidation and refreshing the JWT:

OneSignal.addUserJwtInvalidatedListner(event -> {
  // Get the current user's Extenral ID
  String externalId = event.getExternalId();  
  
  // Fetch a new JWT from your backend for the current user
  String onesignalJWT = "";
  
  // Provide the new JWT to the SDK
  OneSignal.updateUserJwt(externalId, onesignalJWT);
});

OneSignal.addUserJwtInvalidatedListner(
   object : IUserJwtInvalidatedListener {
       override fun onUserJwtInvalidated(event: UserJwtInvalidatedEvent) {
         val externalId = event.externalId
         val onesignalJWT = "" 
         updateUserJwt(externalId, onesignalJWT)
       }
   },
)

This ensures that when a user’s JWT is invalidated, a new one can be fetched from your backend and passed to OneSignal. You can also use this function to generate a token with an email and phone number, allowing you to manage email and SMS subscriptions if the token created during authentication does not contain them.

5. Enable Identity Verification in the Dashboard

From Settings > Keys & IDs, toggle Token Identity Verification to enable.

Enabling Token Identity Verifcation

Enabling Token Identity Verification

📘

Enabling Identity Verification for Existing Apps

  1. Update the OneSignal SDK to version 5.x or later.
  2. Delay starting step five until there is sufficient user adoption.

Using Identity Verification with the REST API

Once Identity Verification is enabled, all requests to the following APIs must include the JWT in the authorization header, e.g., Authorization: Basic <JWT>.