nucleus-core-ts 0.9.700 → 0.9.702

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.
@@ -9,6 +9,26 @@ interface MagicLinkToken {
9
9
  tokenHash: string;
10
10
  expiresAt: Date;
11
11
  }
12
+ /**
13
+ * Build the Set-Cookie for the short-lived, single-use OAuth `state` CSRF cookie.
14
+ *
15
+ * Path is ALWAYS `/`, NOT the backend's internal OAuth `basePath`. The cookie is
16
+ * set when the browser starts the flow and must be re-sent on the provider's
17
+ * callback, but the EXTERNAL callback path is decided by the deployment's
18
+ * ingress/proxy (commonly `/api/auth/oauth/<provider>/callback` or
19
+ * `/oauth/<provider>`) and routinely differs from the backend-internal basePath
20
+ * (`/auth/oauth`). A basePath-scoped cookie then silently fails the browser's
21
+ * path match on the callback, the cookie is never attached, and the M6 CSRF
22
+ * check rejects the login with `invalid_state`. `Path=/` makes the cookie
23
+ * round-trip regardless of how the edge remaps the OAuth routes. `SameSite=Lax`
24
+ * is required so the top-level GET redirect back from the IdP still carries it;
25
+ * the cookie stays HttpOnly + single-use, so the wider path does not weaken CSRF.
26
+ */
27
+ export declare function buildOAuthStateCookie(value: string, opts: {
28
+ maxAge: number;
29
+ secure?: boolean;
30
+ domain?: string;
31
+ }): string;
12
32
  export declare function createOAuthRoutes(config: AuthRouteConfig, oauthService: OAuthService, signAccessToken: (userId: string, roles?: string[], claims?: string[], tenant?: string) => string, signRefreshToken: (userId: string) => string, createSession: (params: CreateSessionParams) => Promise<string>, saveSessionToDb?: (sessionId: string, params: CreateSessionParams, schemaName?: string) => Promise<{
13
33
  requiresApproval?: boolean;
14
34
  sessionId?: string;
@@ -16,6 +16,16 @@ export type RedisLike = {
16
16
  * Redis-backed store (P3) — works across instances and survives restarts. State
17
17
  * is single-use: consume() deletes the key before returning, so a replayed
18
18
  * callback (or a double-submit) finds nothing.
19
+ *
20
+ * IMPORTANT: store the payload as an OBJECT and let the store layer handle
21
+ * serialization. Do NOT JSON.stringify here / JSON.parse on read. The RedisLike
22
+ * implementations already serialize internally — the direct ioredis store
23
+ * `JSON.stringify`s on write and `JSON.parse`s on read, and the Dapr store's
24
+ * `state.get` AUTO-PARSES JSON strings back into objects. A pre-stringify here
25
+ * therefore round-trips fine on the direct store (double-encode cancels out) but
26
+ * breaks on Dapr: `read` returns a parsed OBJECT, so a second `JSON.parse(object)`
27
+ * throws ("[object Object]") and consume returns null → every OAuth login fails
28
+ * with `invalid_state`. Passing the object through works on BOTH backends.
19
29
  */
20
30
  export declare const createRedisOAuthStateStore: (redis: RedisLike) => OAuthStateStore;
21
31
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nucleus-core-ts",
3
- "version": "0.9.700",
3
+ "version": "0.9.702",
4
4
  "description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
5
5
  "author": "Hidayet Can \u00d6zcan <hidayetcan@gmail.com>",
6
6
  "license": "SEE LICENSE IN LICENSE",