Skip to content

[SDK-193] JWT auth example - #73

Open
jferrao-itrbl wants to merge 5 commits into
mainfrom
feature/SDK-193-JWT-auth-example
Open

[SDK-193] JWT auth example#73
jferrao-itrbl wants to merge 5 commits into
mainfrom
feature/SDK-193-JWT-auth-example

Conversation

@jferrao-itrbl

@jferrao-itrbl jferrao-itrbl commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

🎟️ JIRA ticket(s)

🏕 Description

Adds an opt-in JWT auth demo to the Expo plugin example app so a JWT-enabled mobile API key can be exercised the same way as the RN example (SDK-191), without native JWT modules or a backend.

Default login is unchanged: email + a non-JWT API key. JWT is off unless EXPO_PUBLIC_ITERABLE_JWT_ENABLED=true and a real EXPO_PUBLIC_ITERABLE_JWT_SECRET are set in example/.env.local.

When JWT is configured:

  • Iterable.initialize gets authHandler, onJwtError, and retryPolicy { maxRetry: 5, retryInterval: 5, retryBackoff: linear }
  • Login prefetches a JS HS256 JWT ({ email, iat, exp }, 1-day TTL) and calls Iterable.setEmail(email, token)
  • onJwtError / prefetch failure show an Alert with failure reason only (no JWT, authToken, email, userId, userKey, or failedAuthToken)
  • Missing or placeholder secret: no authHandler (match RN)
  • Login may still leave the Login screen (match RN); a failed JWT session means inbox/in-app data does not load

Signer is demo-only (pure JS HMAC-SHA256; Hermes has no SubtleCrypto). Production apps must fetch the token from a backend that holds the secret — EXPO_PUBLIC_* values are inlined into the JS bundle.

Out of scope: plugin pipeline / app.json options, native JWT modules, userId login, plugin README / Zendesk, changelog / version bump (example-only; example/ is not published).

Also ignores local agent tooling dirs (.agent/, .artifacts/, .cursor/, etc.) so they are not committed by accident.

📷 Screenshots

No Login layout changes. JWT failures show a system Alert (JWT authentication failed + reason). Screenshots optional after device verification.

android ios

🧐 Testing

Unit (done on this branch)

  • yarn tsc --noEmit
  • yarn tsc --noEmit -p example
  • yarn lint
  • yarn test — includes signDemoJwt (payload + Node createHmac signature match) and demoAuth (flags, authHandler / retryPolicy / onJwtError, Alert does not include userKey or failedAuthToken)

Default path (JWT off) — iOS and Android

  • Copy example/.envexample/.env.local
  • Set a non-JWT mobile API key; leave JWT vars commented
  • npx expo prebuild --clean and run the example
  • Log in with email — same as today; inbox/in-app load; no JWT Alert

JWT enabled, valid key + secret — iOS and Android

  • Create a JWT-enabled mobile API key (Integrations > API Keys)
  • In .env.local: set that API key, EXPO_PUBLIC_ITERABLE_JWT_ENABLED=true, EXPO_PUBLIC_ITERABLE_JWT_SECRET=<secret>
  • Rebuild / reload
  • Log in — user identified by email; inbox/in-app load
  • Confirm no JWT/token/email/userId in logs or Alerts

JWT failure paths (app must not crash)

  • JWT enabled, secret empty or YOUR_ITERABLE_JWT_SECRET — no authHandler; login may leave Login; inbox/in-app do not load as a JWT session
  • JWT enabled, wrong secret — onJwtError Alert with reason only; UI may still leave Login; inbox/in-app do not load
  • JWT disabled — secret not required; login works with a non-JWT key

📝 Documentation

How have you documented these changes?

  • example/README.md — new JWT authentication (optional) section: env vars (EXPO_PUBLIC_ITERABLE_JWT_ENABLED, EXPO_PUBLIC_ITERABLE_JWT_SECRET, existing API key / email), how to create a JWT-enabled mobile API key, demo-only secret warning (EXPO_PUBLIC_* inlined), and that production authHandler should fetch from a backend
  • example/.env — commented JWT template next to the existing API key / email vars
  • example/src/jwt/demoAuth.tsgetDemoAuthToken comment with a backend fetch stub and DEMO ONLY marking

No plugin README.md, Zendesk, or CHANGELOG.md update (ticket: example docs only; no public plugin options).

jferrao-itrbl and others added 5 commits August 27, 2026 12:59
Enable the Expo example to exercise Iterable JWT login without changing
the default email path or the plugin public API.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep .agent, .cursor, and similar editor/agent folders out of version control.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep local review and design artifacts out of version control.

Co-authored-by: Cursor <cursoragent@cursor.com>
Hermes has no SubtleCrypto, so the Web Crypto signer failed on iOS and Android.

Co-authored-by: Cursor <cursoragent@cursor.com>
Helpers take explicit enabled/secret args so tests do not depend on
inlined EXPO_PUBLIC env. Prefetch failures Alert without PII and skip
setEmail without a token.

Co-authored-by: Cursor <cursoragent@cursor.com>
@jferrao-itrbl
jferrao-itrbl requested a review from a team August 27, 2026 15:59
@jferrao-itrbl
jferrao-itrbl requested a review from a team as a code owner August 27, 2026 15:59
@qltysh

qltysh Bot commented Aug 27, 2026

Copy link
Copy Markdown

Qlty


Coverage Impact

This PR will not change total coverage.

🚦 See full report on Qlty Cloud »

🛟 Help
  • Diff Coverage: Coverage for added or modified lines of code (excludes deleted files). Learn more.

  • Total Coverage: Coverage for the whole repository, calculated as the sum of all File Coverage. Learn more.

  • File Coverage: Covered Lines divided by Covered Lines plus Missed Lines. (Excludes non-executable lines including blank lines and comments.)

    • Indirect Changes: Changes to File Coverage for files that were not modified in this PR. Learn more.

@qltysh

qltysh Bot commented Aug 27, 2026

Copy link
Copy Markdown

❌ 1 blocking issue (1 total)

Tool Category Rule Count
qlty Structure Function with high complexity (count = 22): Login 1

@joaodordio
joaodordio removed the request for review from a team August 27, 2026 16:19
return;
}

config.retryPolicy = {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

JWT mode currently still logs the user’s email.
logReactNativeSdkCalls defaults to true independently of config.logLevel, and the SDK’s setEmail implementation logs setEmail: <email>. This conflicts with the PR’s stated requirement that emails not appear in logs.

Suggest setting config.logReactNativeSdkCalls = false when JWT mode is enabled and cover that configuration in the test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants