SDK Authentication

SDK Authentication allows you to supply cryptographic proof (generated server-side) to SDK requests made on behalf of logged-in users. When this feature is enabled in your app, the Braze dashboard can be configured to reject requests with a missing or invalid JWT signature.

When enabled, this feature will prevent unauthorized requests that use your app’s SDK API Key for logged in users, including:

  • Sending custom events, attributes, purchases, and session data
  • Creating new users in your Braze App Group
  • Updating standard user profile attributes
  • Receiving or triggering messages

Getting Started

There are four high-level steps to get started:

  1. Server-Side Integration - Generate a public and private key-pair, and use your private key to create a JWT (JSON Web Token) for the current logged-in user.

  2. SDK Integration - Enable this feature in the Braze SDK and request the JWT Token generated from your server.

  3. Adding Public Keys - Add your public key to the Braze dashboard in the “Manage Settings” page.

  4. Toggle Enforcement within the Braze Dashboard - Toggle this feature’s enforcement within the Braze dashboard on an app-by-app basis.

Server-Side Integration

Generate a Public/Private Key-Pair

Generate an RSA public/private key-pair. The Public Key will eventually be added to the Braze dashboard, while the Private Key should be stored securely on your server.

We recommend an RSA Key with 2048 bits for use with the RS256 JWT algorithm.

Create a JSON Web Token for the current user

Once you have your private key, your server-side application should use it to return a JWT to your app or website for the currently logged-in user.

Typically, this logic could go wherever your app would normally request the current user’s profile; such as a login endpoint or wherever your app refreshes the current user’s profile.

When generating the JWT, the following fields are expected:

JWT Header

Field Required Description
alg Yes The supported algorithm is RS256.
typ Yes The type should equal JWT.

JWT Payload

Field Required Description
sub Yes The “subject” should equal the User ID you supply Braze SDKs when calling changeUser
exp Yes The “expiration” of when you want this token to expire.
aud No The “audience” claim is optional, and if set should equal braze
iss No The “issuer” claim is optional, and if set should equal your SDK API Key.

JWT Libraries

To learn more about JSON Web Tokens, or to browse the many open source libraries that simplify this signing process, check out https://jwt.io.

SDK Integration

This feature is available as of the following SDK versions:

Enable this feature in the Braze SDK.

When this feature is enabled, the Braze SDK will append the current user’s last known JWT to network requests made to Braze Servers.

When calling initialize, set the optional sdkAuthentication property to true.

1
2
3
4
5
import braze from "@braze/web-sdk";
braze.initialize("YOUR-API-KEY-HERE", {
  baseUrl: "YOUR-SDK-ENDPOINT-HERE",
  enableSdkAuthentication: true,
});

When configuring the Appboy instance, call setIsSdkAuthenticationEnabled to true.

1
2
3
BrazeConfig.Builder brazeConfigBuilder = new BrazeConfig.Builder()
    .setIsSdkAuthenticationEnabled(true);
Braze.configure(this, brazeConfigBuilder.build());

When configuring the Appboy instance, call setIsSdkAuthenticationEnabled to true.

1
2
3
BrazeConfig.Builder brazeConfigBuilder = BrazeConfig.Builder()
    .setIsSdkAuthenticationEnabled(true)
Braze.configure(this, brazeConfigBuilder.build())

To enable SDK Authentication, add the key EnableSDKAuthentication to the Braze dictionary in your .plist file and set it to true.

Alternatively, you can enable SDK Authentication when initializing the SDK:

1
2
3
4
[Appboy startWithApiKey:@"YOUR-API-KEY"
            inApplication:application
        withLaunchOptions:launchOptions
        withAppboyOptions:@{ABKEnableSDKAuthenticationKey : @YES}];

To enable SDK Authentication, add the key EnableSDKAuthentication to the Braze dictionary in your .plist file and set it to true.

Alternatively, you can enable SDK Authentication when initializing the SDK:

1
2
3
4
Appboy.start(withApiKey: "YOUR-API-KEY",
                 in:application,
                 withLaunchOptions:launchOptions,
                 withAppboyOptions:[ ABKEnableSDKAuthenticationKey : true ])

Set the current user’s JWT Token

Whenever your app calls the Braze changeUser method, also supply the JWT token that was generated server-side.

You can also update the token to refresh the token mid-session for the current user.

Supply the JWT Token when calling changeUser:

1
2
import braze from "@braze/web-sdk";
braze.changeUser("NEW-USER-ID", "JWT-TOKEN-FROM-SERVER");

Or, when you have refreshed the user’s token mid-session:

