@seamless-auth/core 0.10.0 → 0.11.0
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 +50 -6
- package/dist/apiContract.d.ts +41 -0
- package/dist/apiContract.d.ts.map +1 -0
- package/dist/apiContract.js +48 -0
- package/dist/apiContract.js.map +1 -0
- package/dist/applyResult.d.ts +100 -0
- package/dist/applyResult.d.ts.map +1 -0
- package/dist/applyResult.js +95 -0
- package/dist/applyResult.js.map +1 -0
- package/dist/authMessaging.d.ts +14 -52
- package/dist/authMessaging.d.ts.map +1 -1
- package/dist/deliverAuthMessage.d.ts +15 -0
- package/dist/deliverAuthMessage.d.ts.map +1 -0
- package/dist/deliverAuthMessage.js +123 -0
- package/dist/deliverAuthMessage.js.map +1 -0
- package/dist/ensureCookies.d.ts +2 -2
- package/dist/ensureCookies.d.ts.map +1 -1
- package/dist/ensureCookies.js +5 -5
- package/dist/ensureCookies.js.map +1 -1
- package/dist/getSeamlessUser.d.ts +9 -8
- package/dist/getSeamlessUser.d.ts.map +1 -1
- package/dist/getSeamlessUser.js.map +1 -1
- package/dist/guards.d.ts +73 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +115 -0
- package/dist/guards.js.map +1 -0
- package/dist/handlers/admin.d.ts +4 -3
- package/dist/handlers/admin.d.ts.map +1 -1
- package/dist/handlers/admin.js +4 -10
- package/dist/handlers/admin.js.map +1 -1
- package/dist/handlers/finishLogin.d.ts +2 -2
- package/dist/handlers/finishLogin.d.ts.map +1 -1
- package/dist/handlers/finishLogin.js +10 -37
- package/dist/handlers/finishLogin.js.map +1 -1
- package/dist/handlers/finishRegister.d.ts +2 -2
- package/dist/handlers/finishRegister.d.ts.map +1 -1
- package/dist/handlers/finishRegister.js +10 -34
- package/dist/handlers/finishRegister.js.map +1 -1
- package/dist/handlers/internalMetrics.d.ts +4 -3
- package/dist/handlers/internalMetrics.d.ts.map +1 -1
- package/dist/handlers/internalMetrics.js +4 -10
- package/dist/handlers/internalMetrics.js.map +1 -1
- package/dist/handlers/login.d.ts +2 -2
- package/dist/handlers/login.d.ts.map +1 -1
- package/dist/handlers/login.js +6 -9
- package/dist/handlers/login.js.map +1 -1
- package/dist/handlers/logout.d.ts.map +1 -1
- package/dist/handlers/logout.js.map +1 -1
- package/dist/handlers/me.d.ts +2 -2
- package/dist/handlers/me.d.ts.map +1 -1
- package/dist/handlers/me.js +1 -1
- package/dist/handlers/me.js.map +1 -1
- package/dist/handlers/oauthHandlers.d.ts +10 -6
- package/dist/handlers/oauthHandlers.d.ts.map +1 -1
- package/dist/handlers/oauthHandlers.js +12 -39
- package/dist/handlers/oauthHandlers.js.map +1 -1
- package/dist/handlers/pollMagicLinkConfirmationHandler.d.ts +2 -2
- package/dist/handlers/pollMagicLinkConfirmationHandler.d.ts.map +1 -1
- package/dist/handlers/pollMagicLinkConfirmationHandler.js +10 -37
- package/dist/handlers/pollMagicLinkConfirmationHandler.js.map +1 -1
- package/dist/handlers/register.d.ts +2 -2
- package/dist/handlers/register.d.ts.map +1 -1
- package/dist/handlers/register.js +4 -4
- package/dist/handlers/register.js.map +1 -1
- package/dist/handlers/requestMagicLinkHandler.d.ts +2 -2
- package/dist/handlers/requestMagicLinkHandler.d.ts.map +1 -1
- package/dist/handlers/requestMagicLinkHandler.js +4 -4
- package/dist/handlers/requestMagicLinkHandler.js.map +1 -1
- package/dist/handlers/requestOtpHandler.d.ts +2 -2
- package/dist/handlers/requestOtpHandler.d.ts.map +1 -1
- package/dist/handlers/requestOtpHandler.js +4 -4
- package/dist/handlers/requestOtpHandler.js.map +1 -1
- package/dist/handlers/sessions.d.ts +2 -2
- package/dist/handlers/sessions.d.ts.map +1 -1
- package/dist/handlers/sessions.js +2 -1
- package/dist/handlers/sessions.js.map +1 -1
- package/dist/handlers/switchOrganizationHandler.d.ts +2 -2
- package/dist/handlers/switchOrganizationHandler.d.ts.map +1 -1
- package/dist/handlers/switchOrganizationHandler.js +9 -28
- package/dist/handlers/switchOrganizationHandler.js.map +1 -1
- package/dist/handlers/systemConfig.d.ts +2 -2
- package/dist/handlers/systemConfig.d.ts.map +1 -1
- package/dist/handlers/systemConfig.js +4 -3
- package/dist/handlers/systemConfig.js.map +1 -1
- package/dist/handlers/verifyLoginOtpHandler.d.ts +2 -2
- package/dist/handlers/verifyLoginOtpHandler.d.ts.map +1 -1
- package/dist/handlers/verifyLoginOtpHandler.js +10 -37
- package/dist/handlers/verifyLoginOtpHandler.js.map +1 -1
- package/dist/handlers/verifyMagicLinkHandler.d.ts +2 -2
- package/dist/handlers/verifyMagicLinkHandler.d.ts.map +1 -1
- package/dist/handlers/verifyMagicLinkHandler.js +2 -1
- package/dist/handlers/verifyMagicLinkHandler.js.map +1 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +26 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +24 -0
- package/dist/logger.js.map +1 -0
- package/dist/proxyRequest.d.ts +62 -0
- package/dist/proxyRequest.d.ts.map +1 -0
- package/dist/proxyRequest.js +82 -0
- package/dist/proxyRequest.js.map +1 -0
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +8 -2
- package/dist/redaction.js.map +1 -1
- package/dist/refreshAccessToken.d.ts.map +1 -1
- package/dist/refreshAccessToken.js.map +1 -1
- package/dist/result.d.ts +23 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +2 -0
- package/dist/result.js.map +1 -0
- package/dist/upstreamError.d.ts +31 -0
- package/dist/upstreamError.d.ts.map +1 -0
- package/dist/upstreamError.js +49 -0
- package/dist/upstreamError.js.map +1 -0
- package/dist/upstreamSession.d.ts +53 -0
- package/dist/upstreamSession.d.ts.map +1 -0
- package/dist/upstreamSession.js +56 -0
- package/dist/upstreamSession.js.map +1 -0
- package/dist/verifySignedAuthResponse.d.ts.map +1 -1
- package/dist/verifySignedAuthResponse.js +2 -1
- package/dist/verifySignedAuthResponse.js.map +1 -1
- package/package.json +2 -1
- package/dist/scopedRoles.d.ts +0 -3
- package/dist/scopedRoles.d.ts.map +0 -1
- package/dist/scopedRoles.js +0 -39
- package/dist/scopedRoles.js.map +0 -1
package/README.md
CHANGED
|
@@ -82,21 +82,65 @@ Core helpers enforce transitions between these states.
|
|
|
82
82
|
|
|
83
83
|
## Public API (Overview)
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Everything below is available from the package root. The `./handlers/*` subpaths
|
|
86
|
+
remain for direct imports.
|
|
87
|
+
|
|
88
|
+
**Sessions and cookies**
|
|
86
89
|
|
|
87
90
|
- `ensureCookies(...)` – validates and refreshes session cookies
|
|
88
91
|
- `refreshAccessToken(...)` – rotates expired access sessions
|
|
89
92
|
- `verifyCookieJwt(...)` – verifies signed cookie payloads
|
|
90
|
-
- `
|
|
93
|
+
- `verifyRefreshCookie(...)` – verifies a refresh cookie, returning `null` on failure
|
|
94
|
+
- `verifySignedAuthResponse(...)` – verifies an auth API response signature against its JWKS
|
|
91
95
|
- `getSeamlessUser(...)` – resolves the hydrated user, typed as `SeamlessUser | null`
|
|
92
96
|
- `hasScopedRole(...)` – checks scoped role grants such as `admin:read`
|
|
97
|
+
|
|
98
|
+
**Building an adapter**
|
|
99
|
+
|
|
100
|
+
- `applyResult(result, adapter, opts)` – turns a handler result into a response
|
|
101
|
+
- `applyCookies(result, adapter, opts)` – cookie instructions only, for middleware
|
|
102
|
+
- `ResponseAdapter` – the three methods an adapter provides: `setCookie`, `clearCookie`, `send`
|
|
103
|
+
- `proxyRequest(...)` – forwards a request to the auth API and returns its status and body
|
|
104
|
+
- `checkProxyIdentity(...)` – checks a request carries the session a proxied route requires
|
|
105
|
+
- `buildQueryString(...)` / `buildUpstreamUrl(...)` – build an upstream URL
|
|
106
|
+
- `signSessionCookie(...)` / `resolveCookieSameSite(...)` – cookie format and policy
|
|
107
|
+
- `authFetch(...)` – calls the auth API with the adapter's headers and a tolerant `json()`
|
|
108
|
+
|
|
109
|
+
**Auth flow handlers**
|
|
110
|
+
|
|
111
|
+
`loginHandler`, `finishLoginHandler`, `registerHandler`, `finishRegisterHandler`,
|
|
112
|
+
`logoutHandler`, `meHandler`, `requestOtpHandler`, `verifyLoginOtpHandler`,
|
|
113
|
+
`verifyRegistrationOtpHandler`, `requestMagicLinkHandler`, `verifyMagicLinkHandler`,
|
|
114
|
+
`pollMagicLinkConfirmationHandler`, `switchOrganizationHandler`,
|
|
115
|
+
`listOAuthProvidersHandler`, `startOAuthLoginHandler`, `finishOAuthLoginHandler`.
|
|
116
|
+
|
|
117
|
+
**Admin and operations handlers**
|
|
118
|
+
|
|
119
|
+
User, session, auth-event, metrics, and system-config handlers, for example
|
|
120
|
+
`getUsersHandler`, `updateUserHandler`, `listSessionsHandler`,
|
|
121
|
+
`getAuthEventsHandler`, `getDashboardMetricsHandler`, and
|
|
122
|
+
`getAvailableRolesHandler`.
|
|
123
|
+
|
|
124
|
+
**Message delivery**
|
|
125
|
+
|
|
126
|
+
- `deliverAuthMessage(...)` – delivers an auth message through the configured transports
|
|
127
|
+
- `applyExternalDelivery(...)` – delivers the payload on a response body and strips it
|
|
128
|
+
- `stripDelivery(...)` – removes the delivery payload from a body
|
|
129
|
+
|
|
130
|
+
**Auth API contract**
|
|
131
|
+
|
|
132
|
+
- `SERVICE_TOKEN_ISSUER` / `SERVICE_TOKEN_AUDIENCE` – the fixed identity for M2M service tokens
|
|
133
|
+
- `AUTH_DELIVERY_MODE_HEADER` / `EXTERNAL_DELIVERY_MODE` / `EXTERNAL_DELIVERY_HEADERS`
|
|
134
|
+
- `DEV_JWKS_KID` – the fallback key id, which is a misconfiguration to deploy on
|
|
135
|
+
- `createServiceToken(...)` / `buildExternalDeliveryAuthorization(...)` – mint service tokens
|
|
136
|
+
|
|
137
|
+
**Utilities**
|
|
138
|
+
|
|
93
139
|
- `assertSecretStrength(...)` / `assertSecrets(...)` – enforce the minimum secret length
|
|
94
140
|
- `redactSensitiveText(...)` – masks tokens, bearer values, and secrets before logging
|
|
95
|
-
- `listOAuthProvidersHandler(...)` – retrieves public OAuth provider metadata
|
|
96
|
-
- `startOAuthLoginHandler(...)` – starts an OAuth authorization-code login
|
|
97
|
-
- `finishOAuthLoginHandler(...)` – finishes OAuth login and returns cookie instructions
|
|
98
141
|
|
|
99
|
-
|
|
142
|
+
Handlers return **descriptive results**, not HTTP responses. `applyResult` is what
|
|
143
|
+
turns one into a response, and it is the only place that decides how.
|
|
100
144
|
|
|
101
145
|
### Secret strength
|
|
102
146
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Values the auth API defines. Changing one of these is a coordinated change
|
|
3
|
+
* with `seamless-auth-api`, so they live here rather than being written out at
|
|
4
|
+
* each call site, and every adapter reads the same value.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Asks the auth API to return a delivery payload instead of sending the message
|
|
8
|
+
* itself, so the adopter's own transports deliver it.
|
|
9
|
+
*/
|
|
10
|
+
export declare const AUTH_DELIVERY_MODE_HEADER = "x-seamless-auth-delivery-mode";
|
|
11
|
+
export declare const EXTERNAL_DELIVERY_MODE = "external";
|
|
12
|
+
/** Headers that request external delivery, spreadable into an `authFetch` call. */
|
|
13
|
+
export declare const EXTERNAL_DELIVERY_HEADERS: Readonly<Record<string, string>>;
|
|
14
|
+
/**
|
|
15
|
+
* The auth API validates machine-to-machine service tokens against a fixed
|
|
16
|
+
* issuer and audience. These are not the adopter's configured audience, which
|
|
17
|
+
* applies to user tokens: a service token signed with the adopter's audience is
|
|
18
|
+
* rejected.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SERVICE_TOKEN_ISSUER = "seamless-portal-api";
|
|
21
|
+
export declare const SERVICE_TOKEN_AUDIENCE = "seamless-auth";
|
|
22
|
+
/**
|
|
23
|
+
* Fallback JWKS key id. Deploying on it is a misconfiguration, and adapters
|
|
24
|
+
* warn when it is in use.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEV_JWKS_KID = "dev-main";
|
|
27
|
+
/**
|
|
28
|
+
* Subject for the token that authorizes an external-delivery request. It names
|
|
29
|
+
* the caller's role rather than a browser user, because no user is involved:
|
|
30
|
+
* the adapter is telling the API to hand back a payload instead of sending it.
|
|
31
|
+
*/
|
|
32
|
+
export declare const EXTERNAL_DELIVERY_TOKEN_SUBJECT = "seamless-auth-external-delivery";
|
|
33
|
+
export interface ServiceIdentityOptions {
|
|
34
|
+
serviceSecret: string;
|
|
35
|
+
jwksKid?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Mints the `Authorization` value for an external-delivery request.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildExternalDeliveryAuthorization(opts: ServiceIdentityOptions): string;
|
|
41
|
+
//# sourceMappingURL=apiContract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContract.d.ts","sourceRoot":"","sources":["../src/apiContract.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH;;;GAGG;AACH,eAAO,MAAM,yBAAyB,kCAAkC,CAAC;AACzE,eAAO,MAAM,sBAAsB,aAAa,CAAC;AAEjD,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGnE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAC1D,eAAO,MAAM,sBAAsB,kBAAkB,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,YAAY,aAAa,CAAC;AAEvC;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,oCACT,CAAC;AAEpC,MAAM,WAAW,sBAAsB;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,sBAAsB,GAC3B,MAAM,CAQR"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createServiceToken } from "./createServiceToken.js";
|
|
2
|
+
/**
|
|
3
|
+
* Values the auth API defines. Changing one of these is a coordinated change
|
|
4
|
+
* with `seamless-auth-api`, so they live here rather than being written out at
|
|
5
|
+
* each call site, and every adapter reads the same value.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Asks the auth API to return a delivery payload instead of sending the message
|
|
9
|
+
* itself, so the adopter's own transports deliver it.
|
|
10
|
+
*/
|
|
11
|
+
export const AUTH_DELIVERY_MODE_HEADER = "x-seamless-auth-delivery-mode";
|
|
12
|
+
export const EXTERNAL_DELIVERY_MODE = "external";
|
|
13
|
+
/** Headers that request external delivery, spreadable into an `authFetch` call. */
|
|
14
|
+
export const EXTERNAL_DELIVERY_HEADERS = Object.freeze({
|
|
15
|
+
[AUTH_DELIVERY_MODE_HEADER]: EXTERNAL_DELIVERY_MODE,
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* The auth API validates machine-to-machine service tokens against a fixed
|
|
19
|
+
* issuer and audience. These are not the adopter's configured audience, which
|
|
20
|
+
* applies to user tokens: a service token signed with the adopter's audience is
|
|
21
|
+
* rejected.
|
|
22
|
+
*/
|
|
23
|
+
export const SERVICE_TOKEN_ISSUER = "seamless-portal-api";
|
|
24
|
+
export const SERVICE_TOKEN_AUDIENCE = "seamless-auth";
|
|
25
|
+
/**
|
|
26
|
+
* Fallback JWKS key id. Deploying on it is a misconfiguration, and adapters
|
|
27
|
+
* warn when it is in use.
|
|
28
|
+
*/
|
|
29
|
+
export const DEV_JWKS_KID = "dev-main";
|
|
30
|
+
/**
|
|
31
|
+
* Subject for the token that authorizes an external-delivery request. It names
|
|
32
|
+
* the caller's role rather than a browser user, because no user is involved:
|
|
33
|
+
* the adapter is telling the API to hand back a payload instead of sending it.
|
|
34
|
+
*/
|
|
35
|
+
export const EXTERNAL_DELIVERY_TOKEN_SUBJECT = "seamless-auth-external-delivery";
|
|
36
|
+
/**
|
|
37
|
+
* Mints the `Authorization` value for an external-delivery request.
|
|
38
|
+
*/
|
|
39
|
+
export function buildExternalDeliveryAuthorization(opts) {
|
|
40
|
+
return `Bearer ${createServiceToken({
|
|
41
|
+
subject: EXTERNAL_DELIVERY_TOKEN_SUBJECT,
|
|
42
|
+
issuer: SERVICE_TOKEN_ISSUER,
|
|
43
|
+
audience: SERVICE_TOKEN_AUDIENCE,
|
|
44
|
+
serviceSecret: opts.serviceSecret,
|
|
45
|
+
keyId: opts.jwksKid || DEV_JWKS_KID,
|
|
46
|
+
})}`;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=apiContract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiContract.js","sourceRoot":"","sources":["../src/apiContract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,+BAA+B,CAAC;AACzE,MAAM,CAAC,MAAM,sBAAsB,GAAG,UAAU,CAAC;AAEjD,mFAAmF;AACnF,MAAM,CAAC,MAAM,yBAAyB,GACpC,MAAM,CAAC,MAAM,CAAC;IACZ,CAAC,yBAAyB,CAAC,EAAE,sBAAsB;CACpD,CAAC,CAAC;AAEL;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAC1D,MAAM,CAAC,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAEtD;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AAEvC;;;;GAIG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAC1C,iCAAiC,CAAC;AAOpC;;GAEG;AACH,MAAM,UAAU,kCAAkC,CAChD,IAA4B;IAE5B,OAAO,UAAU,kBAAkB,CAAC;QAClC,OAAO,EAAE,+BAA+B;QACxC,MAAM,EAAE,oBAAoB;QAC5B,QAAQ,EAAE,sBAAsB;QAChC,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,KAAK,EAAE,IAAI,CAAC,OAAO,IAAI,YAAY;KACpC,CAAC,EAAE,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { CookiePayload } from "./ensureCookies.js";
|
|
2
|
+
import type { ResultFailure } from "./result.js";
|
|
3
|
+
export type CookieSameSite = "lax" | "none" | "strict";
|
|
4
|
+
export interface CookieSecurityOptions {
|
|
5
|
+
cookieSecret: string;
|
|
6
|
+
cookieDomain?: string;
|
|
7
|
+
cookieSecure?: boolean;
|
|
8
|
+
cookieSameSite?: CookieSameSite;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the effective `SameSite` policy. Shared so the cookie attributes and
|
|
12
|
+
* any policy that keys off `SameSite=None` cannot drift. Browsers reject
|
|
13
|
+
* `SameSite=None` without `Secure`, so the default tracks `secure`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveCookieSameSite(opts: Pick<CookieSecurityOptions, "cookieSecure" | "cookieSameSite">): CookieSameSite;
|
|
16
|
+
export interface SetCookieCommand {
|
|
17
|
+
name: string;
|
|
18
|
+
/** Already signed. Adapters emit it as-is. */
|
|
19
|
+
value: string;
|
|
20
|
+
domain?: string;
|
|
21
|
+
maxAgeSeconds: number;
|
|
22
|
+
/**
|
|
23
|
+
* The same lifetime as `maxAgeSeconds`, as an absolute time.
|
|
24
|
+
*
|
|
25
|
+
* Both are specified so every adapter emits the same header. `Max-Age` wins
|
|
26
|
+
* wherever it is understood; `Expires` is the fallback for clients that do
|
|
27
|
+
* not, which would otherwise treat the cookie as a session cookie. Leaving
|
|
28
|
+
* this to the adapter is how two adapters end up issuing different cookies for
|
|
29
|
+
* the same session.
|
|
30
|
+
*/
|
|
31
|
+
expires: Date;
|
|
32
|
+
httpOnly: boolean;
|
|
33
|
+
secure: boolean;
|
|
34
|
+
sameSite: CookieSameSite;
|
|
35
|
+
path: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ClearCookieCommand {
|
|
38
|
+
name: string;
|
|
39
|
+
domain?: string;
|
|
40
|
+
/**
|
|
41
|
+
* The epoch, which is what tells the browser to drop the cookie. Specified
|
|
42
|
+
* here for the same reason as on the set path: so every adapter emits the
|
|
43
|
+
* same header rather than each picking its own expression of "delete this".
|
|
44
|
+
*/
|
|
45
|
+
expires: Date;
|
|
46
|
+
secure: boolean;
|
|
47
|
+
sameSite: CookieSameSite;
|
|
48
|
+
path: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The three things an adapter has to be able to do with its framework's
|
|
52
|
+
* response. Everything else about turning a handler result into a response,
|
|
53
|
+
* including cookie format and attribute policy, is decided here so adapters do
|
|
54
|
+
* not each reimplement it.
|
|
55
|
+
*/
|
|
56
|
+
export interface ResponseAdapter {
|
|
57
|
+
setCookie(command: SetCookieCommand): void;
|
|
58
|
+
clearCookie(command: ClearCookieCommand): void;
|
|
59
|
+
/** `body` is `undefined` when the response carries none. */
|
|
60
|
+
send(status: number, body: unknown): void;
|
|
61
|
+
}
|
|
62
|
+
export interface SessionCookie {
|
|
63
|
+
name: string;
|
|
64
|
+
value: CookiePayload;
|
|
65
|
+
ttl: number;
|
|
66
|
+
domain?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface AppliableResult extends ResultFailure {
|
|
69
|
+
status: number;
|
|
70
|
+
body?: unknown;
|
|
71
|
+
setCookies?: SessionCookie[];
|
|
72
|
+
clearCookies?: string[];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Signs a session cookie payload. The cookie format is core's, not the
|
|
76
|
+
* adapter's: an adapter that signed differently would mint sessions this
|
|
77
|
+
* package cannot read back.
|
|
78
|
+
*/
|
|
79
|
+
export declare function signSessionCookie(payload: CookiePayload, secret: string, ttlSeconds: number): string;
|
|
80
|
+
/**
|
|
81
|
+
* Writes a result's cookie instructions, without touching the body.
|
|
82
|
+
*
|
|
83
|
+
* Separate from {@link applyResult} for middleware, which has to apply cookies
|
|
84
|
+
* on a request that then continues rather than one that is being answered.
|
|
85
|
+
*
|
|
86
|
+
* Clears run before sets, because a result that does both is replacing a
|
|
87
|
+
* session rather than ending one.
|
|
88
|
+
*/
|
|
89
|
+
export declare function applyCookies(result: Pick<AppliableResult, "setCookies" | "clearCookies">, adapter: Pick<ResponseAdapter, "setCookie" | "clearCookie">, opts: CookieSecurityOptions): void;
|
|
90
|
+
/**
|
|
91
|
+
* Applies a handler result to a response.
|
|
92
|
+
*
|
|
93
|
+
* Cookies are written before the body.
|
|
94
|
+
*
|
|
95
|
+
* A failure carrying `errorBody` is the auth API's own body and goes out
|
|
96
|
+
* untouched; callers read fields off it. A failure carrying `errorCode` is this
|
|
97
|
+
* package's own and is rendered as `{ error, details }`.
|
|
98
|
+
*/
|
|
99
|
+
export declare function applyResult(result: AppliableResult, adapter: ResponseAdapter, opts: CookieSecurityOptions): void;
|
|
100
|
+
//# sourceMappingURL=applyResult.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyResult.d.ts","sourceRoot":"","sources":["../src/applyResult.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,GAAG,gBAAgB,CAAC,GACnE,cAAc,CAGhB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,EAAE,IAAI,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAKD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC3C,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC/C,4DAA4D;IAC5D,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,aAAa,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,aAAa;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAUD;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,YAAY,GAAG,cAAc,CAAC,EAC5D,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,aAAa,CAAC,EAC3D,IAAI,EAAE,qBAAqB,GAC1B,IAAI,CAoCN;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,qBAAqB,GAC1B,IAAI,CAmBN"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import jwt from "jsonwebtoken";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves the effective `SameSite` policy. Shared so the cookie attributes and
|
|
4
|
+
* any policy that keys off `SameSite=None` cannot drift. Browsers reject
|
|
5
|
+
* `SameSite=None` without `Secure`, so the default tracks `secure`.
|
|
6
|
+
*/
|
|
7
|
+
export function resolveCookieSameSite(opts) {
|
|
8
|
+
const secure = opts.cookieSecure ?? true;
|
|
9
|
+
return opts.cookieSameSite ?? (secure ? "none" : "lax");
|
|
10
|
+
}
|
|
11
|
+
/** Any time in the past drops the cookie; the epoch is the conventional one. */
|
|
12
|
+
const COOKIE_EPOCH = new Date(0);
|
|
13
|
+
/**
|
|
14
|
+
* Signs a session cookie payload. The cookie format is core's, not the
|
|
15
|
+
* adapter's: an adapter that signed differently would mint sessions this
|
|
16
|
+
* package cannot read back.
|
|
17
|
+
*/
|
|
18
|
+
export function signSessionCookie(payload, secret, ttlSeconds) {
|
|
19
|
+
return jwt.sign(payload, secret, {
|
|
20
|
+
algorithm: "HS256",
|
|
21
|
+
expiresIn: `${ttlSeconds}s`,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function requireSecret(opts) {
|
|
25
|
+
if (!opts.cookieSecret) {
|
|
26
|
+
throw new Error("Missing cookieSecret");
|
|
27
|
+
}
|
|
28
|
+
return opts.cookieSecret;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Writes a result's cookie instructions, without touching the body.
|
|
32
|
+
*
|
|
33
|
+
* Separate from {@link applyResult} for middleware, which has to apply cookies
|
|
34
|
+
* on a request that then continues rather than one that is being answered.
|
|
35
|
+
*
|
|
36
|
+
* Clears run before sets, because a result that does both is replacing a
|
|
37
|
+
* session rather than ending one.
|
|
38
|
+
*/
|
|
39
|
+
export function applyCookies(result, adapter, opts) {
|
|
40
|
+
const secure = opts.cookieSecure ?? true;
|
|
41
|
+
const sameSite = resolveCookieSameSite(opts);
|
|
42
|
+
if (result.clearCookies?.length) {
|
|
43
|
+
for (const name of result.clearCookies) {
|
|
44
|
+
adapter.clearCookie({
|
|
45
|
+
name,
|
|
46
|
+
domain: opts.cookieDomain,
|
|
47
|
+
expires: COOKIE_EPOCH,
|
|
48
|
+
secure,
|
|
49
|
+
sameSite,
|
|
50
|
+
path: "/",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (result.setCookies?.length) {
|
|
55
|
+
const secret = requireSecret(opts);
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
for (const cookie of result.setCookies) {
|
|
58
|
+
adapter.setCookie({
|
|
59
|
+
name: cookie.name,
|
|
60
|
+
value: signSessionCookie(cookie.value, secret, cookie.ttl),
|
|
61
|
+
domain: cookie.domain,
|
|
62
|
+
maxAgeSeconds: cookie.ttl,
|
|
63
|
+
expires: new Date(now + cookie.ttl * 1000),
|
|
64
|
+
httpOnly: true,
|
|
65
|
+
secure,
|
|
66
|
+
sameSite,
|
|
67
|
+
path: "/",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Applies a handler result to a response.
|
|
74
|
+
*
|
|
75
|
+
* Cookies are written before the body.
|
|
76
|
+
*
|
|
77
|
+
* A failure carrying `errorBody` is the auth API's own body and goes out
|
|
78
|
+
* untouched; callers read fields off it. A failure carrying `errorCode` is this
|
|
79
|
+
* package's own and is rendered as `{ error, details }`.
|
|
80
|
+
*/
|
|
81
|
+
export function applyResult(result, adapter, opts) {
|
|
82
|
+
applyCookies(result, adapter, opts);
|
|
83
|
+
if (result.errorBody !== undefined) {
|
|
84
|
+
adapter.send(result.status, result.errorBody);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (result.errorCode !== undefined) {
|
|
88
|
+
adapter.send(result.status, result.details === undefined
|
|
89
|
+
? { error: result.errorCode }
|
|
90
|
+
: { error: result.errorCode, details: result.details });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
adapter.send(result.status, result.body);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=applyResult.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyResult.js","sourceRoot":"","sources":["../src/applyResult.ts"],"names":[],"mappings":"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"}
|
package/dist/authMessaging.d.ts
CHANGED
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
export interface SmsMessage {
|
|
17
|
-
to: string;
|
|
18
|
-
from?: string;
|
|
19
|
-
body: string;
|
|
20
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* The messaging contract.
|
|
3
|
+
*
|
|
4
|
+
* The wire shapes belong to `@seamless-auth/types`, so they are re-exported rather
|
|
5
|
+
* than declared again: the auth API sends the delivery instruction and this
|
|
6
|
+
* package consumes it, and two definitions of that could drift. The re-export is
|
|
7
|
+
* type-only, so it is erased at compile time and neither zod nor the schema
|
|
8
|
+
* barrel enters the runtime module graph.
|
|
9
|
+
*
|
|
10
|
+
* What stays here is what is genuinely this package's: the transport interfaces,
|
|
11
|
+
* which carry provider implementations, and the adopter-facing configuration.
|
|
12
|
+
*/
|
|
13
|
+
export type { AuthDeliveryInstruction, DeliveryResult, EmailMessage, MessagingChannel, SendMagicLinkEmailInput, SendOtpEmailInput, SendOtpSmsInput, SmsMessage, } from "@seamless-auth/types";
|
|
14
|
+
import type { DeliveryResult, EmailMessage, SendMagicLinkEmailInput, SendOtpEmailInput, SendOtpSmsInput, SmsMessage } from "@seamless-auth/types";
|
|
21
15
|
export interface EmailTransport {
|
|
22
16
|
readonly name: string;
|
|
23
17
|
send(message: EmailMessage): Promise<DeliveryResult>;
|
|
@@ -26,24 +20,6 @@ export interface SmsTransport {
|
|
|
26
20
|
readonly name: string;
|
|
27
21
|
send(message: SmsMessage): Promise<DeliveryResult>;
|
|
28
22
|
}
|
|
29
|
-
export interface SendOtpEmailInput {
|
|
30
|
-
to: string;
|
|
31
|
-
token: string;
|
|
32
|
-
from?: string;
|
|
33
|
-
subject?: string;
|
|
34
|
-
}
|
|
35
|
-
export interface SendOtpSmsInput {
|
|
36
|
-
to: string;
|
|
37
|
-
token: string | number;
|
|
38
|
-
from?: string;
|
|
39
|
-
}
|
|
40
|
-
export interface SendMagicLinkEmailInput {
|
|
41
|
-
to: string;
|
|
42
|
-
magicLinkUrl: string;
|
|
43
|
-
token?: string;
|
|
44
|
-
from?: string;
|
|
45
|
-
subject?: string;
|
|
46
|
-
}
|
|
47
23
|
export interface AuthMessageOverrideContext {
|
|
48
24
|
appName?: string;
|
|
49
25
|
}
|
|
@@ -68,18 +44,4 @@ export interface SeamlessAuthMessagingOptions {
|
|
|
68
44
|
smsFrom?: string;
|
|
69
45
|
};
|
|
70
46
|
}
|
|
71
|
-
export type AuthDeliveryInstruction = {
|
|
72
|
-
kind: "otp_email";
|
|
73
|
-
to: string;
|
|
74
|
-
token: string;
|
|
75
|
-
} | {
|
|
76
|
-
kind: "otp_sms";
|
|
77
|
-
to: string;
|
|
78
|
-
token: string | number;
|
|
79
|
-
} | {
|
|
80
|
-
kind: "magic_link_email";
|
|
81
|
-
to: string;
|
|
82
|
-
token?: string;
|
|
83
|
-
magicLinkUrl: string;
|
|
84
|
-
};
|
|
85
47
|
//# sourceMappingURL=authMessaging.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authMessaging.d.ts","sourceRoot":"","sources":["../src/authMessaging.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"authMessaging.d.ts","sourceRoot":"","sources":["../src/authMessaging.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,YAAY,EACV,uBAAuB,EACvB,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,uBAAuB,EACvB,iBAAiB,EACjB,eAAe,EACf,UAAU,EACX,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,0BAA0B;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,iBAAiB,EACxB,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,0BAA0B,KAChC,YAAY,CAAC;IAClB,MAAM,CAAC,EAAE,CACP,KAAK,EAAE,eAAe,EACtB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,0BAA0B,KAChC,UAAU,CAAC;IAChB,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,uBAAuB,EAC9B,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,0BAA0B,KAChC,YAAY,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAChE,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAC5D,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,QAAQ,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AuthDeliveryInstruction, SeamlessAuthMessagingOptions } from "./authMessaging.js";
|
|
2
|
+
export declare function deliverAuthMessage(messaging: SeamlessAuthMessagingOptions | undefined, delivery: AuthDeliveryInstruction | undefined): Promise<void>;
|
|
3
|
+
export declare function stripDelivery<T extends {
|
|
4
|
+
delivery?: unknown;
|
|
5
|
+
}>(body: T): Omit<T, "delivery">;
|
|
6
|
+
/**
|
|
7
|
+
* Applies external delivery to an upstream response body and returns the body to send on.
|
|
8
|
+
*
|
|
9
|
+
* When messaging is configured the adapter asks the auth API for a delivery payload instead of
|
|
10
|
+
* having the API send the message itself. A missing payload means nobody sent anything, so it is
|
|
11
|
+
* surfaced here: the four endpoints that route through this helper always include `delivery` when
|
|
12
|
+
* the API accepts the request as externally delivered.
|
|
13
|
+
*/
|
|
14
|
+
export declare function applyExternalDelivery(messaging: SeamlessAuthMessagingOptions | undefined, body: unknown): Promise<unknown>;
|
|
15
|
+
//# sourceMappingURL=deliverAuthMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliverAuthMessage.d.ts","sourceRoot":"","sources":["../src/deliverAuthMessage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EAEvB,4BAA4B,EAE7B,MAAM,oBAAoB,CAAC;AA0G5B,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,4BAA4B,GAAG,SAAS,EACnD,QAAQ,EAAE,uBAAuB,GAAG,SAAS,GAC5C,OAAO,CAAC,IAAI,CAAC,CA0Df;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,EAC5D,IAAI,EAAE,CAAC,GACN,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAGrB;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,4BAA4B,GAAG,SAAS,EACnD,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,OAAO,CAAC,CAgBlB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { getSeamlessLogger } from "./logger.js";
|
|
2
|
+
function applyEmailOverride(override, input, defaults, appName) {
|
|
3
|
+
return override ? override(input, defaults, { appName }) : defaults;
|
|
4
|
+
}
|
|
5
|
+
function applySmsOverride(override, input, defaults, appName) {
|
|
6
|
+
return override ? override(input, defaults, { appName }) : defaults;
|
|
7
|
+
}
|
|
8
|
+
function buildOtpEmailMessage(input, messaging) {
|
|
9
|
+
const appName = messaging.defaults?.appName ?? "Seamless Auth";
|
|
10
|
+
return applyEmailOverride(messaging.overrides?.otpEmail, {
|
|
11
|
+
to: input.to,
|
|
12
|
+
token: input.token,
|
|
13
|
+
from: messaging.defaults?.emailFrom,
|
|
14
|
+
subject: `${appName} - Verify your email`,
|
|
15
|
+
}, {
|
|
16
|
+
to: input.to,
|
|
17
|
+
from: messaging.defaults?.emailFrom,
|
|
18
|
+
subject: `${appName} - Verify your email`,
|
|
19
|
+
text: `Verify your account with ${appName}.\n\nYour verification code is: ${input.token}\n\nIf you did not request this code, you can safely ignore this message.`,
|
|
20
|
+
html: `<div><h1>Verify your account with ${appName}</h1><p>Please use the verification code below:</p><p><strong>${input.token}</strong></p><p>If you did not request this code, you can safely ignore this message.</p></div>`,
|
|
21
|
+
}, appName);
|
|
22
|
+
}
|
|
23
|
+
function buildOtpSmsMessage(input, messaging) {
|
|
24
|
+
const appName = messaging.defaults?.appName ?? "Seamless Auth";
|
|
25
|
+
return applySmsOverride(messaging.overrides?.otpSms, {
|
|
26
|
+
to: input.to,
|
|
27
|
+
token: input.token,
|
|
28
|
+
from: messaging.defaults?.smsFrom,
|
|
29
|
+
}, {
|
|
30
|
+
to: input.to,
|
|
31
|
+
from: messaging.defaults?.smsFrom,
|
|
32
|
+
body: `Your ${appName} verification code is: ${input.token}. No one will ever ask you for this code. Do not share it.`,
|
|
33
|
+
}, appName);
|
|
34
|
+
}
|
|
35
|
+
function buildMagicLinkMessage(input, messaging) {
|
|
36
|
+
const appName = messaging.defaults?.appName ?? "Seamless Auth";
|
|
37
|
+
return applyEmailOverride(messaging.overrides?.magicLinkEmail, {
|
|
38
|
+
to: input.to,
|
|
39
|
+
magicLinkUrl: input.magicLinkUrl,
|
|
40
|
+
token: input.token,
|
|
41
|
+
from: messaging.defaults?.emailFrom,
|
|
42
|
+
subject: `${appName} - Your sign-in link`,
|
|
43
|
+
}, {
|
|
44
|
+
to: input.to,
|
|
45
|
+
from: messaging.defaults?.emailFrom,
|
|
46
|
+
subject: `${appName} - Your sign-in link`,
|
|
47
|
+
text: `Use the link below to sign in to ${appName}:\n\n${input.magicLinkUrl}\n\nIf you did not request this email, you can safely ignore it.`,
|
|
48
|
+
html: `<div><h1>Sign in to ${appName}</h1><p>Use the link below to complete sign-in:</p><p><a href="${input.magicLinkUrl}">${input.magicLinkUrl}</a></p><p>If you did not request this email, you can safely ignore it.</p></div>`,
|
|
49
|
+
}, appName);
|
|
50
|
+
}
|
|
51
|
+
export async function deliverAuthMessage(messaging, delivery) {
|
|
52
|
+
if (!messaging || !delivery) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
switch (delivery.kind) {
|
|
56
|
+
case "otp_email":
|
|
57
|
+
if (messaging.handlers?.sendOtpEmail) {
|
|
58
|
+
await messaging.handlers.sendOtpEmail({
|
|
59
|
+
to: delivery.to,
|
|
60
|
+
token: delivery.token,
|
|
61
|
+
from: messaging.defaults?.emailFrom,
|
|
62
|
+
});
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (!messaging.email) {
|
|
66
|
+
throw new Error("Missing email transport for OTP email delivery.");
|
|
67
|
+
}
|
|
68
|
+
await messaging.email.send(buildOtpEmailMessage(delivery, messaging));
|
|
69
|
+
return;
|
|
70
|
+
case "otp_sms":
|
|
71
|
+
if (messaging.handlers?.sendOtpSms) {
|
|
72
|
+
await messaging.handlers.sendOtpSms({
|
|
73
|
+
to: delivery.to,
|
|
74
|
+
token: delivery.token,
|
|
75
|
+
from: messaging.defaults?.smsFrom,
|
|
76
|
+
});
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (!messaging.sms) {
|
|
80
|
+
throw new Error("Missing SMS transport for OTP SMS delivery.");
|
|
81
|
+
}
|
|
82
|
+
await messaging.sms.send(buildOtpSmsMessage(delivery, messaging));
|
|
83
|
+
return;
|
|
84
|
+
case "magic_link_email":
|
|
85
|
+
if (messaging.handlers?.sendMagicLinkEmail) {
|
|
86
|
+
await messaging.handlers.sendMagicLinkEmail({
|
|
87
|
+
to: delivery.to,
|
|
88
|
+
token: delivery.token,
|
|
89
|
+
magicLinkUrl: delivery.magicLinkUrl,
|
|
90
|
+
from: messaging.defaults?.emailFrom,
|
|
91
|
+
});
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!messaging.email) {
|
|
95
|
+
throw new Error("Missing email transport for magic link delivery.");
|
|
96
|
+
}
|
|
97
|
+
await messaging.email.send(buildMagicLinkMessage(delivery, messaging));
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export function stripDelivery(body) {
|
|
102
|
+
const { delivery: _delivery, ...rest } = body;
|
|
103
|
+
return rest;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Applies external delivery to an upstream response body and returns the body to send on.
|
|
107
|
+
*
|
|
108
|
+
* When messaging is configured the adapter asks the auth API for a delivery payload instead of
|
|
109
|
+
* having the API send the message itself. A missing payload means nobody sent anything, so it is
|
|
110
|
+
* surfaced here: the four endpoints that route through this helper always include `delivery` when
|
|
111
|
+
* the API accepts the request as externally delivered.
|
|
112
|
+
*/
|
|
113
|
+
export async function applyExternalDelivery(messaging, body) {
|
|
114
|
+
if (body && typeof body === "object" && "delivery" in body) {
|
|
115
|
+
await deliverAuthMessage(messaging, body.delivery);
|
|
116
|
+
return stripDelivery(body);
|
|
117
|
+
}
|
|
118
|
+
if (messaging) {
|
|
119
|
+
getSeamlessLogger().warn("[SeamlessAuth] External delivery was requested but the auth API returned no delivery payload, so no message was sent. Verify that serviceSecret matches the auth API's API_SERVICE_TOKEN.");
|
|
120
|
+
}
|
|
121
|
+
return body;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=deliverAuthMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliverAuthMessage.js","sourceRoot":"","sources":["../src/deliverAuthMessage.ts"],"names":[],"mappings":"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"}
|
package/dist/ensureCookies.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ResultFailure } from "./result.js";
|
|
1
2
|
export interface EnsureCookiesInput {
|
|
2
3
|
path: string;
|
|
3
4
|
cookies: Record<string, string | undefined>;
|
|
@@ -18,10 +19,9 @@ export interface CookieInstruction {
|
|
|
18
19
|
ttl: number;
|
|
19
20
|
domain?: string;
|
|
20
21
|
}
|
|
21
|
-
export interface EnsureCookiesResult {
|
|
22
|
+
export interface EnsureCookiesResult extends ResultFailure {
|
|
22
23
|
type: "ok" | "error";
|
|
23
24
|
status?: number;
|
|
24
|
-
error?: string;
|
|
25
25
|
user?: {
|
|
26
26
|
sub: string;
|
|
27
27
|
sessionId?: string;
|