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.
Click Generate New Keys to create a new key pair.
Download the PEM file or copy the private key, making sure to store the private key securely.
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
Property | Required | Description |
---|---|---|
iss | ✅ | Your Onesignal App ID. |
exp | ✅ | The token expiration date. |
identity | ✅ | The user's alias. |
subscriptions | Optional; 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 Identity Verification for Existing Apps
- Update the OneSignal SDK to version 5.x or later.
- 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>
.
Updated 22 days ago