1
2
import braze from "@braze/web-sdk";
braze.setSdkAuthenticationSignature("NEW-JWT-TOKEN-FROM-SERVER");

Supply the JWT Token when calling appboy.changeUser:

1
Braze.getInstance(this).changeUser("NEW-USER-ID", "JWT-TOKEN-FROM-SERVER");

Or, when you have refreshed the user’s token mid-session:

1
Braze.getInstance(this).setSdkAuthenticationSignature("NEW-JWT-TOKEN-FROM-SERVER");

Supply the JWT Token when calling appboy.changeUser:

1
Braze.getInstance(this).changeUser("NEW-USER-ID", "JWT-TOKEN-FROM-SERVER")

Or, when you have refreshed the user’s token mid-session:

1
Braze.getInstance(this).setSdkAuthenticationSignature("NEW-JWT-TOKEN-FROM-SERVER")

Supply the JWT Token when calling changeUser:

1
[[Appboy sharedInstance] changeUser:@"userId" sdkAuthSignature:@"signature"];

Or, when you have refreshed the user’s token mid-session:

1
[[Appboy sharedInstance] setSdkAuthenticationSignature:@"signature"];

Supply the JWT Token when calling changeUser:

1
Appboy.sharedInstance()?.changeUser("userId", sdkAuthSignature: "signature")

Or, when you have refreshed the user’s token mid-session:

1
Appboy.sharedInstance()?.setSdkAuthenticationSignature("signature")

Register a callback function for invalid tokens

When this feature is set as “Required”, the following scenarios will cause SDK requests to be rejected by Braze:

  • JWT was expired by the time is was received by the Braze API
  • JWT was empty or missing
  • JWT failed to verify for the Public Keys you uploaded to the Braze dashboard

When the SDK requests fail for one of these reasons, a callback function you supply will be invoked with a relevant Error Code. Failed requests will periodically be retried until your app supplies a new valid JWT.

This callback includes the User ID for which the request failed, the relevant Error Code, and the failed signature. If that user is still logged in, you can use this callback as an opportunity to request a new JWT from your server and supply Braze’s SDK with this new valid token.

1
2
3
4
5
6
7
import braze from "@braze/web-sdk";
braze.subscribeToSdkAuthenticationFailures((authFailure) => {
  // TODO: optionally log to your error-reporting service
  // TODO: check if the errorEvent user matches the currently logged-in user
  const updated_jwt = await getNewTokenSomehow(errorEvent);
  appboy.setSdkAuthenticationSignature(updated_jwt);
});
1
2
3
4
5
6
Braze.getInstance(this).subscribeToSdkAuthenticationFailures(errorEvent -> {
    // TODO: optionally log to your error-reporting service
    // TODO: check if the errorEvent user matches the currently logged-in user
    String newToken = getNewTokenSomehow(errorEvent);
    Braze.getInstance(getContext()).setSdkAuthenticationSignature(newToken);
});
1
2
3
4
5
6
Braze.getInstance(this).subscribeToSdkAuthenticationFailures({ errorEvent: BrazeSdkAuthenticationErrorEvent ->
    // TODO: optionally log to your error-reporting service
    // TODO: check if the errorEvent user matches the currently logged-in user
    val newToken: String = getNewTokenSomehow(errorEvent)
    Braze.getInstance(getContext()).setSdkAuthenticationSignature(newToken)
})
1
2
3
4
5
6
7
8
9
10
[[Appboy sharedInstance] setSdkAuthenticationDelegate:delegate];

// Method to implement in delegate
- (void)handleSdkAuthenticationError:(ABKSdkAuthenticationError *)errorEvent {
  // TODO: optionally log to your error-reporting service
  // TODO: check if the errorEvent user matches the currently logged-in user
  NSLog(@"Invalid SDK Authentication signature.");
  NSString *newSignature = getNewSignatureSomehow(errorEvent);
  [[Appboy sharedInstance] setSdkAuthenticationSignature:newSignature];
}
1
2
3
4
5
6
7
8
9
10
Appboy.sharedInstance()?.setSdkAuthenticationDelegate(delegate)

// Method to implement in delegate
func handle(_ errorEvent: ABKSdkAuthenticationError?) {
        // TODO: optionally log to your error-reporting service
        // TODO: check if the errorEvent user matches the currently logged-in user
        print("Invalid SDK Authentication signature.")
        let newSignature = getNewSignatureSomehow(errorEvent)
        Appboy.sharedInstance()?.setSdkAuthenticationSignature(newSignature)
    }

The errorEvent argument passed to this callback will contain the following information:

