@iqauth/sdk 2.6.1 → 2.6.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.
package/README.md CHANGED
@@ -17,6 +17,7 @@ The canonical TypeScript SDK for **IQAuthService** — DispositionIQ's multi-ten
17
17
  - [Install](#install)
18
18
  - [Five-line integration](#five-line-integration)
19
19
  - [Pick your environment](#pick-your-environment)
20
+ - [What's new in 2.6.2](#whats-new-in-262)
20
21
  - [What's new in 2.6.1](#whats-new-in-261)
21
22
  - [What's new in 2.0.3](#whats-new-in-203)
22
23
  - [Browser apps with a backend (recommended)](#browser-apps-with-a-backend-recommended)
@@ -173,6 +174,25 @@ The SDK is not "one auth model for every environment". The safe pattern depends
173
174
 
174
175
  ---
175
176
 
177
+ ## What's new in 2.6.2
178
+
179
+ ### Card grows responsively on desktop (no more phone-sized form)
180
+
181
+ `.iqauth-sdk-card` used to cap at `max-width: 460px` at every viewport,
182
+ which meant a desktop user staring at a 1440px monitor saw a thin mobile
183
+ column floating inside a 720px-wide pane. The cap is now responsive:
184
+
185
+ - mobile (default): **480px**
186
+ - tablet / desktop (`@container ≥ 768px`): **540px**
187
+ - extra-wide (`@container ≥ 1280px`): **580px**
188
+
189
+ Inner header/body padding and the title size also bump up at the desktop
190
+ breakpoint so the form actually fills its half of the split layout. No
191
+ opt-in required — the change applies to every consumer of `<SignIn/>` and
192
+ `<SignUp/>` after upgrading.
193
+
194
+ ---
195
+
176
196
  ## What's new in 2.6.1
177
197
 
178
198
  ### 1. Silent SSO is now opt-in (default off)
@@ -604,6 +624,54 @@ Common codes you'll handle:
604
624
  | Cross-origin call to a sister IQAuth-protected app gets CORS-blocked | Add the caller's origin to the target app's `app_allowed_origins`. Allow up to 60s for the cache to refresh. |
605
625
  | `req.auth` is undefined under Passport | Verify you're reading `req.auth`, not `req.user`. The SDK deliberately uses `req.auth` to avoid Passport collision. |
606
626
  | Hosted sign-in page won't accept your `return_to` | The origin isn't in this app's allowlist. Add it in the admin dashboard. |
627
+ | Server logs `[AUTH-MW] Missing auth credentials` on `GET /api/v1/auth/me` at app boot — **once**, immediately followed by a successful `[OIDC] SSO resume issued code` AND the next `/auth/me` returns 200 | **Benign.** SDK's `bootstrap()` probe. See ["Why does the server log `Missing auth credentials` at startup?"](#why-does-the-server-log-missing-auth-credentials-at-startup) below. |
628
+ | `[AUTH-MW] Missing auth credentials` repeats in a **loop** (warn → resume → token → warn → resume → token …), user can't actually finish login | **NOT benign.** The SDK's callback handler on YOUR app's domain isn't completing the token exchange, so no cookie ever gets set. See ["When the bootstrap loop never ends"](#when-the-bootstrap-loop-never-ends) below — almost always a middleware-ordering bug on the consumer app. |
629
+ | Same `Missing auth credentials` warning on `/api/v1/auth/me` but **no** subsequent `SSO resume issued code` or `/oidc/token` for the same user within ~1s | Real problem — your fetch is dropping cookies. Check `credentials: "include"`, CORS `Access-Control-Allow-Credentials: true`, `SameSite`/`COOKIE_DOMAIN`. |
630
+
631
+ ### Why does the server log `Missing auth credentials` at startup?
632
+
633
+ When `<IQAuthProvider>` mounts, the SDK's `bootstrap()` runs `GET /api/v1/auth/me` once to ask the issuer "do I already have a session on this app?" That call is *defined* to be anonymous when the user has never signed in here yet — there is no `iqauth_at` cookie scoped to your origin yet to send.
634
+
635
+ So the very first request you'll see for a returning user is:
636
+
637
+ ```
638
+ WARN [AUTH-MW] Missing auth credentials GET /api/v1/auth/me origin=https://your-app.com
639
+ INFO [OIDC] SSO resume issued code userId=… clientId=iq_…
640
+ INFO [AuthMetrics] /oidc/token latency
641
+ ```
642
+
643
+ That sequence is the **happy path** for silent SSO: probe → no session here → resume from the issuer's `iq_sso` cookie → exchange code for tokens → cookie now set on your origin → subsequent requests succeed against the cookie. The warning was misleading log severity for a defined-anonymous endpoint, and as of the next IQAuth server release the bootstrap probe on `/auth/me` and `/auth/refresh` is logged at **`debug`** rather than `warn`. Other routes still log at `warn` — so seeing this message on, say, `GET /api/v1/users` remains a real signal that cookies aren't traveling.
644
+
645
+ **If you're on an older IQAuth server and want to silence the noise without an upgrade,** add a server-side log filter on the `[AUTH-MW] Missing auth credentials` line where `route` matches `/api/v1/auth/(me|refresh)`. Don't blanket-mute the message — you'll lose visibility on real CORS/cookie failures.
646
+
647
+ ### When the bootstrap loop never ends
648
+
649
+ If you see `Missing auth credentials` → `SSO resume issued code` → `/oidc/token` happen **on repeat** and the user never actually gets signed in, the issuer side is doing its job perfectly — the failure is on **your** server. The SDK's callback helper at `/api/iqauth/callback` is responsible for taking the `?code=` from the OAuth redirect, POSTing it to `/oidc/token`, and setting the `iqauth_at` cookie on your app's domain. If that handler doesn't run (or returns an error), no cookie ever gets set and the SDK's next bootstrap probe is anonymous again — forever.
650
+
651
+ The single most common cause: **your own auth middleware is intercepting `/api/iqauth/callback` before `attachHelpers()` can handle it.** The OAuth return trip is a fresh GET from the issuer with no `Authorization` header (correctly so — that's the whole point of the callback), so an `app.use(requireAuth)` mounted globally will reject it as 401.
652
+
653
+ Confirm with these signals — if you see *any* of them, this is your bug:
654
+
655
+ - Browser: `GET https://your-app.com/api/iqauth/callback?code=…` returns **401** (or any 4xx other than 302)
656
+ - Browser DevTools → Application → Cookies for your app's domain: **no `iqauth_at` cookie present** after a sign-in attempt
657
+ - Your app's server log shows your **own** auth middleware rejecting `path=/iqauth/callback` or `/api/iqauth/callback` with "missing authorization header"
658
+
659
+ **Fix — pick one:**
660
+
661
+ ```ts
662
+ // ✅ Option 1 (recommended) — mount SDK helpers BEFORE your auth middleware.
663
+ const auth = iqAuth({ publishableKey, secretKey });
664
+ auth.attachHelpers(app); // public: /api/iqauth/{callback,refresh,signout}
665
+ app.use(yourAuthMiddleware); // anything below here requires a session
666
+
667
+ // ✅ Option 2 — exempt /api/iqauth/* from your own auth gate.
668
+ app.use((req, res, next) => {
669
+ if (req.path.startsWith("/api/iqauth/")) return next();
670
+ return yourAuthMiddleware(req, res, next);
671
+ });
672
+ ```
673
+
674
+ After the fix you should see `/api/iqauth/callback` return **302**, a `Set-Cookie: iqauth_at=…` header on the response, the cookie appearing under your app's domain in DevTools, and the next `/api/v1/auth/me` returning 200. The `Missing auth credentials` warning drops to the one harmless boot probe per fresh visitor.
607
675
 
608
676
  ---
609
677
 
package/dist/react.js CHANGED
@@ -2432,7 +2432,7 @@ var SHELL_CSS = `
2432
2432
  box-sizing: border-box;
2433
2433
  }
2434
2434
  .iqauth-sdk-card {
2435
- width: 100%; max-width: 460px;
2435
+ width: 100%; max-width: 480px;
2436
2436
  background: var(--brand-surface, #ffffff);
2437
2437
  border: 1px solid rgba(15,23,42,0.08);
2438
2438
  border-radius: var(--brand-radius, 16px);
@@ -2479,6 +2479,13 @@ var SHELL_CSS = `
2479
2479
  /* 2.6.1 \u2014 Restore 100vh ONLY for the wide side-by-side layout where
2480
2480
  hero+pane need height parity. Embedded narrow uses keep natural height. */
2481
2481
  .iqauth-sdk-pane { padding: 48px 24px; min-height: 100vh; }
2482
+ /* 2.6.2 \u2014 Let the card breathe on desktop. The 480px mobile cap looks
2483
+ phone-sized on a 720px+ pane; bump to 540px and grow the inner padding
2484
+ so the form fills its half of the split layout. */
2485
+ .iqauth-sdk-card { max-width: 540px; }
2486
+ .iqauth-sdk-card-header { padding: 40px 44px 0; }
2487
+ .iqauth-sdk-card-body { padding: 32px 44px 32px; }
2488
+ .iqauth-sdk-card-header h1 { font-size: 26px; }
2482
2489
  .iqauth-sdk-hero {
2483
2490
  display: flex; flex-direction: column; justify-content: space-between;
2484
2491
  padding: clamp(32px, 4vw, 56px); color: #ffffff;
@@ -2500,6 +2507,9 @@ var SHELL_CSS = `
2500
2507
  }
2501
2508
  @container iqauth-sdk (min-width: 1280px) {
2502
2509
  .iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
2510
+ /* 2.6.2 \u2014 Extra-wide screens: card grows once more so the form keeps
2511
+ pace with the hero pane on 1440px+ monitors. */
2512
+ .iqauth-sdk-card { max-width: 580px; }
2503
2513
  }
2504
2514
  `;
2505
2515
  var sdkShellStylesInjected = false;
package/dist/react.mjs CHANGED
@@ -687,7 +687,7 @@ var SHELL_CSS = `
687
687
  box-sizing: border-box;
688
688
  }
689
689
  .iqauth-sdk-card {
690
- width: 100%; max-width: 460px;
690
+ width: 100%; max-width: 480px;
691
691
  background: var(--brand-surface, #ffffff);
692
692
  border: 1px solid rgba(15,23,42,0.08);
693
693
  border-radius: var(--brand-radius, 16px);
@@ -734,6 +734,13 @@ var SHELL_CSS = `
734
734
  /* 2.6.1 \u2014 Restore 100vh ONLY for the wide side-by-side layout where
735
735
  hero+pane need height parity. Embedded narrow uses keep natural height. */
736
736
  .iqauth-sdk-pane { padding: 48px 24px; min-height: 100vh; }
737
+ /* 2.6.2 \u2014 Let the card breathe on desktop. The 480px mobile cap looks
738
+ phone-sized on a 720px+ pane; bump to 540px and grow the inner padding
739
+ so the form fills its half of the split layout. */
740
+ .iqauth-sdk-card { max-width: 540px; }
741
+ .iqauth-sdk-card-header { padding: 40px 44px 0; }
742
+ .iqauth-sdk-card-body { padding: 32px 44px 32px; }
743
+ .iqauth-sdk-card-header h1 { font-size: 26px; }
737
744
  .iqauth-sdk-hero {
738
745
  display: flex; flex-direction: column; justify-content: space-between;
739
746
  padding: clamp(32px, 4vw, 56px); color: #ffffff;
@@ -755,6 +762,9 @@ var SHELL_CSS = `
755
762
  }
756
763
  @container iqauth-sdk (min-width: 1280px) {
757
764
  .iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
765
+ /* 2.6.2 \u2014 Extra-wide screens: card grows once more so the form keeps
766
+ pace with the hero pane on 1440px+ monitors. */
767
+ .iqauth-sdk-card { max-width: 580px; }
758
768
  }
759
769
  `;
760
770
  var sdkShellStylesInjected = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iqauth/sdk",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "TypeScript SDK for IQAuth — the canonical way for all IQ projects to integrate with IQAuthService",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",