@poly-x/next 0.1.0-alpha.8 → 0.1.0-alpha.9
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/dist/proxy.cjs +1 -1
- package/dist/proxy.mjs +1 -1
- package/dist/{server-session-B3zJ7CS8.mjs → server-session-CXVB1Rgx.mjs} +18 -8
- package/dist/{server-session-YbnXBt3c.cjs → server-session-DmR0ZJqP.cjs} +18 -8
- package/dist/server.cjs +40 -10
- package/dist/server.d.cts +14 -0
- package/dist/server.d.mts +14 -0
- package/dist/server.mjs +40 -10
- package/dist/styles.css +57 -0
- package/package.json +3 -3
package/dist/proxy.cjs
CHANGED
package/dist/proxy.mjs
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { SessionExpiredError, SessionRevokedError } from "@poly-x/core";
|
|
2
2
|
//#region src/cookie-adapter.ts
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Attributes for the session cookie (ADR-0004 secure custody). `secure` is decided at
|
|
5
|
+
* write time from the actual transport: a `Secure` cookie is silently dropped by the
|
|
6
|
+
* browser over plain http, so http/localhost dev must set `secure:false` while https
|
|
7
|
+
* always sets `secure:true`. This is not a downgrade — `Secure` carries no meaning on
|
|
8
|
+
* http; setting it there just breaks the session. httpOnly/sameSite/path are unchanged.
|
|
9
|
+
*/
|
|
10
|
+
function buildSessionCookieOptions(secure) {
|
|
11
|
+
return {
|
|
12
|
+
httpOnly: true,
|
|
13
|
+
secure,
|
|
14
|
+
sameSite: "lax",
|
|
15
|
+
path: "/"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
10
18
|
//#endregion
|
|
11
19
|
//#region src/cookie-codec.ts
|
|
12
20
|
const IV_BYTES = 12;
|
|
@@ -69,11 +77,13 @@ var ServerSession = class {
|
|
|
69
77
|
secret;
|
|
70
78
|
cookies;
|
|
71
79
|
cookieName;
|
|
80
|
+
secure;
|
|
72
81
|
constructor(options) {
|
|
73
82
|
this.authClient = options.authClient;
|
|
74
83
|
this.secret = options.secret;
|
|
75
84
|
this.cookies = options.cookies;
|
|
76
85
|
this.cookieName = options.cookieName ?? "polyx_session";
|
|
86
|
+
this.secure = options.secure ?? true;
|
|
77
87
|
}
|
|
78
88
|
async establishFromCode(code, codeVerifier, redirectUri) {
|
|
79
89
|
const stored = await this.authClient.exchangeCode({
|
|
@@ -110,7 +120,7 @@ var ServerSession = class {
|
|
|
110
120
|
}
|
|
111
121
|
async write(session) {
|
|
112
122
|
const sealed = await sealSession(session, this.secret);
|
|
113
|
-
this.cookies.set(this.cookieName, sealed,
|
|
123
|
+
this.cookies.set(this.cookieName, sealed, buildSessionCookieOptions(this.secure));
|
|
114
124
|
}
|
|
115
125
|
};
|
|
116
126
|
function toAuthContext(session) {
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
let _poly_x_core = require("@poly-x/core");
|
|
2
2
|
//#region src/cookie-adapter.ts
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Attributes for the session cookie (ADR-0004 secure custody). `secure` is decided at
|
|
5
|
+
* write time from the actual transport: a `Secure` cookie is silently dropped by the
|
|
6
|
+
* browser over plain http, so http/localhost dev must set `secure:false` while https
|
|
7
|
+
* always sets `secure:true`. This is not a downgrade — `Secure` carries no meaning on
|
|
8
|
+
* http; setting it there just breaks the session. httpOnly/sameSite/path are unchanged.
|
|
9
|
+
*/
|
|
10
|
+
function buildSessionCookieOptions(secure) {
|
|
11
|
+
return {
|
|
12
|
+
httpOnly: true,
|
|
13
|
+
secure,
|
|
14
|
+
sameSite: "lax",
|
|
15
|
+
path: "/"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
10
18
|
//#endregion
|
|
11
19
|
//#region src/cookie-codec.ts
|
|
12
20
|
const IV_BYTES = 12;
|
|
@@ -69,11 +77,13 @@ var ServerSession = class {
|
|
|
69
77
|
secret;
|
|
70
78
|
cookies;
|
|
71
79
|
cookieName;
|
|
80
|
+
secure;
|
|
72
81
|
constructor(options) {
|
|
73
82
|
this.authClient = options.authClient;
|
|
74
83
|
this.secret = options.secret;
|
|
75
84
|
this.cookies = options.cookies;
|
|
76
85
|
this.cookieName = options.cookieName ?? "polyx_session";
|
|
86
|
+
this.secure = options.secure ?? true;
|
|
77
87
|
}
|
|
78
88
|
async establishFromCode(code, codeVerifier, redirectUri) {
|
|
79
89
|
const stored = await this.authClient.exchangeCode({
|
|
@@ -110,7 +120,7 @@ var ServerSession = class {
|
|
|
110
120
|
}
|
|
111
121
|
async write(session) {
|
|
112
122
|
const sealed = await sealSession(session, this.secret);
|
|
113
|
-
this.cookies.set(this.cookieName, sealed,
|
|
123
|
+
this.cookies.set(this.cookieName, sealed, buildSessionCookieOptions(this.secure));
|
|
114
124
|
}
|
|
115
125
|
};
|
|
116
126
|
function toAuthContext(session) {
|
package/dist/server.cjs
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_server_session = require("./server-session-
|
|
2
|
+
const require_server_session = require("./server-session-DmR0ZJqP.cjs");
|
|
3
3
|
let _poly_x_core = require("@poly-x/core");
|
|
4
4
|
let next_headers = require("next/headers");
|
|
5
5
|
//#region src/config.ts
|
|
6
|
+
/** Parse a boolean-ish env var; undefined when unset/unrecognized (→ auto-derive). */
|
|
7
|
+
function parseBoolEnv(value) {
|
|
8
|
+
if (value === void 0) return void 0;
|
|
9
|
+
const v = value.trim().toLowerCase();
|
|
10
|
+
if (v === "true" || v === "1") return true;
|
|
11
|
+
if (v === "false" || v === "0") return false;
|
|
12
|
+
}
|
|
6
13
|
function resolveNextConfig(overrides = {}) {
|
|
7
14
|
const publishableKey = overrides.publishableKey ?? process.env.NEXT_PUBLIC_POLYX_PUBLISHABLE_KEY;
|
|
8
15
|
const secret = overrides.secret ?? process.env.POLYX_SESSION_SECRET;
|
|
@@ -12,7 +19,8 @@ function resolveNextConfig(overrides = {}) {
|
|
|
12
19
|
publishableKey,
|
|
13
20
|
secret,
|
|
14
21
|
baseUrl: overrides.baseUrl ?? process.env.POLYX_BASE_URL,
|
|
15
|
-
signInUrl: overrides.signInUrl ?? process.env.NEXT_PUBLIC_POLYX_SIGN_IN_URL
|
|
22
|
+
signInUrl: overrides.signInUrl ?? process.env.NEXT_PUBLIC_POLYX_SIGN_IN_URL,
|
|
23
|
+
cookieSecure: overrides.cookieSecure ?? parseBoolEnv(process.env.POLYX_COOKIE_SECURE)
|
|
16
24
|
};
|
|
17
25
|
}
|
|
18
26
|
function buildServerAuthClient(config) {
|
|
@@ -48,6 +56,22 @@ function adapt(store) {
|
|
|
48
56
|
async function requestCookies() {
|
|
49
57
|
return adapt(await (0, next_headers.cookies)());
|
|
50
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Decide the cookie `Secure` attribute for this request. An explicit `cookieSecure`
|
|
61
|
+
* (from `POLYX_COOKIE_SECURE` or code) wins; otherwise derive from the transport —
|
|
62
|
+
* `x-forwarded-proto` (proxied TLS) then the request URL — and fail secure if unknown.
|
|
63
|
+
* A Secure cookie is dropped by the browser over http, so http/localhost must be false.
|
|
64
|
+
*/
|
|
65
|
+
function resolveCookieSecure(request, config) {
|
|
66
|
+
if (config.cookieSecure !== void 0) return config.cookieSecure;
|
|
67
|
+
const forwarded = request.headers.get("x-forwarded-proto");
|
|
68
|
+
if (forwarded) return forwarded.split(",")[0].trim() === "https";
|
|
69
|
+
try {
|
|
70
|
+
return new URL(request.url).protocol === "https:";
|
|
71
|
+
} catch {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
51
75
|
/** Read the current session — safe in Server Components (no cookie write). */
|
|
52
76
|
async function auth(overrides) {
|
|
53
77
|
const config = resolveNextConfig(overrides);
|
|
@@ -60,16 +84,18 @@ async function auth(overrides) {
|
|
|
60
84
|
function createAuthHandlers(handlersConfig = {}) {
|
|
61
85
|
const callbackPath = handlersConfig.callbackPath ?? "/api/polyx/callback";
|
|
62
86
|
const afterSignInPath = handlersConfig.afterSignInPath ?? "/";
|
|
63
|
-
function newSession(store, config) {
|
|
87
|
+
function newSession(store, config, secure) {
|
|
64
88
|
return new require_server_session.ServerSession({
|
|
65
89
|
authClient: buildServerAuthClient(config),
|
|
66
90
|
secret: config.secret,
|
|
67
|
-
cookies: store
|
|
91
|
+
cookies: store,
|
|
92
|
+
secure
|
|
68
93
|
});
|
|
69
94
|
}
|
|
70
95
|
return {
|
|
71
96
|
async signin(request) {
|
|
72
97
|
const config = resolveNextConfig(handlersConfig);
|
|
98
|
+
const secure = resolveCookieSecure(request, config);
|
|
73
99
|
const redirectUri = `${new URL(request.url).origin}${callbackPath}`;
|
|
74
100
|
const { verifier, challenge } = await (0, _poly_x_core.generatePkce)();
|
|
75
101
|
const state = (0, _poly_x_core.randomState)();
|
|
@@ -79,7 +105,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
79
105
|
redirectUri
|
|
80
106
|
}), {
|
|
81
107
|
httpOnly: true,
|
|
82
|
-
secure
|
|
108
|
+
secure,
|
|
83
109
|
sameSite: "lax",
|
|
84
110
|
path: "/",
|
|
85
111
|
maxAge: VERIFIER_MAX_AGE
|
|
@@ -93,6 +119,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
93
119
|
},
|
|
94
120
|
async authenticate(request) {
|
|
95
121
|
const config = resolveNextConfig(handlersConfig);
|
|
122
|
+
const secure = resolveCookieSecure(request, config);
|
|
96
123
|
const redirectUri = `${new URL(request.url).origin}${callbackPath}`;
|
|
97
124
|
const client = buildServerAuthClient(config);
|
|
98
125
|
let payload;
|
|
@@ -122,7 +149,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
122
149
|
});
|
|
123
150
|
switch (outcome.type) {
|
|
124
151
|
case "authorized":
|
|
125
|
-
await newSession(adapt(await (0, next_headers.cookies)()), config).establishFromCode(outcome.code, verifier, redirectUri);
|
|
152
|
+
await newSession(adapt(await (0, next_headers.cookies)()), config, secure).establishFromCode(outcome.code, verifier, redirectUri);
|
|
126
153
|
return Response.json({
|
|
127
154
|
status: "success",
|
|
128
155
|
redirectTo: afterSignInPath
|
|
@@ -211,6 +238,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
211
238
|
},
|
|
212
239
|
async callback(request) {
|
|
213
240
|
const config = resolveNextConfig(handlersConfig);
|
|
241
|
+
const secure = resolveCookieSecure(request, config);
|
|
214
242
|
const url = new URL(request.url);
|
|
215
243
|
const code = url.searchParams.get("code");
|
|
216
244
|
const state = url.searchParams.get("state");
|
|
@@ -221,17 +249,19 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
221
249
|
if (!code || !state || !raw) return Response.redirect(home, 302);
|
|
222
250
|
const tx = JSON.parse(raw);
|
|
223
251
|
if (tx.state !== state) return Response.redirect(home, 302);
|
|
224
|
-
await newSession(adapt(store), config).establishFromCode(code, tx.verifier, tx.redirectUri);
|
|
252
|
+
await newSession(adapt(store), config, secure).establishFromCode(code, tx.verifier, tx.redirectUri);
|
|
225
253
|
return Response.redirect(home, 302);
|
|
226
254
|
},
|
|
227
|
-
async refresh() {
|
|
255
|
+
async refresh(request) {
|
|
228
256
|
const config = resolveNextConfig(handlersConfig);
|
|
229
|
-
const
|
|
257
|
+
const secure = resolveCookieSecure(request, config);
|
|
258
|
+
const session = await newSession(await requestCookies(), config, secure).refresh();
|
|
230
259
|
return Response.json({ isSignedIn: session !== null }, { status: session ? 200 : 401 });
|
|
231
260
|
},
|
|
232
261
|
async signout(request) {
|
|
233
262
|
const config = resolveNextConfig(handlersConfig);
|
|
234
|
-
|
|
263
|
+
const secure = resolveCookieSecure(request, config);
|
|
264
|
+
newSession(adapt(await (0, next_headers.cookies)()), config, secure).clear();
|
|
235
265
|
try {
|
|
236
266
|
await buildServerAuthClient(config).logout("device");
|
|
237
267
|
} catch {}
|
package/dist/server.d.cts
CHANGED
|
@@ -8,6 +8,13 @@ interface NextServerConfig {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
/** Hosted sign-in page URL the signin route redirects to. */
|
|
10
10
|
signInUrl?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Force the session/verifier cookie `Secure` attribute. Leave undefined (default) to
|
|
13
|
+
* derive it from the request transport (https → true, http/localhost → false). Set via
|
|
14
|
+
* `POLYX_COOKIE_SECURE=true|false` only for edge cases (e.g. a TLS-terminating proxy
|
|
15
|
+
* that doesn't forward `x-forwarded-proto`).
|
|
16
|
+
*/
|
|
17
|
+
cookieSecure?: boolean;
|
|
11
18
|
}
|
|
12
19
|
declare function resolveNextConfig(overrides?: Partial<NextServerConfig>): NextServerConfig;
|
|
13
20
|
//#endregion
|
|
@@ -37,12 +44,19 @@ interface ServerSessionOptions {
|
|
|
37
44
|
secret: string;
|
|
38
45
|
cookies: CookieAdapter;
|
|
39
46
|
cookieName?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Whether to set the `Secure` attribute on the session cookie. Defaults to `true`
|
|
49
|
+
* (fail secure). Handlers derive it from the request transport so http/localhost dev
|
|
50
|
+
* works (a Secure cookie is dropped over http). See buildSessionCookieOptions.
|
|
51
|
+
*/
|
|
52
|
+
secure?: boolean;
|
|
40
53
|
}
|
|
41
54
|
declare class ServerSession {
|
|
42
55
|
private readonly authClient;
|
|
43
56
|
private readonly secret;
|
|
44
57
|
private readonly cookies;
|
|
45
58
|
private readonly cookieName;
|
|
59
|
+
private readonly secure;
|
|
46
60
|
constructor(options: ServerSessionOptions);
|
|
47
61
|
establishFromCode(code: string, codeVerifier: string, redirectUri: string): Promise<StoredSession>;
|
|
48
62
|
read(): Promise<StoredSession | null>;
|
package/dist/server.d.mts
CHANGED
|
@@ -8,6 +8,13 @@ interface NextServerConfig {
|
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
/** Hosted sign-in page URL the signin route redirects to. */
|
|
10
10
|
signInUrl?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Force the session/verifier cookie `Secure` attribute. Leave undefined (default) to
|
|
13
|
+
* derive it from the request transport (https → true, http/localhost → false). Set via
|
|
14
|
+
* `POLYX_COOKIE_SECURE=true|false` only for edge cases (e.g. a TLS-terminating proxy
|
|
15
|
+
* that doesn't forward `x-forwarded-proto`).
|
|
16
|
+
*/
|
|
17
|
+
cookieSecure?: boolean;
|
|
11
18
|
}
|
|
12
19
|
declare function resolveNextConfig(overrides?: Partial<NextServerConfig>): NextServerConfig;
|
|
13
20
|
//#endregion
|
|
@@ -37,12 +44,19 @@ interface ServerSessionOptions {
|
|
|
37
44
|
secret: string;
|
|
38
45
|
cookies: CookieAdapter;
|
|
39
46
|
cookieName?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Whether to set the `Secure` attribute on the session cookie. Defaults to `true`
|
|
49
|
+
* (fail secure). Handlers derive it from the request transport so http/localhost dev
|
|
50
|
+
* works (a Secure cookie is dropped over http). See buildSessionCookieOptions.
|
|
51
|
+
*/
|
|
52
|
+
secure?: boolean;
|
|
40
53
|
}
|
|
41
54
|
declare class ServerSession {
|
|
42
55
|
private readonly authClient;
|
|
43
56
|
private readonly secret;
|
|
44
57
|
private readonly cookies;
|
|
45
58
|
private readonly cookieName;
|
|
59
|
+
private readonly secure;
|
|
46
60
|
constructor(options: ServerSessionOptions);
|
|
47
61
|
establishFromCode(code: string, codeVerifier: string, redirectUri: string): Promise<StoredSession>;
|
|
48
62
|
read(): Promise<StoredSession | null>;
|
package/dist/server.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
import { a as sealSession, i as openSession, n as ServerSession, r as toAuthContext, t as DEFAULT_SESSION_COOKIE } from "./server-session-
|
|
1
|
+
import { a as sealSession, i as openSession, n as ServerSession, r as toAuthContext, t as DEFAULT_SESSION_COOKIE } from "./server-session-CXVB1Rgx.mjs";
|
|
2
2
|
import { AuthClient, FetchTransport, generatePkce, randomState, resolveConfig } from "@poly-x/core";
|
|
3
3
|
import { cookies } from "next/headers";
|
|
4
4
|
//#region src/config.ts
|
|
5
|
+
/** Parse a boolean-ish env var; undefined when unset/unrecognized (→ auto-derive). */
|
|
6
|
+
function parseBoolEnv(value) {
|
|
7
|
+
if (value === void 0) return void 0;
|
|
8
|
+
const v = value.trim().toLowerCase();
|
|
9
|
+
if (v === "true" || v === "1") return true;
|
|
10
|
+
if (v === "false" || v === "0") return false;
|
|
11
|
+
}
|
|
5
12
|
function resolveNextConfig(overrides = {}) {
|
|
6
13
|
const publishableKey = overrides.publishableKey ?? process.env.NEXT_PUBLIC_POLYX_PUBLISHABLE_KEY;
|
|
7
14
|
const secret = overrides.secret ?? process.env.POLYX_SESSION_SECRET;
|
|
@@ -11,7 +18,8 @@ function resolveNextConfig(overrides = {}) {
|
|
|
11
18
|
publishableKey,
|
|
12
19
|
secret,
|
|
13
20
|
baseUrl: overrides.baseUrl ?? process.env.POLYX_BASE_URL,
|
|
14
|
-
signInUrl: overrides.signInUrl ?? process.env.NEXT_PUBLIC_POLYX_SIGN_IN_URL
|
|
21
|
+
signInUrl: overrides.signInUrl ?? process.env.NEXT_PUBLIC_POLYX_SIGN_IN_URL,
|
|
22
|
+
cookieSecure: overrides.cookieSecure ?? parseBoolEnv(process.env.POLYX_COOKIE_SECURE)
|
|
15
23
|
};
|
|
16
24
|
}
|
|
17
25
|
function buildServerAuthClient(config) {
|
|
@@ -47,6 +55,22 @@ function adapt(store) {
|
|
|
47
55
|
async function requestCookies() {
|
|
48
56
|
return adapt(await cookies());
|
|
49
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Decide the cookie `Secure` attribute for this request. An explicit `cookieSecure`
|
|
60
|
+
* (from `POLYX_COOKIE_SECURE` or code) wins; otherwise derive from the transport —
|
|
61
|
+
* `x-forwarded-proto` (proxied TLS) then the request URL — and fail secure if unknown.
|
|
62
|
+
* A Secure cookie is dropped by the browser over http, so http/localhost must be false.
|
|
63
|
+
*/
|
|
64
|
+
function resolveCookieSecure(request, config) {
|
|
65
|
+
if (config.cookieSecure !== void 0) return config.cookieSecure;
|
|
66
|
+
const forwarded = request.headers.get("x-forwarded-proto");
|
|
67
|
+
if (forwarded) return forwarded.split(",")[0].trim() === "https";
|
|
68
|
+
try {
|
|
69
|
+
return new URL(request.url).protocol === "https:";
|
|
70
|
+
} catch {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
50
74
|
/** Read the current session — safe in Server Components (no cookie write). */
|
|
51
75
|
async function auth(overrides) {
|
|
52
76
|
const config = resolveNextConfig(overrides);
|
|
@@ -59,16 +83,18 @@ async function auth(overrides) {
|
|
|
59
83
|
function createAuthHandlers(handlersConfig = {}) {
|
|
60
84
|
const callbackPath = handlersConfig.callbackPath ?? "/api/polyx/callback";
|
|
61
85
|
const afterSignInPath = handlersConfig.afterSignInPath ?? "/";
|
|
62
|
-
function newSession(store, config) {
|
|
86
|
+
function newSession(store, config, secure) {
|
|
63
87
|
return new ServerSession({
|
|
64
88
|
authClient: buildServerAuthClient(config),
|
|
65
89
|
secret: config.secret,
|
|
66
|
-
cookies: store
|
|
90
|
+
cookies: store,
|
|
91
|
+
secure
|
|
67
92
|
});
|
|
68
93
|
}
|
|
69
94
|
return {
|
|
70
95
|
async signin(request) {
|
|
71
96
|
const config = resolveNextConfig(handlersConfig);
|
|
97
|
+
const secure = resolveCookieSecure(request, config);
|
|
72
98
|
const redirectUri = `${new URL(request.url).origin}${callbackPath}`;
|
|
73
99
|
const { verifier, challenge } = await generatePkce();
|
|
74
100
|
const state = randomState();
|
|
@@ -78,7 +104,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
78
104
|
redirectUri
|
|
79
105
|
}), {
|
|
80
106
|
httpOnly: true,
|
|
81
|
-
secure
|
|
107
|
+
secure,
|
|
82
108
|
sameSite: "lax",
|
|
83
109
|
path: "/",
|
|
84
110
|
maxAge: VERIFIER_MAX_AGE
|
|
@@ -92,6 +118,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
92
118
|
},
|
|
93
119
|
async authenticate(request) {
|
|
94
120
|
const config = resolveNextConfig(handlersConfig);
|
|
121
|
+
const secure = resolveCookieSecure(request, config);
|
|
95
122
|
const redirectUri = `${new URL(request.url).origin}${callbackPath}`;
|
|
96
123
|
const client = buildServerAuthClient(config);
|
|
97
124
|
let payload;
|
|
@@ -121,7 +148,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
121
148
|
});
|
|
122
149
|
switch (outcome.type) {
|
|
123
150
|
case "authorized":
|
|
124
|
-
await newSession(adapt(await cookies()), config).establishFromCode(outcome.code, verifier, redirectUri);
|
|
151
|
+
await newSession(adapt(await cookies()), config, secure).establishFromCode(outcome.code, verifier, redirectUri);
|
|
125
152
|
return Response.json({
|
|
126
153
|
status: "success",
|
|
127
154
|
redirectTo: afterSignInPath
|
|
@@ -210,6 +237,7 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
210
237
|
},
|
|
211
238
|
async callback(request) {
|
|
212
239
|
const config = resolveNextConfig(handlersConfig);
|
|
240
|
+
const secure = resolveCookieSecure(request, config);
|
|
213
241
|
const url = new URL(request.url);
|
|
214
242
|
const code = url.searchParams.get("code");
|
|
215
243
|
const state = url.searchParams.get("state");
|
|
@@ -220,17 +248,19 @@ function createAuthHandlers(handlersConfig = {}) {
|
|
|
220
248
|
if (!code || !state || !raw) return Response.redirect(home, 302);
|
|
221
249
|
const tx = JSON.parse(raw);
|
|
222
250
|
if (tx.state !== state) return Response.redirect(home, 302);
|
|
223
|
-
await newSession(adapt(store), config).establishFromCode(code, tx.verifier, tx.redirectUri);
|
|
251
|
+
await newSession(adapt(store), config, secure).establishFromCode(code, tx.verifier, tx.redirectUri);
|
|
224
252
|
return Response.redirect(home, 302);
|
|
225
253
|
},
|
|
226
|
-
async refresh() {
|
|
254
|
+
async refresh(request) {
|
|
227
255
|
const config = resolveNextConfig(handlersConfig);
|
|
228
|
-
const
|
|
256
|
+
const secure = resolveCookieSecure(request, config);
|
|
257
|
+
const session = await newSession(await requestCookies(), config, secure).refresh();
|
|
229
258
|
return Response.json({ isSignedIn: session !== null }, { status: session ? 200 : 401 });
|
|
230
259
|
},
|
|
231
260
|
async signout(request) {
|
|
232
261
|
const config = resolveNextConfig(handlersConfig);
|
|
233
|
-
|
|
262
|
+
const secure = resolveCookieSecure(request, config);
|
|
263
|
+
newSession(adapt(await cookies()), config, secure).clear();
|
|
234
264
|
try {
|
|
235
265
|
await buildServerAuthClient(config).logout("device");
|
|
236
266
|
} catch {}
|
package/dist/styles.css
CHANGED
|
@@ -208,6 +208,13 @@
|
|
|
208
208
|
margin-bottom: 0.75rem;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
/* Branding logo fetched from the app's tokens (FR-BRND). */
|
|
212
|
+
.polyx-signin__brand-logo {
|
|
213
|
+
max-height: 2.25rem;
|
|
214
|
+
width: auto;
|
|
215
|
+
object-fit: contain;
|
|
216
|
+
}
|
|
217
|
+
|
|
211
218
|
.polyx-signin__heading {
|
|
212
219
|
margin: 0;
|
|
213
220
|
font-size: 1.375rem;
|
|
@@ -270,6 +277,56 @@
|
|
|
270
277
|
cursor: not-allowed;
|
|
271
278
|
}
|
|
272
279
|
|
|
280
|
+
/* --- Password reveal toggle --------------------------------------------- */
|
|
281
|
+
|
|
282
|
+
.polyx-signin__input-wrap {
|
|
283
|
+
position: relative;
|
|
284
|
+
display: flex;
|
|
285
|
+
align-items: center;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* Leave room for the reveal button so masked text never slides under it. */
|
|
289
|
+
.polyx-signin__input--has-reveal {
|
|
290
|
+
padding-right: 2.75rem;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.polyx-signin__reveal {
|
|
294
|
+
position: absolute;
|
|
295
|
+
right: 0.25rem;
|
|
296
|
+
display: inline-flex;
|
|
297
|
+
align-items: center;
|
|
298
|
+
justify-content: center;
|
|
299
|
+
width: 2rem;
|
|
300
|
+
height: 2rem;
|
|
301
|
+
padding: 0;
|
|
302
|
+
color: var(--polyx-muted-fg);
|
|
303
|
+
background: transparent;
|
|
304
|
+
border: none;
|
|
305
|
+
border-radius: var(--polyx-radius-sm);
|
|
306
|
+
cursor: pointer;
|
|
307
|
+
transition: color 0.15s ease, box-shadow 0.15s ease;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.polyx-signin__reveal:hover:not(:disabled) {
|
|
311
|
+
color: var(--polyx-fg);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.polyx-signin__reveal:focus-visible {
|
|
315
|
+
outline: none;
|
|
316
|
+
color: var(--polyx-fg);
|
|
317
|
+
box-shadow: 0 0 0 3px var(--polyx-ring);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.polyx-signin__reveal:disabled {
|
|
321
|
+
cursor: not-allowed;
|
|
322
|
+
opacity: 0.6;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.polyx-signin__reveal svg {
|
|
326
|
+
width: 1.125rem;
|
|
327
|
+
height: 1.125rem;
|
|
328
|
+
}
|
|
329
|
+
|
|
273
330
|
/* --- Buttons ------------------------------------------------------------- */
|
|
274
331
|
|
|
275
332
|
.polyx-signin__submit,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poly-x/next",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.9",
|
|
4
4
|
"description": "PolyX SDK for Next.js App Router - components plus server helpers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"module": "./dist/index.mjs",
|
|
48
48
|
"types": "./dist/index.d.cts",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@poly-x/core": "0.1.0-alpha.
|
|
51
|
-
"@poly-x/react": "0.1.0-alpha.
|
|
50
|
+
"@poly-x/core": "0.1.0-alpha.9",
|
|
51
|
+
"@poly-x/react": "0.1.0-alpha.9"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"next": ">=14",
|