Property Description
reason A description of why the request failed.
error_code An internal error code used by Braze.
user_id The user ID from which the request failed.
signature The JWT that failed.

Adding Public Keys

In the “Manage Settings” page of the dashboard, add your Public Key to a specific app in the Braze dashboard. Each app supports up to 3 Public Keys. Note that the same Public/Private keys may be used across apps.

To add a Public Key:

  1. Choose the app in the left-hand side menu
  2. Click the Add Public Key button within the SDK Authentication settings
  3. Paste in the Public Key, and add an optional description
  4. After saving your changes, the key will appear in the list of Public Keys.

To delete a key, or to promote a key to the Primary key, choose the corresponding action in the overflow menu next to each key.

Enabling in the Braze Dashboard

Once your Server-side Integration and SDK Integration are complete, you can begin to enable this feature for those specific apps.

Keep in mind, SDK requests will continue to flow as usual - without authentication - unless the app’s SDK Authentication setting is switched to required in the Braze dashboard.

Should anything go wrong with your integration (i.e. your app is incorrectly passing tokens to the SDK, or your server is generating invalid tokens), simply disable this feature in the Braze dashboard and data will resume to flow as usual, without verification.

Enforcement Options

In the dashboard Settings page, each app has three SDK Authentication states which control how Braze verifies requests.

Setting Description
Disabled Braze will not verify the JWT supplied for a user. (Default Setting)
Optional Braze will verify requests for logged-in users, but will not reject invalid requests.
Required Braze will verify requests for logged-in users and will reject invalid JWTs.

dashboard

The “Optional” setting is a useful way to monitor the potential impact this feature will have on your app’s SDK traffic.

Invalid JWT signatures will be reported in both Optional and Required states, however only the Required state will reject SDK requests causing apps to retry and request new signatures.

Analytics

Each app will show a breakdown of SDK Authentication errors collected while this feature is in the Optional and Required state.

Data is available in real-time, and you can hover over points in the chart to see a breakdown of errors for a given date.

analytics

Error Codes

Error Code Error Reason Description
10 EXPIRATION_REQUIRED Expiration is a required field for Braze usage.
20 DECODING_ERROR Non-matching public key or a general uncaught error.
21 SUBJECT_MISMATCH The expected and actual subjects are not the same.
22 EXPIRED The token provided has expired.
23 INVALID_PAYLOAD The token payload is invalid.
24 INCORRECT_ALGORITHM The algorithm of the token is not supported.
25 PUBLIC_KEY_ERROR The public key could not be converted into the proper format.
26 MISSING_TOKEN No token was provided in the request.
27 NO_MATCHING_PUBLIC_KEYS No public keys matched the provided token.
28 PAYLOAD_USER_ID_MISMATCH Not all user ids in the request payload match as is required.

Frequently Asked Questions

Can I use this feature on only some of my apps?

Yes, this feature can be enabled for specific apps and doesn’t need to be used on all of your apps.

What happens to users who are still on older versions of my app?

When you begin to enforce this feature, requests made by older app versions will be rejected by Braze and retried by the SDKs. Once users upgrade their app to a supported version, those enqueued requests will begin to be accepted again.

If possible, you should push users to upgrade as you would for any other mandatory upgrade. Alternatively, you can keep the feature “optional” until you see that an acceptable percentage of users have upgraded.

What expiration should I use when generating JWT tokens?

We recommend using the higher value of: average session duration, session cookie/token expiration, or the frequency at which your application would otherwise refresh the current user’s profile.

What happens if a JWT expires in the middle of a user’s session?

Should a user’s token expire mid-session, the SDK has a callback function it will invoke to let your app know that a new JWT token is needed to continue sending data to Braze.

What happens if my server-side integration breaks and I can no longer create a JWT?

If your server is not able to provide JWT tokens or you notice some integration issue, you can always disable the feature in the Braze dashboard.

Once disabled, any pending failed SDK requests will eventually be retried by the SDK and accepted by Braze.

Why does this feature use Public/Private keys instead of Shared Secrets?

When using Shared Secrets, anyone with access to that shared secret (i.e. the Braze dashboard page) would be able to generate tokens and impersonate your end-users.

Instead, we use Public/Private Keys so that not even Braze Employees (let alone your dashboard users) have access to your Private Keys.

How will rejected requests be retried?

When a request is rejected because of an authentication error, the SDKs will invoke a your callback used to refresh the user’s JWT signature.

Requests will retry periodically using an exponential backoff approach. After 50 consecutive failed attempts, retries will be paused until the next session start. Each SDK also has a method to manually request a data flush.

WAS THIS PAGE HELPFUL?
New Stuff!