Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
bd32975
feat: add authentication failure and retry policy enums and types
lposen Oct 7, 2025
50ef0e6
chore: update eslint-config-prettier and add prettier-eslint dependency
lposen Oct 7, 2025
af0065e
feat: export new authentication and retry policy types in index files
lposen Oct 7, 2025
762f333
feat: enhance IterableConfig with JWT error handling and retry policy…
lposen Oct 7, 2025
cfe1de2
feat: add onAuthFailure and pauseAuthRetries methods to Iterable class
lposen Oct 7, 2025
7fde4e7
feat: implement retry policy and JWT error handling in IterableAppPro…
lposen Oct 7, 2025
8975ac1
chore: update Iterable API dependency version to 3.6.1
lposen Oct 7, 2025
ab8efaa
feat: implement onAuthFailure handling and pauseAuthRetries method in…
lposen Oct 7, 2025
1972fbb
feat: fix nullpointerexception on com.iterable.iterableapi.IterableIn…
lposen Oct 7, 2025
2cd8253
refactor: remove commented-out encryptionEnforced code from Serializa…
lposen Oct 7, 2025
5810a0a
feat: improve JWT error handling and enhance IterableConfig with addi…
lposen Oct 7, 2025
fd74351
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 7, 2025
ef86b15
refactor: fix onAuthFailure call
lposen Oct 7, 2025
e85d660
refactor: remove onAuthFailure method and update event handler setup …
lposen Oct 7, 2025
372df66
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 7, 2025
c32447f
chore: remove unused index.ts file from hooks directory
lposen Oct 7, 2025
a7804e5
refactor: simplify authHandler type and standardize IterableAuthFailu…
lposen Oct 7, 2025
21ca59d
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 7, 2025
6d8c45a
refactor: simplify authHandler type and standardize IterableAuthFailu…
lposen Oct 7, 2025
18cba09
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 7, 2025
050ad22
feat: enhance JWT error handling with detailed alerts for auth failures
lposen Oct 7, 2025
a63b9dc
refactor: remove onJWTErrorPresent flag from IterableConfig to stream…
lposen Oct 7, 2025
60bc88e
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 7, 2025
38f2791
chore: update Iterable-iOS-SDK dependency to version 6.6.1 in podspec
lposen Oct 7, 2025
e36be70
chore: remove tempfix and update Embed Pods Frameworks build phase in…
lposen Oct 7, 2025
356e767
feat: implement user notification handling and remote notification re…
lposen Oct 7, 2025
04cb0d1
feat: add pauseAuthRetries method and enhance auth failure handling i…
lposen Oct 7, 2025
47cdab3
chore: update Xcode project configuration and enable authHandler in I…
lposen Oct 7, 2025
b22b9ea
refactor: delegate event sending for auth failure handling in ReactIt…
lposen Oct 7, 2025
16c2c9a
fix: improve JWT error logging and alert messaging for auth failures
lposen Oct 7, 2025
492c3b6
chore: update dependencies and improve code formatting
lposen Oct 9, 2025
786a079
Merge branch 'jwt/master' into jwt/MOB-10946-task-2-authfailure-and-r…
lposen Oct 9, 2025
f1d10cb
chore: update yarn.lock
lposen Oct 9, 2025
5fbb9c9
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 9, 2025
78e4914
Merge branch 'jwt/MOB-10947-task-3-android-retrypolicy-config-at-andr…
lposen Oct 9, 2025
edfa70f
refactor: remove unnecessary NSLog statements from AppDelegate.swift
lposen Oct 9, 2025
65cb551
feat: add authentication manager to Iterable class
lposen Oct 10, 2025
5bbb5fc
refactor: remove pauseAuthRetries method from Iterable class
lposen Oct 10, 2025
92fbff1
chore: disable TSDoc syntax rule for IterableRetryBackoff enum
lposen Oct 10, 2025
e94100f
feat: add pauseAuthRetries method to authentication manager and enhan…
lposen Oct 10, 2025
5e4e579
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 10, 2025
836ad6c
Merge branch 'jwt/MOB-10947-task-3-android-retrypolicy-config-at-andr…
lposen Oct 10, 2025
3737d57
fix: improve null safety in IterableInAppMessage.fromViewToken method
lposen Oct 10, 2025
20cd031
Merge branch 'jwt/MOB-10947-task-3-android-retrypolicy-config-at-andr…
lposen Oct 10, 2025
361897f
feat: implement IterableApi class for calls to native layer
lposen Oct 10, 2025
4ee7bdf
docs: add documentation comment for IterableApi class
lposen Oct 10, 2025
f2cf388
refactor: replace RNIterableAPI calls with IterableApi methods in Ite…
lposen Oct 10, 2025
4da6aa0
refactor: update IterableApi method signatures to accept destructured…
lposen Oct 10, 2025
9be2327
refactor: streamline logging in Iterable class and enhance IterableLo…
lposen Oct 10, 2025
de4db13
refactor: remove IterableLogger instantiation from tests and clean up…
lposen Oct 10, 2025
efb72a6
refactor: replace RNIterableAPI references with IterableApi
lposen Oct 10, 2025
3990876
Merge branch 'jwt/MOB-12231-create-an-iterableapi-class-for-api-calls…
lposen Oct 10, 2025
cbd2799
refactor: enable logging in IterableApi methods by removing commented…
lposen Oct 10, 2025
2025291
test: add comprehensive unit tests for IterableLogger functionality
lposen Oct 10, 2025
cf76e09
Merge branch 'new-arch/master' into jwt/master
lposen Oct 10, 2025
841f63f
Merge branch 'jwt/master' into jwt/MOB-10946-task-2-authfailure-and-r…
lposen Oct 10, 2025
7b8fdb1
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 10, 2025
3870dc3
Merge branch 'jwt/MOB-10947-task-3-android-retrypolicy-config-at-andr…
lposen Oct 10, 2025
39f07d0
Merge branch 'jwt/MOB-11032-task-4-ios-bridge-retrypolicy-and-authfai…
lposen Oct 10, 2025
307326e
Merge branch 'jwt/MOB-12231-create-an-iterableapi-class-for-api-calls…
lposen Oct 10, 2025
fb4b801
refactor: simplify inAppManager initialization to avoid circular depe…
lposen Oct 10, 2025
800bb0b
feat: add IterableApi and IterableAuthManager exports to core classes
lposen Oct 10, 2025
0af6532
Merge branch 'jwt/MOB-12231-create-an-iterableapi-class-for-api-calls…
lposen Oct 10, 2025
67a806d
fix: removed comment description that no longer applies
lposen Oct 13, 2025
d9a7b82
test: prettify Iterable test file
lposen Oct 13, 2025
1dbd4e2
Merge branch 'jwt/master' into jwt/MOB-10946-task-2-authfailure-and-r…
lposen Oct 13, 2025
71ac5c4
docs: add better comments to IterableAuthManager
lposen Oct 13, 2025
d95ae90
fix: standardize authentication failure reason representation across …
lposen Oct 13, 2025
b31ffd7
Merge branch 'jwt/MOB-10946-task-2-authfailure-and-retrypolicy-ts-cla…
lposen Oct 14, 2025
0587649
Merge branch 'jwt/MOB-10947-task-3-android-retrypolicy-config-at-andr…
lposen Oct 14, 2025
9883a21
Merge branch 'new-arch/master' into jwt/master
lposen Oct 14, 2025
0eedca5
Merge pull request #726 from Iterable/jwt/MOB-10946-task-2-authfailur…
lposen Oct 14, 2025
ed20041
Merge branch 'jwt/master' into jwt/MOB-10947-task-3-android-retrypoli…
lposen Oct 14, 2025
0191b7b
chore: removed onTokenRegistrationFailed method as per PR comment
lposen Oct 14, 2025
70fa36a
feat: implement retry policy configuration in IterableConfig for iOS
lposen Oct 14, 2025
52d5ac4
Merge branch 'jwt/MOB-11032-task-4-ios-bridge-retrypolicy-and-authfai…
lposen Oct 14, 2025
2fa18f8
Merge branch 'jwt/MOB-12231-create-an-iterableapi-class-for-api-calls…
lposen Oct 14, 2025
5fa3361
Merge pull request #727 from Iterable/jwt/MOB-10947-task-3-android-re…
lposen Oct 14, 2025
db24c40
Merge branch 'jwt/master' into jwt/MOB-11032-task-4-ios-bridge-retryp…
lposen Oct 14, 2025
e579386
Merge pull request #728 from Iterable/jwt/MOB-11032-task-4-ios-bridge…
lposen Oct 14, 2025
c9fefd7
Merge branch 'jwt/master' into jwt/MOB-12231-create-an-iterableapi-cl…
lposen Oct 14, 2025
23d719a
test: add tests to IterableApi
lposen Oct 14, 2025
644c510
Merge branch 'jwt/MOB-12231-create-an-iterableapi-class-for-api-calls…
lposen Oct 14, 2025
a693494
docs: enhance IterableLogger documentation with descriptions and exa…
lposen Oct 14, 2025
54f4626
Merge branch 'jwt/MOB-12298-new-improve-logger' of github.com:Iterabl…
lposen Oct 14, 2025
5517bf7
Update src/inApp/classes/IterableInAppManager.ts
lposen Oct 16, 2025
a2e5177
Merge pull request #737 from Iterable/jwt/MOB-12231-create-an-iterabl…
lposen Oct 16, 2025
42669ff
Merge branch 'new-arch/master' into jwt/master
lposen Oct 16, 2025
a4bd708
Merge branch 'jwt/master' into jwt/MOB-12298-new-improve-logger
lposen Oct 17, 2025
c0a2c20
docs: removed a TODO and enhanced documentation for IterableLogger
lposen Oct 17, 2025
1eb3069
Merge branch 'new-arch/master' into jwt/master
lposen Oct 17, 2025
e06edab
Merge branch 'jwt/master' into jwt/MOB-12298-new-improve-logger
lposen Oct 17, 2025
6828a7a
fix: change default log level from info to debug in IterableConfig
lposen Oct 17, 2025
e2c6148
refactor: update default log level to debug in IterableLogger and rel…
lposen Oct 17, 2025
d695a8b
Merge pull request #739 from Iterable/jwt/MOB-12298-new-improve-logger
lposen Oct 17, 2025
2dcb969
chore: update yarn.lock and enhance example configuration documentation
lposen Oct 21, 2025
1bfa9d5
chore: add .env.local to .gitignore and update example configuration …
lposen Oct 21, 2025
d471800
refactor: small updates to ReactIterable.swift
lposen Oct 21, 2025
6a9972a
feat: implement JWT generation module for React Native in example
lposen Oct 21, 2025
ad48782
chore: remove unused crypto-js and @types/crypto-js dependencies from…
lposen Oct 21, 2025
5df923f
feat: add IterableJwtGenerator and JwtTokenModule for JWT token gener…
lposen Oct 21, 2025
40c4bad
fix: ensure login is called during initialization and improve error h…
lposen Oct 21, 2025
fea6232
refactor: remove commented-out code from IterableJwtGenerator.swift t…
lposen Oct 21, 2025
fd76f08
refactor: remove unnecessary login calls and clean up error handling …
lposen Oct 21, 2025
b663dce
refactor: remove console log statements to streamline IterableAppProv…
lposen Oct 21, 2025
a58be2a
feat: introduce NativeJwtTokenModule for JWT token generation and rem…
lposen Oct 21, 2025
13012d9
refactor: enhance JWT generation methods and update .env.example comm…
lposen Oct 21, 2025
9038579
Merge pull request #767 from Iterable/jwt/SDK-136-new-jwt-token-gener…
lposen Oct 21, 2025
d7f81c0
chore: update package version to 2.2.0-alpha.0 in package.json and it…
lposen Oct 21, 2025
e7deb3d
chore: update CHANGELOG.md for 2.2.0-alpha.0 release
lposen Oct 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ ios/generated
android/generated

# Iterable
.env.local
.env
.xcode.env.local
coverage/
Expand Down
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
## 2.2.0-alpha.0 (2025-10-21)

### Updates
- Updated Android SDK version to [3.6.1](https://github.com/Iterable/iterable-android-sdk/releases/tag/3.6.1)
- Updated iOS SDK version to [6.6.1](https://github.com/Iterable/swift-sdk/releases/tag/6.6.1)
- Added JWT Capabilities:
- Added `Iterable.authhManager`, which manages the authentication flow
- Added `IterableRetryBackoff` and `IterableAuthFailureReason` enums
- Added `onJWTError` and `retryPolicy` for control over JWT flow
- Moved all native calls to `IterableApi.ts`
- Added JWT example to our example app

### Fixes
- Created a standalone `IterableLogger` to avoid circular dependencies

## 2.1.0-beta.1

## Fixes
### Fixes
- Add Temporary fix for circular paths, which break expo ([9c09743](https://github.com/Iterable/react-native-sdk/commit/9c09743))

## 2.1.0-beta.0
Expand Down
2 changes: 1 addition & 1 deletion Iterable-React-Native-SDK.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Pod::Spec.new do |s|
s.private_header_files = "ios/**/*.h"

# Load Iterables iOS SDK as a dependency
s.dependency "Iterable-iOS-SDK", "6.5.4.1"
s.dependency "Iterable-iOS-SDK", "6.6.1"

# Basic Swift support
s.pod_target_xcconfig = {
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def kotlin_version = getExtOrDefault("kotlinVersion")
dependencies {
implementation "com.facebook.react:react-android"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
api "com.iterable:iterableapi:3.5.2"
api "com.iterable:iterableapi:3.6.1"
// api project(":iterableapi") // links to local android SDK repo rather than by release
}

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

import com.iterable.iterableapi.AuthFailure;
import com.iterable.iterableapi.InboxSessionManager;
import com.iterable.iterableapi.IterableAction;
import com.iterable.iterableapi.IterableActionContext;
Expand Down Expand Up @@ -572,19 +573,33 @@ public String onAuthTokenRequested() {
}
}

@Override
public void onAuthFailure(AuthFailure authFailure) {
// Create a JSON object for the authFailure object
JSONObject messageJson = new JSONObject();
try {
messageJson.put("userKey", authFailure.userKey);
messageJson.put("failedAuthToken", authFailure.failedAuthToken);
messageJson.put("failedRequestTime", authFailure.failedRequestTime);
messageJson.put("failureReason", authFailure.failureReason.name());
WritableMap eventData = Serialization.convertJsonToMap(messageJson);
sendEvent(EventName.handleAuthFailureCalled.name(), eventData);
} catch (JSONException e) {
IterableLogger.v(TAG, "Failed to set authToken");
}
}

public void pauseAuthRetries(boolean pauseRetry) {
IterableApi.getInstance().pauseAuthRetries(pauseRetry);
}

@Override
public void onTokenRegistrationSuccessful(String authToken) {
IterableLogger.v(TAG, "authToken successfully set");
// MOB-10422: Pass successhandler to event listener
sendEvent(EventName.handleAuthSuccessCalled.name(), null);
}

@Override
public void onTokenRegistrationFailed(Throwable object) {
IterableLogger.v(TAG, "Failed to set authToken");
sendEvent(EventName.handleAuthFailureCalled.name(), null);
}

public void addListener(String eventName) {
// Keep: Required for RN built in Event Emitter Calls.
}
Expand Down
36 changes: 28 additions & 8 deletions android/src/main/java/com/iterable/reactnative/Serialization.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.iterable.iterableapi.IterableInboxSession;
import com.iterable.iterableapi.IterableLogger;
import com.iterable.iterableapi.RNIterableInternal;
import com.iterable.iterableapi.RetryPolicy;

import org.json.JSONArray;
import org.json.JSONException;
Expand Down Expand Up @@ -94,7 +95,7 @@ static CommerceItem commerceItemFromMap(JSONObject itemMap) throws JSONException
categories[i] = categoriesArray.getString(i);
}
}

return new CommerceItem(itemMap.getString("id"),
itemMap.getString("name"),
itemMap.getDouble("price"),
Expand Down Expand Up @@ -216,9 +217,17 @@ static IterableConfig.Builder getConfigFromReadableMap(ReadableMap iterableConte

configBuilder.setDataRegion(iterableDataRegion);
}

if (iterableContextJSON.has("encryptionEnforced")) {
configBuilder.setEncryptionEnforced(iterableContextJSON.optBoolean("encryptionEnforced"));

if (iterableContextJSON.has("retryPolicy")) {
JSONObject retryPolicyJson = iterableContextJSON.getJSONObject("retryPolicy");
int maxRetry = retryPolicyJson.getInt("maxRetry");
long retryInterval = retryPolicyJson.getLong("retryInterval");
String retryBackoff = retryPolicyJson.getString("retryBackoff");
RetryPolicy.Type retryPolicyType = RetryPolicy.Type.LINEAR;
if (retryBackoff.equals("EXPONENTIAL")) {
retryPolicyType = RetryPolicy.Type.EXPONENTIAL;
}
configBuilder.setAuthRetryPolicy(new RetryPolicy(maxRetry, retryInterval, retryPolicyType));
}

return configBuilder;
Expand Down Expand Up @@ -257,7 +266,13 @@ static JSONObject actionContextToJson(IterableActionContext iterableActionContex
}

static IterableInboxSession.Impression inboxImpressionFromMap(JSONObject impressionMap) throws JSONException {
return new IterableInboxSession.Impression(impressionMap.getString("messageId"),
// Add null check for messageId to prevent NullPointerException
String messageId = impressionMap.optString("messageId", null);
if (messageId == null || messageId.isEmpty()) {
throw new JSONException("messageId is null or empty");
}

return new IterableInboxSession.Impression(messageId,
impressionMap.getBoolean("silentInbox"),
impressionMap.optInt("displayCount", 0),
(float) impressionMap.optDouble("duration", 0)
Expand All @@ -271,8 +286,13 @@ static List<IterableInboxSession.Impression> impressionsFromReadableArray(Readab
JSONArray impressionJsonArray = convertArrayToJson(array);

for (int i = 0; i < impressionJsonArray.length(); i++) {
JSONObject impressionObj = impressionJsonArray.getJSONObject(i);
list.add(inboxImpressionFromMap(impressionObj));
try {
JSONObject impressionObj = impressionJsonArray.getJSONObject(i);
list.add(inboxImpressionFromMap(impressionObj));
} catch (JSONException e) {
// Skip invalid entries instead of failing completely
IterableLogger.w(TAG, "Skipping invalid impression at index " + i + ": " + e.getLocalizedMessage());
}
}
} catch (JSONException e) {
IterableLogger.e(TAG, "Failed converting to JSONObject");
Expand All @@ -286,7 +306,7 @@ static List<IterableInboxSession.Impression> impressionsFromReadableArray(Readab
// ---------------------------------------------------------------------------------------
// region React Native JSON conversion methods
// obtained from https://gist.github.com/viperwarp/2beb6bbefcc268dee7ad

static WritableMap convertJsonToMap(JSONObject jsonObject) throws JSONException {
WritableMap map = new WritableNativeMap();

Expand Down
7 changes: 7 additions & 0 deletions android/src/newarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.iterable.iterableapi.AuthFailure;
import com.iterable.iterableapi.IterableLogger;

public class RNIterableAPIModule extends NativeRNIterableAPISpec {
private final ReactApplicationContext reactContext;
Expand Down Expand Up @@ -217,6 +219,11 @@ public void passAlongAuthToken(@Nullable String authToken) {
moduleImpl.passAlongAuthToken(authToken);
}

@Override
public void pauseAuthRetries(boolean pauseRetry) {
moduleImpl.pauseAuthRetries(pauseRetry);
}

public void sendEvent(@NonNull String eventName, @Nullable Object eventData) {
moduleImpl.sendEvent(eventName, eventData);
}
Expand Down
5 changes: 5 additions & 0 deletions android/src/oldarch/java/com/RNIterableAPIModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,11 @@ public void passAlongAuthToken(@Nullable String authToken) {
moduleImpl.passAlongAuthToken(authToken);
}

@ReactMethod
public void pauseAuthRetries(boolean pauseRetry) {
moduleImpl.pauseAuthRetries(pauseRetry);
}


public void sendEvent(@NonNull String eventName, @Nullable Object eventData) {
moduleImpl.sendEvent(eventName, eventData);
Expand Down
16 changes: 12 additions & 4 deletions example/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,19 @@
# 4. Fill in the following fields:
# - Name: A descriptive name for the API key
# - Type: Mobile
# - JWT authentication: Leave **unchecked** (IMPORTANT)
# - JWT authentication: Whether or not you want to use JWT
# 5. Click "Create API Key"
# 6. Copy the generated API key
# 7. Replace the placeholder text next to `ITBL_API_KEY=` with the copied API key
# 6. Copy the generated API key and replace the placeholder text next to
# `ITBL_API_KEY=` with the copied API key
# 7. If you chose to enable JWT authentication, copy the JWT secret and and
# replace the placeholder text next to `ITBL_JWT_SECRET=` with the copied
# JWT secret
ITBL_API_KEY=replace_this_with_your_iterable_api_key
# Your JWT Secret, created when making your API key (see above)
ITBL_JWT_SECRET=replace_this_with_your_jwt_secret
# Is your api token JWT Enabled?
# Must be set to 'true' to enable JWT authentication
ITBL_IS_JWT_ENABLED=true

# Your Iterable user ID or email address
ITBL_ID=replace_this_with_your_user_id_or_email
ITBL_ID=replace_this_with_your_user_id_or_email
21 changes: 14 additions & 7 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ _example app directory_. To do so, run the following:

```bash
cd ios
pod install
bundle install
bundle exec pod install
```

Once this is done, `cd` back into the _example app directory_:
Expand All @@ -40,12 +41,18 @@ In it, you will find:

```shell
ITBL_API_KEY=replace_this_with_your_iterable_api_key
ITBL_JWT_SECRET=replace_this_with_your_jwt_secret
ITBL_IS_JWT_ENABLED=true
ITBL_ID=replace_this_with_your_user_id_or_email
```

Replace `replace_this_with_your_iterable_api_key` with your _mobile_ Iterable API key,
and replace `replace_this_with_your_user_id_or_email` with the email or user id
that you use to log into Iterable.
- Replace `replace_this_with_your_iterable_api_key` with your **_mobile_
Iterable API key**
- Replace `replace_this_with_your_jwt_secret` with your **JWT Secret** (if you
have a JWT-enabled API key)
- Set `ITBL_IS_JWT_ENABLED` to true if you have a JWT-enabled key, and false if you do not.
- Replace `replace_this_with_your_user_id_or_email` with the **email or user
id** that you use to log into Iterable.

Follow the steps below if you do not have a mobile Iterable API key.

Expand All @@ -54,12 +61,12 @@ To add an API key, do the following:
1. Sign into your Iterable account
2. Go to [Integrations > API Keys](https://app.iterable.com/settings/apiKeys)
3. Click "New API Key" in the top right corner
4. Fill in the followsing fields:
4. Fill in the following fields:
- Name: A descriptive name for the API key
- Type: Mobile
- JWT authentication: Leave **unchecked** (IMPORTANT)
- JWT authentication: Check to enable JWT authentication. If enabled, will need to create a [JWT generator](https://support.iterable.com/hc/en-us/articles/360050801231-JWT-Enabled-API-Keys#sample-python-code-for-jwt-generation) to generate the JWT token.
5. Click "Create API Key"
6. Copy the generated API key
6. Copy the generated API key and JWT secret into your _.env_ file


## Step 3: Start the Metro Server
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.iterable;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Base64;
import java.util.Base64.Encoder;

/**
* Utility class to generate JWTs for use with the Iterable API
*
* @author engineering@iterable.com
*/
public class IterableJwtGenerator {
static Encoder encoder = Base64.getUrlEncoder().withoutPadding();

private static final String algorithm = "HmacSHA256";

// Iterable enforces a 1-year maximum token lifetime
private static final Duration maxTokenLifetime = Duration.ofDays(365);

private static long millisToSeconds(long millis) {
return millis / 1000;
}

private static final String encodedHeader = encoder.encodeToString(
"{\"alg\":\"HS256\",\"typ\":\"JWT\"}".getBytes(StandardCharsets.UTF_8)
);

/**
* Generates a JWT from the provided secret, header, and payload. Does not
* validate the header or payload.
*
* @param secret Your organization's shared secret with Iterable
* @param payload The JSON payload
*
* @return a signed JWT
*/
public static String generateToken(String secret, String payload) {
try {
String encodedPayload = encoder.encodeToString(
payload.getBytes(StandardCharsets.UTF_8)
);
String encodedHeaderAndPayload = encodedHeader + "." + encodedPayload;

// HMAC setup
Mac hmac = Mac.getInstance(algorithm);
SecretKeySpec keySpec = new SecretKeySpec(
secret.getBytes(StandardCharsets.UTF_8), algorithm
);
hmac.init(keySpec);

String signature = encoder.encodeToString(
hmac.doFinal(
encodedHeaderAndPayload.getBytes(StandardCharsets.UTF_8)
)
);

return encodedHeaderAndPayload + "." + signature;

} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
}

/**
* Generates a JWT (issued now, expires after the provided duration).
*
* @param secret Your organization's shared secret with Iterable.
* @param duration The token's expiration time. Up to one year.
* @param email The email to included in the token, or null.
* @param userId The userId to include in the token, or null.
*
* @return A JWT string
*/
public static String generateToken(
String secret, Duration duration, String email, String userId) {

if (duration.compareTo(maxTokenLifetime) > 0)
throw new IllegalArgumentException(
"Duration must be one year or less."
);

if ((userId != null && email != null) || (userId == null && email == null))
throw new IllegalArgumentException(
"The token must include a userId or email, but not both."
);

long now = millisToSeconds(System.currentTimeMillis());

String payload;
if (userId != null)
payload = String.format(
"{ \"userId\": \"%s\", \"iat\": %d, \"exp\": %d }",
userId, now, now + millisToSeconds(duration.toMillis())
);
else
payload = String.format(
"{ \"email\": \"%s\", \"iat\": %d, \"exp\": %d }",
email, now, now + millisToSeconds(duration.toMillis())
);

return generateToken(secret, payload);
Comment on lines +77 to +104
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found 2 issues:

1. Function with high complexity (count = 7): generateToken [qlty:function-complexity]


2. Function with many parameters (count = 4): generateToken [qlty:function-parameters]

}
}
Loading