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

📘

Identity Verification Beta is available to test on iOS SDK 5.3.x

  1. Use the OneSignal iOS SDK beta version 5.3 or later.
  2. It is recommended to test on new apps only as support is not yet available for Android and Web.

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: externalId, token: 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 withToken:onesignalJWT];
  

Example of adding an email:

OneSignal.getUser().addEmail(emailAddress);

OneSignal.getUser().addEmail(emailAddress)

// If you have not already included it in your JWT token, update the JWT with the email
let onesignalJWT = "newTokenThatContainsTheEmailToAdd"
OneSignal.updateUserJwt(externalId: externalId, token: onesignalJWT)

// Add the email
OneSignal.User.addEmail(emailAddress)

// If you have not already included it in your JWT token, update the JWT with the email
NSString *onesignalJWT = @"newTokenThatContainsTheEmailToAdd";
[OneSignal updateUserJwt:externalId withToken:onesignalJWT];

// Add the email
[OneSignal.User addEmail:emailAddress];

Example of adding an SMS subscription:

OneSignal.getUser().addSms(smsNumber);

OneSignal.getUser().addSms(smsNumber)

// If you have not already included it in your JWT token, update the JWT with the sms
let onesignalJWT = "newTokenThatContainsTheSmsToAdd"
OneSignal.updateUserJwt(externalId: externalId, token: onesignalJWT)

// Add the sms number
OneSignal.User.addSms(smsNumber)

// If you have not already included it in your JWT token, update the JWT with the sms
NSString *onesignalJWT = @"newTokenThatContainsTheSmsToAdd";
[OneSignal updateUserJwt:externalId withToken:onesignalJWT];

// Add the sms number
[OneSignal.User 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.addUserJwtInvalidatedListener(event -> {
  // Get the expired user's External ID
  String externalId = event.getExternalId();  
  
  // Fetch a new JWT from your backend for the user
  String onesignalJWT = "yourUpdatedToken";
  
  // 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)
       }
   },
)

class MyListener: OSUserJwtInvalidatedListener {
  func onUserJwtInvalidated(event: OSUserJwtInvalidatedEvent) {
    // Get the expired user's External ID
    let externalId = event.externalId
    
    // Fetch a new JWT from your backend for the user
  	let onesignalJWT = "yourUpdatedToken";
    
    // Provide the new JWT to the SDK
    OneSignal.updateUserJwt(externalId: externalId, token: onesignalJWT)
  }
}

// Add or remove your User Jwt Invalidated Listener
OneSignal.addUserJwtInvalidatedListener(myListener)
OneSignal.removeUserJwtInvalidatedListener(myListener)

@interface MyListener: NSObject<OSUserJwtInvalidatedListener>
@end

@implementation MyListener
- (void)onUserJwtInvalidatedWithEvent:(OSUserJwtInvalidatedEvent * _Nonnull)event { 
  // Get the expired user's External ID
  NSString *externalId = event.externalId;
    
  // Fetch a new JWT from your backend for the user
  NSString *onesignalJWT = @"yourUpdatedToken";

  // Provide the new JWT to the SDK
	[OneSignal updateUserJwt:externalId withToken:onesignalJWT];
}

// Add or remove your User Jwt Invalidated Listener
[OneSignal addUserJwtInvalidatedListener:myListener];
[OneSignal removeUserJwtInvalidatedListener:myListener];

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

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: Bearer <JWT>.