@itm-studio/partner-sdk 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +13 -6
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -2177,14 +2177,19 @@ There are two ways to run it:
2177
2177
  | How it runs | Browser redirect to ITM, then a standard authorization-code exchange | `startPartnerAppLogin` and `verifyPartnerAppLogin`, from your server |
2178
2178
  | What you receive | An ID token and an access token issued by ITM (1 hour, no refresh) | `customerUid` and a profile. **No token**: you keep your own session |
2179
2179
  | Partner key used | Only to register the app | On every call |
2180
- | Marketing opt-in | Not offered. Use `createPartnerBrandSubscription` separately | One optional checkbox, recorded with the sign-in |
2180
+ | Marketing opt-in | One optional checkbox on ITM's code and "Continue" screens | One optional checkbox, recorded with the sign-in |
2181
2181
  | Person identifier | The ID token's `sub` claim (equal to the customer UID) | `customerUid` |
2182
2182
 
2183
2183
  Use the hosted sign-in unless you need the form inside your own UI. Both start with an app.
2184
2184
 
2185
2185
  ### Register an app
2186
2186
 
2187
- An app is a public OpenID Connect client for one of your sites. Register it once, from your server:
2187
+ An app is an OpenID Connect client for one of your sites. There are two kinds:
2188
+
2189
+ - **Browser app:** a public client with no secret. `createPartnerBrandApp` registers this kind, and it is all the custom sign-in form needs.
2190
+ - **Server website:** a confidential client whose server keeps a client secret, so tokens never reach the browser. Create it in Backstage under **Manage › Advanced settings › Login with ITM**. Backstage shows the client secret once and can rotate it.
2191
+
2192
+ Register a Browser app once, from your server:
2188
2193
 
2189
2194
  ```typescript
2190
2195
  const { createPartnerBrandApp: app } = await itm.mutation({
@@ -2220,14 +2225,14 @@ Hosted sign-in is standard OpenID Connect, so you do not need this SDK for it, a
2220
2225
 
2221
2226
  - **Discovery:** `${issuer}/.well-known/openid-configuration`. Read the endpoints from it rather than hard-coding paths.
2222
2227
  - **Flow:** authorization code with PKCE. `response_type=code` and `code_challenge_method=S256` are the only values accepted, and PKCE is required.
2223
- - **Client authentication:** none. The app is a public client (`token_endpoint_auth_method: none`) with no secret.
2228
+ - **Client authentication:** a Browser app is a public client with no secret (`token_endpoint_auth_method: none`). A Server website app authenticates with its client secret using `client_secret_basic`.
2224
2229
  - **Scopes:** `openid profile email phone`. Every app gets this fixed set.
2225
2230
  - **ID token:** verify it against the issuer's `jwks_uri`, with `aud` equal to your client ID and the `nonce` you sent. Its `sub` is pairwise: it equals the person's customer UID for your brand.
2226
2231
  - **Profile claims:** read them from the userinfo endpoint with the access token. It returns `name`, `email`, `email_verified`, `phone_number` and `phone_number_verified`, and leaves out any the person does not have. The access token is opaque.
2227
2232
  - **Lifetimes:** authorization codes last 60 seconds; access and ID tokens last 1 hour. There are no refresh tokens (`offline_access` is not supported). When you need new tokens, send the person through the flow again. While their ITM session on the issuer lasts (up to 30 days), a person who already approved your app comes straight back without a prompt.
2228
2233
  - **Revocation** is available. There is no logout endpoint: end your own session.
2229
2234
 
2230
- The person sees your brand's name and logo, gets a code by SMS or email, and approves sharing their name, email address and phone number the first time. They become a contact and are **not** subscribed to marketing.
2235
+ The person sees your brand's name and logo, gets a code by SMS or email, and approves sharing their name, email address and phone number the first time. They become a contact. They are subscribed to your brand's marketing only if they tick the optional, unticked checkbox on ITM's page.
2231
2236
 
2232
2237
  Run the token exchange on your server and keep tokens out of the browser, following the Backend for Frontend pattern ([RFC 10017 §6.1](https://www.rfc-editor.org/rfc/rfc10017.html)). Prefer an OpenID Connect client library that performs the protocol validation. This framework-neutral sketch with `fetch` and [`jose`](https://github.com/panva/jose) shows the main steps; `rotateSession()` represents your framework's session regeneration API and must invalidate the old session ID and return the new session.
2233
2238
 
@@ -2313,6 +2318,8 @@ const authenticatedSession = await rotateSession();
2313
2318
  authenticatedSession.customerUid = payload.sub;
2314
2319
  ```
2315
2320
 
2321
+ The sketch uses a Browser app. With a Server website app, also authenticate the token request with `client_secret_basic` (an `authorization: Basic …` header built from the client ID and client secret) and keep the secret on your server. For a complete server example using `openid-client`, see [`examples/login-with-itm`](https://github.com/itm-studio/demo-events-sdk-integration/tree/main/examples/login-with-itm).
2322
+
2316
2323
  A redirect that comes back with `error=access_denied` means the person cancelled.
2317
2324
  Never use UserInfo claims until its `sub` matches the validated ID token's `sub` ([OpenID Connect Core §5.3.2](https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse)). Persist the pending login before redirecting, expire it after a short interval, and consume it once on callback using your session store's concurrency controls.
2318
2325
 
@@ -2461,7 +2468,7 @@ When the visitor ticks the checkbox from step 2 and you send `marketingConsent:
2461
2468
  - Each opt-in is recorded as new evidence, including repeat opt-ins. Leaving the box unticked records nothing and never unsubscribes anyone.
2462
2469
  - People your brand has blacklisted can still sign in, but an opt-in never subscribes them.
2463
2470
 
2464
- Hosted sign-in does not offer an opt-in. To subscribe someone outside the custom sign-in form, collect consent on your own page and call `createPartnerBrandSubscription`; see the [Partner Brand Subscription Guide](#partner-brand-subscription-guide).
2471
+ Hosted sign-in offers the same optional checkbox on ITM's code and "Continue to {Brand}" screens, and ITM records a ticked box as an opt-in. To subscribe someone outside sign-in, collect consent on your own page and call `createPartnerBrandSubscription`; see the [Partner Brand Subscription Guide](#partner-brand-subscription-guide).
2465
2472
 
2466
2473
  ### What ITM handles
2467
2474
 
@@ -2511,7 +2518,7 @@ For staging or local development:
2511
2518
  ```typescript
2512
2519
  const itm = createITMPartnerClient({
2513
2520
  token: process.env.ITM_PARTNER_TOKEN!,
2514
- baseUrl: "https://staging-api.itm.studio/graphql",
2521
+ baseUrl: "https://staging.itm-api.com/graphql",
2515
2522
  });
2516
2523
  ```
2517
2524
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@itm-studio/partner-sdk",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "TypeScript SDK for the ITM Partner API — typed GraphQL client with zero introspection required",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",