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
Identity Verification Beta is available to test on iOS SDK 5.3.x
- Use the OneSignal iOS SDK beta version 5.3 or later.
- 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.
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>
.
Updated 11 days ago