-
Notifications
You must be signed in to change notification settings - Fork 40
[SDK-136] Add JWT Token generator #765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: jwt/master
Are you sure you want to change the base?
Conversation
…into a ReadableMap
…IterableAuthManager
… ReactIterableAPI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements JWT token generation functionality for the Iterable SDK, enabling support for JWT-enabled API keys. The implementation includes TypeScript type definitions, native iOS and Android implementations, and comprehensive test coverage.
- Adds JWT token generator method accessible via
IterableAuthManager.generateJwtToken() - Implements native token generation for both iOS (Swift) and Android (Java) platforms
- Updates example app to demonstrate JWT authentication flow
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/index.tsx |
Exports new IterableGenerateJwtTokenArgs type |
src/core/types/index.ts |
Re-exports JWT token arguments type |
src/core/types/IterableGenerateJwtTokenArgs.ts |
Defines TypeScript type for JWT token generation parameters with email/userId union |
src/core/classes/IterableAuthManager.ts |
Adds generateJwtToken method with comprehensive documentation |
src/core/classes/IterableApi.ts |
Implements static generateJwtToken method and corrects typo in comment |
src/core/classes/Iterable.ts |
Removes unused timeout variable and cleanup code |
src/api/NativeRNIterableAPI.ts |
Defines native module interface for JWT token generation |
src/__tests__/IterableAuthManager.test.ts |
Adds comprehensive test suite for auth manager functionality |
src/__mocks__/MockRNIterableAPI.ts |
Implements mock for JWT token generation testing |
ios/RNIterableAPI/ReactIterableAPI.swift |
Implements native iOS JWT generation with validation |
ios/RNIterableAPI/RNIterableAPI.mm |
Bridges Swift implementation to React Native |
example/src/hooks/useIterableApp.tsx |
Demonstrates JWT auth handler usage in example app |
example/README.md |
Updates documentation with JWT setup instructions |
example/.env.example |
Adds JWT secret configuration template |
android/src/oldarch/java/com/RNIterableAPIModule.java |
Adds JWT generation method to old architecture module |
android/src/newarch/java/com/RNIterableAPIModule.java |
Adds JWT generation method to new architecture module |
android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java |
Implements Android JWT token generation logic |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| userId: userId | ||
| ) | ||
| } else if let email = email { | ||
| token = IterableTokenGenerator.generateJwtForEial( |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'generateJwtForEial' to 'generateJwtForEmail'.
| token = IterableTokenGenerator.generateJwtForEial( | |
| token = IterableTokenGenerator.generateJwtForEmail( |
| 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: |
Copilot
AI
Oct 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Corrected spelling of 'followsing' to 'following'.
| 4. Fill in the followsing fields: | |
| 4. Fill in the following fields: |
|
We might have to re-consider JWT generator in native SDKs. Idea of JWT is that tokens will be generated on Client's server side. The generator on client side was just for testing purpose and should have lived in the Tester apps for purpose of test. Will need to investigate how native layer jwt generation code made it to public SDK |
3 new issues
This is from Qlty Cloud, the successor to Code Climate Quality. Learn more. |
❌ 3 blocking issues (6 total)
This is from Qlty Cloud, the successor to Code Climate Quality. Learn more. |
android/src/main/java/com/iterable/reactnative/RNIterableAPIModuleImpl.java
Show resolved
Hide resolved
| public void generateJwtToken(ReadableMap opts, Promise promise) { | ||
| try { | ||
| String secret = opts.getString("secret"); | ||
| long durationMs = (long) opts.getDouble("duration"); | ||
| String userId = opts.hasKey("userId") && !opts.isNull("userId") ? opts.getString("userId") : null; | ||
| String email = opts.hasKey("email") && !opts.isNull("email") ? opts.getString("email") : null; | ||
|
|
||
| // Validate that exactly one of userId or email is provided | ||
| if ((userId != null && email != null) || (userId == null && email == null)) { | ||
| promise.reject("E_INVALID_ARGS", "The token must include a userId or email, but not both.", (Throwable) null); | ||
| return; | ||
| } | ||
|
|
||
| // Use the Android SDK's Duration-based JWT generator | ||
| Duration duration = Duration.ofMillis(durationMs); | ||
| String token = IterableJwtGenerator.generateToken(secret, duration, email, userId); | ||
| promise.resolve(token); | ||
| } catch (Exception e) { | ||
| promise.reject("E_JWT_GENERATION_FAILED", "Failed to generate JWT: " + e.getMessage(), e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @@ -0,0 +1,186 @@ | |||
| import { MockRNIterableAPI } from '../__mocks__/MockRNIterableAPI'; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @@ -1,5 +1,6 @@ | |||
| import { IterableAuthResponse } from './IterableAuthResponse'; | |||
| import type { IterableGenerateJwtTokenArgs } from '../types/IterableGenerateJwtTokenArgs'; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @@ -0,0 +1,28 @@ | |||
| interface IterableGenerateJwtTokenArgsBase { | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void generateJwtToken(ReadableMap opts, Promise promise) { | ||
| try { | ||
| String secret = opts.getString("secret"); | ||
| long durationMs = (long) opts.getDouble("duration"); | ||
| String userId = opts.hasKey("userId") && !opts.isNull("userId") ? opts.getString("userId") : null; | ||
| String email = opts.hasKey("email") && !opts.isNull("email") ? opts.getString("email") : null; | ||
|
|
||
| // Validate that exactly one of userId or email is provided | ||
| if ((userId != null && email != null) || (userId == null && email == null)) { | ||
| promise.reject("E_INVALID_ARGS", "The token must include a userId or email, but not both.", (Throwable) null); | ||
| return; | ||
| } | ||
|
|
||
| // Use the Android SDK's Duration-based JWT generator | ||
| Duration duration = Duration.ofMillis(durationMs); | ||
| String token = IterableJwtGenerator.generateToken(secret, duration, email, userId); | ||
| promise.resolve(token); | ||
| } catch (Exception e) { | ||
| promise.reject("E_JWT_GENERATION_FAILED", "Failed to generate JWT: " + e.getMessage(), e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| public void generateJwtToken(ReadableMap opts, Promise promise) { | ||
| try { | ||
| String secret = opts.getString("secret"); | ||
| long durationMs = (long) opts.getDouble("duration"); | ||
| String userId = opts.hasKey("userId") && !opts.isNull("userId") ? opts.getString("userId") : null; | ||
| String email = opts.hasKey("email") && !opts.isNull("email") ? opts.getString("email") : null; | ||
|
|
||
| // Validate that exactly one of userId or email is provided | ||
| if ((userId != null && email != null) || (userId == null && email == null)) { | ||
| promise.reject("E_INVALID_ARGS", "The token must include a userId or email, but not both.", (Throwable) null); | ||
| return; | ||
| } | ||
|
|
||
| // Use the Android SDK's Duration-based JWT generator | ||
| Duration duration = Duration.ofMillis(durationMs); | ||
| String token = IterableJwtGenerator.generateToken(secret, duration, email, userId); | ||
| promise.resolve(token); | ||
| } catch (Exception e) { | ||
| promise.reject("E_JWT_GENERATION_FAILED", "Failed to generate JWT: " + e.getMessage(), e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔹 JIRA Ticket(s) if any
✏️ Description
Adds a token generator
Testing