Skip to content

Commit db32b2e

Browse files
authored
Merge pull request #4 from fells-code/cookie-update
Cookie update
2 parents 205f85c + 5a98e12 commit db32b2e

8 files changed

Lines changed: 51 additions & 16 deletions

File tree

packages/express/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/express/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
{
22
"name": "@seamless-auth/express",
3-
"version": "0.0.2-beta.3",
3+
"version": "0.0.2-beta.5",
44
"description": "Express adapter for Seamless Auth passwordless authentication",
55
"license": "MIT",
66
"type": "module",
77
"main": "dist/index.js",
88
"types": "./dist/index.d.ts",
99
"author": "Fells Code LLC",
1010
"scripts": {
11-
"build": "tsup src/index.ts --format esm --out-dir dist --dts --splitting",
11+
"build": "tsup src/index.ts --format esm --out-dir dist --splitting",
1212
"dev": "tsc --watch"
1313
},
1414
"repository": {

packages/express/src/createServer.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { verifySignedAuthResponse } from "./internal/verifySignedAuthResponse";
3737
* ```ts
3838
* app.use("/auth", createSeamlessAuthServer({
3939
* authServerUrl: "https://identifier.seamlessauth.com",
40+
* cookieDomain: "mycompany.com",
4041
* accesscookieName: "sa_access",
4142
* registrationCookieName: "sa_registration",
4243
* refreshCookieName: "sa_refresh",
@@ -45,6 +46,7 @@ import { verifySignedAuthResponse } from "./internal/verifySignedAuthResponse";
4546
*
4647
* @param opts - Configuration options for the Seamless Auth proxy:
4748
* - `authServerUrl` — Base URL of your Seamless Auth instance (required)
49+
* - `cookieDomain` — Domain attribute applied to all auth cookies
4850
* - `accesscookieName` — Name of the session access cookie
4951
* - `registrationCookieName` — Name of the ephemeral registration cookie
5052
* - `refreshCookieName` — Name of the refresh token cookie
@@ -61,14 +63,18 @@ export function createSeamlessAuthServer(
6163

6264
const {
6365
authServerUrl,
66+
cookieDomain = "",
6467
accesscookieName = "seamless-access",
6568
registrationCookieName = "seamless-ephemeral",
6669
refreshCookieName = "seamless-refresh",
6770
preAuthCookieName = "seamless-ephemeral",
6871
} = opts;
6972

7073
const proxy =
71-
(path: string, method: "GET" | "POST" | "PUT" | "DELETE" = "POST") =>
74+
(
75+
path: string,
76+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" = "POST"
77+
) =>
7278
async (req: Request, res: Response) => {
7379
try {
7480
const response = await authFetch(req, `${authServerUrl}/${path}`, {
@@ -84,6 +90,7 @@ export function createSeamlessAuthServer(
8490
r.use(
8591
createEnsureCookiesMiddleware({
8692
authServerUrl,
93+
cookieDomain,
8794
accesscookieName,
8895
registrationCookieName,
8996
refreshCookieName,
@@ -99,6 +106,8 @@ export function createSeamlessAuthServer(
99106
r.post("/otp/verify-email-otp", proxy("otp/verify-email-otp"));
100107
r.post("/login", login);
101108
r.post("/users/update", proxy("users/update"));
109+
r.post("/users/credentials", proxy("users/credentials"));
110+
r.delete("/users/credentials", proxy("users/credentials"));
102111
r.post("/registration/register", register);
103112
r.get("/users/me", me);
104113
r.get("/logout", logout);
@@ -123,7 +132,13 @@ export function createSeamlessAuthServer(
123132
throw new Error("Signature mismatch with data payload");
124133
}
125134

126-
setSessionCookie(res, { sub: data.sub }, data.ttl, preAuthCookieName);
135+
setSessionCookie(
136+
res,
137+
{ sub: data.sub },
138+
cookieDomain,
139+
data.ttl,
140+
preAuthCookieName
141+
);
127142
res.status(204).end();
128143
}
129144

@@ -135,7 +150,13 @@ export function createSeamlessAuthServer(
135150
const data = (await up.json()) as any;
136151
if (!up.ok) return res.status(up.status).json(data);
137152

138-
setSessionCookie(res, { sub: data.sub }, data.ttl, registrationCookieName);
153+
setSessionCookie(
154+
res,
155+
{ sub: data.sub },
156+
cookieDomain,
157+
data.ttl,
158+
registrationCookieName
159+
);
139160
res.status(200).json(data).end();
140161
}
141162

@@ -163,13 +184,15 @@ export function createSeamlessAuthServer(
163184
setSessionCookie(
164185
res,
165186
{ sub: data.sub, roles: data.roles },
187+
cookieDomain,
166188
data.ttl,
167189
accesscookieName
168190
);
169191

170192
setSessionCookie(
171193
res,
172194
{ sub: data.sub, refreshToken: data.refreshToken },
195+
cookieDomain,
173196
data.refreshTtl,
174197
refreshCookieName
175198
);
@@ -192,6 +215,7 @@ export function createSeamlessAuthServer(
192215
setSessionCookie(
193216
res,
194217
{ sub: data.sub, roles: data.roles },
218+
cookieDomain,
195219
data.ttl,
196220
accesscookieName
197221
);
@@ -205,6 +229,7 @@ export function createSeamlessAuthServer(
205229

206230
clearAllCookies(
207231
res,
232+
cookieDomain,
208233
accesscookieName,
209234
registrationCookieName,
210235
refreshCookieName
@@ -218,8 +243,8 @@ export function createSeamlessAuthServer(
218243
});
219244
const data = (await up.json()) as any;
220245

221-
clearSessionCookie(res, preAuthCookieName);
246+
clearSessionCookie(res, cookieDomain, preAuthCookieName);
222247
if (!data.user) return res.status(401).json({ error: "unauthenticated" });
223-
res.json({ user: data.user });
248+
res.json({ user: data.user, credentials: data.credentials });
224249
}
225250
}

packages/express/src/internal/authFetch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import jwt from "jsonwebtoken";
22
import { CookieRequest } from "../middleware/ensureCookies";
33

44
export interface AuthFetchOptions {
5-
method?: "GET" | "POST" | "PUT" | "DELETE";
5+
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
66
body?: any;
77
cookies?: string[];
88
headers?: Record<string, string>;

packages/express/src/internal/cookie.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export interface CookiePayload {
1111
export function setSessionCookie(
1212
res: Response,
1313
payload: CookiePayload,
14+
domain?: string,
1415
ttlSeconds = 300,
1516
name = "sa_session"
1617
) {
@@ -20,6 +21,8 @@ export function setSessionCookie(
2021
throw new Error("Missing required env SEAMLESS_COOKIE_SIGNING_KEY");
2122
}
2223

24+
console.debug("[SeamlessAuth] Domain check... ", domain);
25+
2326
const token = jwt.sign(payload, COOKIE_SECRET, {
2427
algorithm: "HS256",
2528
expiresIn: `${ttlSeconds}s`,
@@ -30,6 +33,7 @@ export function setSessionCookie(
3033
secure: process.env.NODE_ENV === "production",
3134
sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
3235
path: "/",
36+
domain,
3337
maxAge: ttlSeconds * 1000,
3438
});
3539
}
@@ -44,11 +48,13 @@ export function clearSessionCookie(
4448

4549
export function clearAllCookies(
4650
res: Response,
51+
domain: string,
4752
accesscookieName: string,
4853
registrationCookieName: string,
4954
refreshCookieName: string
5055
) {
51-
res.clearCookie(accesscookieName, { path: "/" });
52-
res.clearCookie(registrationCookieName, { path: "/" });
53-
res.clearCookie(refreshCookieName, { path: "/" });
56+
console.debug("[SeamlessAuth] clearing cookies");
57+
res.clearCookie(accesscookieName, { domain, path: "/" });
58+
res.clearCookie(registrationCookieName, { domain, path: "/" });
59+
res.clearCookie(refreshCookieName, { domain, path: "/" });
5460
}

packages/express/src/internal/getSeamlessUser.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import type { Request } from "express";
21
import { authFetch } from "./authFetch.js";
3-
import { verifySignedAuthResponse } from "./verifySignedAuthResponse.js";
42
import { CookieRequest } from "../middleware/ensureCookies.js";
53
import { verifyCookieJwt } from "./verifyCookieJwt.js";
64

packages/express/src/middleware/ensureCookies.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ export function createEnsureCookiesMiddleware(opts: SeamlessAuthServerOptions) {
4141
req: CookieRequest,
4242
res: Response,
4343
next: NextFunction,
44-
cookieDomain = ""
44+
cookieDomain = opts.cookieDomain || ""
4545
) {
46+
console.debug("[SeamlessAuth] Ensuring cookies domain...", cookieDomain);
4647
const match = Object.entries(COOKIE_REQUIREMENTS).find(([path]) =>
4748
req.path.startsWith(path)
4849
);
@@ -65,6 +66,7 @@ export function createEnsureCookiesMiddleware(opts: SeamlessAuthServerOptions) {
6566
if (!refreshed?.token) {
6667
clearAllCookies(
6768
res,
69+
cookieDomain,
6870
name,
6971
opts.registrationCookieName!,
7072
opts.refreshCookieName!
@@ -81,13 +83,15 @@ export function createEnsureCookiesMiddleware(opts: SeamlessAuthServerOptions) {
8183
token: refreshed.token,
8284
roles: refreshed.roles,
8385
},
86+
cookieDomain,
8487
refreshed.ttl,
8588
name
8689
);
8790

8891
setSessionCookie(
8992
res,
9093
{ sub: refreshed.sub, refreshToken: refreshed.refreshToken },
94+
cookieDomain,
9195
refreshed.refreshTtl,
9296
opts.refreshCookieName!
9397
);

packages/express/src/middleware/requireAuth.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,15 @@ export function requireAuth(
126126
token: refreshed.token,
127127
roles: refreshed.roles,
128128
},
129+
cookieDomain,
129130
refreshed.ttl,
130131
cookieName
131132
);
132133

133134
setSessionCookie(
134135
res,
135136
{ sub: refreshed.sub, refreshToken: refreshed.refreshToken },
137+
req.hostname,
136138
refreshed.refreshTtl,
137139
refreshCookieName
138140
);

0 commit comments

Comments
 (0)