@incorta/auth 1.1.1 → 1.3.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 +20 -3
- package/dist/cli.js +30 -2
- package/dist/{config-B-2cbZDV.d.cts → config-CHNLJVau.d.cts} +33 -0
- package/dist/{config-B-2cbZDV.d.ts → config-CHNLJVau.d.ts} +33 -0
- package/dist/express.d.cts +1 -1
- package/dist/express.d.ts +1 -1
- package/dist/index.cjs +47 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -3
- package/dist/index.d.ts +10 -3
- package/dist/index.js +46 -8
- package/dist/index.js.map +1 -1
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/react/index.d.cts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ guide; this is the API surface.
|
|
|
8
8
|
|
|
9
9
|
| Import | What's in it |
|
|
10
10
|
| ----------------------- | ------------------------------------------------------------------- |
|
|
11
|
-
| `@incorta/auth` | `createIncortaAuth`, `registerClient`, `getClient`, `updateClientRedirectUris`, types (`IncortaUser`, `AuthSession`, …) |
|
|
11
|
+
| `@incorta/auth` | `createIncortaAuth`, `registerClient`, `getClient`, `updateClientRedirectUris`, `deleteClient`, types (`IncortaUser`, `AuthSession`, …) |
|
|
12
12
|
| `@incorta/auth/react` | `IncortaAuthProvider`, `useAuth`, `useUser`, `SignedIn`, `SignedOut`, `Protect`, `RedirectToLogin` |
|
|
13
13
|
| `@incorta/auth/express` | `incortaAuth(auth)` middleware, `requireAuth(auth, options?)` |
|
|
14
14
|
| `@incorta/auth/node` | `toNodeHandler(auth)`, `toWebRequest`, `sendWebResponse`, `getNodeSession` |
|
|
@@ -35,7 +35,11 @@ Returns `{ handler, getSession, config }`:
|
|
|
35
35
|
for server code (`user`, `accessToken`, `accessTokenExpiresAt`, `expiresAt`).
|
|
36
36
|
|
|
37
37
|
Config falls back to `INCORTA_URL`, `INCORTA_TENANT`, `INCORTA_CLIENT_ID`,
|
|
38
|
-
`INCORTA_CLIENT_SECRET`, `INCORTA_AUTH_SECRET`, `INCORTA_APP_URL
|
|
38
|
+
`INCORTA_CLIENT_SECRET`, `INCORTA_AUTH_SECRET`, `INCORTA_APP_URL`, and
|
|
39
|
+
`INCORTA_INTERNAL_URL` (split horizon: server-side discovery/token/JWKS calls
|
|
40
|
+
use it when the public `incortaUrl` is not routable from the app — e.g.
|
|
41
|
+
`http://host.docker.internal:8080/incorta` from a local container; the
|
|
42
|
+
authorize redirect and issuer validation stay on the public URL).
|
|
39
43
|
|
|
40
44
|
## Session model
|
|
41
45
|
|
|
@@ -44,6 +48,15 @@ The cookie is an encrypted JWT (JWE `dir`/`A256GCM`, key derived from
|
|
|
44
48
|
claims (`sub`, `name`, `email`, `roles`, `tenant`) + the Incorta access/refresh
|
|
45
49
|
tokens. Nothing is stored server-side.
|
|
46
50
|
|
|
51
|
+
**Embedded (cross-site iframe) mode**: when the app runs inside an iframe on a
|
|
52
|
+
DIFFERENT site, `Lax` cookies are never sent — the login flow loops forever.
|
|
53
|
+
Set `cookies: { sameSite: "none", partitioned: true }` (or env
|
|
54
|
+
`INCORTA_COOKIE_SAMESITE=none` + `INCORTA_COOKIE_PARTITIONED=1`): the auth
|
|
55
|
+
cookies become `SameSite=None; Secure; Partitioned` (CHIPS), which modern
|
|
56
|
+
Chrome allows in third-party iframes with a per-embedder cookie jar. `none`
|
|
57
|
+
forces `Secure` (accepted on trustworthy plain-http origins like
|
|
58
|
+
`*.localhost`); top-level usage keeps working with the same setting.
|
|
59
|
+
|
|
47
60
|
## CLI
|
|
48
61
|
|
|
49
62
|
```bash
|
|
@@ -54,12 +67,16 @@ incorta-auth show --url ... --tenant ... --client <id> --rat <token> [--json]
|
|
|
54
67
|
|
|
55
68
|
incorta-auth update-redirects --url ... --tenant ... --client <id> --rat <token> \
|
|
56
69
|
--redirect <url> [--redirect ...] [--replace] [--json]
|
|
70
|
+
|
|
71
|
+
incorta-auth delete --url ... --tenant ... --client <id> --rat <token>
|
|
57
72
|
```
|
|
58
73
|
|
|
59
74
|
`register` creates the OAuth client via RFC 7591 dynamic registration and
|
|
60
75
|
prints the `.env` entries (keep the registration access token). `show` and
|
|
61
76
|
`update-redirects` manage the registered client's allowed callback URLs —
|
|
62
|
-
adding by default, replacing the whole set with `--replace`.
|
|
77
|
+
adding by default, replacing the whole set with `--replace`. `delete` removes
|
|
78
|
+
the registration (new logins stop immediately; issued sessions live until
|
|
79
|
+
they expire).
|
|
63
80
|
|
|
64
81
|
## Testing
|
|
65
82
|
|
package/dist/cli.js
CHANGED
|
@@ -118,6 +118,19 @@ async function updateClientRedirectUris(options) {
|
|
|
118
118
|
}
|
|
119
119
|
return getClient(options);
|
|
120
120
|
}
|
|
121
|
+
async function deleteClient(options) {
|
|
122
|
+
const { incortaUrl, tenant, clientId, registrationAccessToken, fetchImpl = fetch } = options;
|
|
123
|
+
const response = await fetchImpl(registrationEndpoint(incortaUrl, tenant, clientId), {
|
|
124
|
+
method: "DELETE",
|
|
125
|
+
headers: {
|
|
126
|
+
accept: "application/json",
|
|
127
|
+
authorization: `Bearer ${registrationAccessToken}`
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
await readJson(response, "Deleting the client");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
121
134
|
|
|
122
135
|
// src/cli.ts
|
|
123
136
|
var HELP = `incorta-auth \u2014 IncortaAuth SDK helper
|
|
@@ -135,14 +148,19 @@ Usage:
|
|
|
135
148
|
--redirect <callbackUrl> [--redirect ...] \\
|
|
136
149
|
[--replace] [--json]
|
|
137
150
|
|
|
151
|
+
incorta-auth delete --url <incortaUrl> --tenant <tenant> \\
|
|
152
|
+
--client <clientId> --rat <registrationAccessToken>
|
|
153
|
+
|
|
138
154
|
register Registers an OAuth client in Incorta (RFC 7591 dynamic
|
|
139
155
|
registration) and prints the .env entries your app needs.
|
|
140
156
|
Keep the printed registration access token \u2014 it is the key
|
|
141
|
-
for show/update-redirects later.
|
|
157
|
+
for show/update-redirects/delete later.
|
|
142
158
|
show Prints a registered client's current metadata.
|
|
143
159
|
update-redirects Adds the given callback URLs to the client's allowed set
|
|
144
160
|
(or replaces the whole set with --replace, which is also how
|
|
145
161
|
URLs are removed).
|
|
162
|
+
delete Deletes the client registration. New logins stop
|
|
163
|
+
immediately; sessions already issued live until they expire.
|
|
146
164
|
|
|
147
165
|
Example:
|
|
148
166
|
incorta-auth register \\
|
|
@@ -263,6 +281,15 @@ async function runUpdateRedirects(args) {
|
|
|
263
281
|
console.log(`Redirect URIs ${args.replace ? "replaced" : "updated"}. Current set:`);
|
|
264
282
|
for (const uri of info.redirectUris) console.log(` - ${uri}`);
|
|
265
283
|
}
|
|
284
|
+
async function runDelete(args) {
|
|
285
|
+
await deleteClient({
|
|
286
|
+
incortaUrl: args.url,
|
|
287
|
+
tenant: args.tenant,
|
|
288
|
+
clientId: args.client,
|
|
289
|
+
registrationAccessToken: args.rat
|
|
290
|
+
});
|
|
291
|
+
console.log(`Client ${args.client} deleted.`);
|
|
292
|
+
}
|
|
266
293
|
var COMMANDS = {
|
|
267
294
|
register: { required: ["url", "tenant", "name"], needsRedirect: true, run: runRegister },
|
|
268
295
|
show: { required: ["url", "tenant", "client", "rat"], needsRedirect: false, run: runShow },
|
|
@@ -270,7 +297,8 @@ var COMMANDS = {
|
|
|
270
297
|
required: ["url", "tenant", "client", "rat"],
|
|
271
298
|
needsRedirect: true,
|
|
272
299
|
run: runUpdateRedirects
|
|
273
|
-
}
|
|
300
|
+
},
|
|
301
|
+
delete: { required: ["url", "tenant", "client", "rat"], needsRedirect: false, run: runDelete }
|
|
274
302
|
};
|
|
275
303
|
async function main() {
|
|
276
304
|
const [command, ...rest] = process.argv.slice(2);
|
|
@@ -36,6 +36,16 @@ interface IncortaAuthConfig {
|
|
|
36
36
|
* or `http://localhost:8080/incorta`. Defaults to `INCORTA_URL`.
|
|
37
37
|
*/
|
|
38
38
|
incortaUrl?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Split-horizon override: base URL this SERVER should use to reach Incorta
|
|
41
|
+
* when the public `incortaUrl` is not routable from where the app runs
|
|
42
|
+
* (containers, cluster-internal DNS) — e.g.
|
|
43
|
+
* `http://host.docker.internal:8080/incorta` from a local container. Only
|
|
44
|
+
* server-to-server calls (discovery, token exchange, JWKS) use it; browser
|
|
45
|
+
* redirects and token `iss` validation stay on the public `incortaUrl`.
|
|
46
|
+
* Defaults to `INCORTA_INTERNAL_URL`; unset means no rewrite.
|
|
47
|
+
*/
|
|
48
|
+
internalIncortaUrl?: string;
|
|
39
49
|
/** Incorta tenant name, e.g. `demo`. Defaults to `INCORTA_TENANT`. */
|
|
40
50
|
tenant?: string;
|
|
41
51
|
/** OAuth client id (see `incorta-auth register`). Defaults to `INCORTA_CLIENT_ID`. */
|
|
@@ -75,6 +85,25 @@ interface IncortaAuthConfig {
|
|
|
75
85
|
* @default "auto"
|
|
76
86
|
*/
|
|
77
87
|
secure?: boolean | "auto";
|
|
88
|
+
/**
|
|
89
|
+
* `SameSite` for the session/state cookies. The `"lax"` default is right
|
|
90
|
+
* for top-level apps. Set `"none"` when the app runs inside a CROSS-SITE
|
|
91
|
+
* iframe (e.g. an embedded preview) — Lax cookies are never sent there,
|
|
92
|
+
* which loops the login flow forever. `"none"` forces the `Secure`
|
|
93
|
+
* attribute (browsers require the pair; Chrome still accepts it on
|
|
94
|
+
* trustworthy plain-http origins like `*.localhost`). Defaults to
|
|
95
|
+
* `INCORTA_COOKIE_SAMESITE`.
|
|
96
|
+
* @default "lax"
|
|
97
|
+
*/
|
|
98
|
+
sameSite?: "lax" | "none";
|
|
99
|
+
/**
|
|
100
|
+
* CHIPS: adds the `Partitioned` attribute, giving each embedding
|
|
101
|
+
* top-level site its own cookie jar — what modern Chrome requires for
|
|
102
|
+
* cookies in third-party iframes. Use together with `sameSite: "none"`.
|
|
103
|
+
* Defaults to `INCORTA_COOKIE_PARTITIONED` (`1`/`true`).
|
|
104
|
+
* @default false
|
|
105
|
+
*/
|
|
106
|
+
partitioned?: boolean;
|
|
78
107
|
};
|
|
79
108
|
/**
|
|
80
109
|
* Expose `GET {basePath}/token` returning the raw Incorta access token to the
|
|
@@ -94,6 +123,8 @@ interface IncortaAuthConfig {
|
|
|
94
123
|
}
|
|
95
124
|
interface ResolvedConfig {
|
|
96
125
|
incortaUrl: string;
|
|
126
|
+
/** Server-side fetch base when set (split horizon) — see the config doc. */
|
|
127
|
+
internalIncortaUrl?: string;
|
|
97
128
|
tenant: string;
|
|
98
129
|
clientId: string;
|
|
99
130
|
clientSecret: string;
|
|
@@ -105,6 +136,8 @@ interface ResolvedConfig {
|
|
|
105
136
|
stateCookieName: string;
|
|
106
137
|
sessionMaxAge: number;
|
|
107
138
|
secureCookies: boolean | "auto";
|
|
139
|
+
cookieSameSite: "lax" | "none";
|
|
140
|
+
cookiePartitioned: boolean;
|
|
108
141
|
exposeAccessToken: boolean;
|
|
109
142
|
/** `{incortaUrl}/oauth/{tenant}` — the OIDC issuer for this tenant. */
|
|
110
143
|
issuer: string;
|
|
@@ -36,6 +36,16 @@ interface IncortaAuthConfig {
|
|
|
36
36
|
* or `http://localhost:8080/incorta`. Defaults to `INCORTA_URL`.
|
|
37
37
|
*/
|
|
38
38
|
incortaUrl?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Split-horizon override: base URL this SERVER should use to reach Incorta
|
|
41
|
+
* when the public `incortaUrl` is not routable from where the app runs
|
|
42
|
+
* (containers, cluster-internal DNS) — e.g.
|
|
43
|
+
* `http://host.docker.internal:8080/incorta` from a local container. Only
|
|
44
|
+
* server-to-server calls (discovery, token exchange, JWKS) use it; browser
|
|
45
|
+
* redirects and token `iss` validation stay on the public `incortaUrl`.
|
|
46
|
+
* Defaults to `INCORTA_INTERNAL_URL`; unset means no rewrite.
|
|
47
|
+
*/
|
|
48
|
+
internalIncortaUrl?: string;
|
|
39
49
|
/** Incorta tenant name, e.g. `demo`. Defaults to `INCORTA_TENANT`. */
|
|
40
50
|
tenant?: string;
|
|
41
51
|
/** OAuth client id (see `incorta-auth register`). Defaults to `INCORTA_CLIENT_ID`. */
|
|
@@ -75,6 +85,25 @@ interface IncortaAuthConfig {
|
|
|
75
85
|
* @default "auto"
|
|
76
86
|
*/
|
|
77
87
|
secure?: boolean | "auto";
|
|
88
|
+
/**
|
|
89
|
+
* `SameSite` for the session/state cookies. The `"lax"` default is right
|
|
90
|
+
* for top-level apps. Set `"none"` when the app runs inside a CROSS-SITE
|
|
91
|
+
* iframe (e.g. an embedded preview) — Lax cookies are never sent there,
|
|
92
|
+
* which loops the login flow forever. `"none"` forces the `Secure`
|
|
93
|
+
* attribute (browsers require the pair; Chrome still accepts it on
|
|
94
|
+
* trustworthy plain-http origins like `*.localhost`). Defaults to
|
|
95
|
+
* `INCORTA_COOKIE_SAMESITE`.
|
|
96
|
+
* @default "lax"
|
|
97
|
+
*/
|
|
98
|
+
sameSite?: "lax" | "none";
|
|
99
|
+
/**
|
|
100
|
+
* CHIPS: adds the `Partitioned` attribute, giving each embedding
|
|
101
|
+
* top-level site its own cookie jar — what modern Chrome requires for
|
|
102
|
+
* cookies in third-party iframes. Use together with `sameSite: "none"`.
|
|
103
|
+
* Defaults to `INCORTA_COOKIE_PARTITIONED` (`1`/`true`).
|
|
104
|
+
* @default false
|
|
105
|
+
*/
|
|
106
|
+
partitioned?: boolean;
|
|
78
107
|
};
|
|
79
108
|
/**
|
|
80
109
|
* Expose `GET {basePath}/token` returning the raw Incorta access token to the
|
|
@@ -94,6 +123,8 @@ interface IncortaAuthConfig {
|
|
|
94
123
|
}
|
|
95
124
|
interface ResolvedConfig {
|
|
96
125
|
incortaUrl: string;
|
|
126
|
+
/** Server-side fetch base when set (split horizon) — see the config doc. */
|
|
127
|
+
internalIncortaUrl?: string;
|
|
97
128
|
tenant: string;
|
|
98
129
|
clientId: string;
|
|
99
130
|
clientSecret: string;
|
|
@@ -105,6 +136,8 @@ interface ResolvedConfig {
|
|
|
105
136
|
stateCookieName: string;
|
|
106
137
|
sessionMaxAge: number;
|
|
107
138
|
secureCookies: boolean | "auto";
|
|
139
|
+
cookieSameSite: "lax" | "none";
|
|
140
|
+
cookiePartitioned: boolean;
|
|
108
141
|
exposeAccessToken: boolean;
|
|
109
142
|
/** `{incortaUrl}/oauth/{tenant}` — the OIDC issuer for this tenant. */
|
|
110
143
|
issuer: string;
|
package/dist/express.d.cts
CHANGED
package/dist/express.d.ts
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
IncortaAuthError: () => IncortaAuthError,
|
|
24
24
|
createIncortaAuth: () => createIncortaAuth,
|
|
25
|
+
deleteClient: () => deleteClient,
|
|
25
26
|
getClient: () => getClient,
|
|
26
27
|
registerClient: () => registerClient,
|
|
27
28
|
updateClientRedirectUris: () => updateClientRedirectUris
|
|
@@ -45,6 +46,7 @@ function resolveConfig(input = {}) {
|
|
|
45
46
|
const incortaUrl = stripTrailingSlash(
|
|
46
47
|
required(input.incortaUrl ?? env.INCORTA_URL, "incortaUrl", "INCORTA_URL")
|
|
47
48
|
);
|
|
49
|
+
const internalIncortaUrl = input.internalIncortaUrl ?? env.INCORTA_INTERNAL_URL;
|
|
48
50
|
const tenant = required(input.tenant ?? env.INCORTA_TENANT, "tenant", "INCORTA_TENANT");
|
|
49
51
|
const clientId = required(
|
|
50
52
|
input.clientId ?? env.INCORTA_CLIENT_ID,
|
|
@@ -75,8 +77,18 @@ function resolveConfig(input = {}) {
|
|
|
75
77
|
const appUrl = input.appUrl ?? env.INCORTA_APP_URL;
|
|
76
78
|
const cookieName = input.session?.cookieName ?? "incorta_auth_session";
|
|
77
79
|
const issuer = `${incortaUrl}/oauth/${tenant}`;
|
|
80
|
+
const envSameSite = env.INCORTA_COOKIE_SAMESITE?.toLowerCase();
|
|
81
|
+
const cookieSameSite = input.cookies?.sameSite ?? (envSameSite === "none" || envSameSite === "lax" ? envSameSite : "lax");
|
|
82
|
+
const envPartitioned = env.INCORTA_COOKIE_PARTITIONED?.toLowerCase();
|
|
83
|
+
const cookiePartitioned = input.cookies?.partitioned ?? (envPartitioned === "1" || envPartitioned === "true");
|
|
84
|
+
if (cookiePartitioned && cookieSameSite !== "none") {
|
|
85
|
+
throw new Error(
|
|
86
|
+
'[incorta-auth] `cookies.partitioned` requires `cookies.sameSite: "none"` \u2014 browsers only partition cross-site cookies.'
|
|
87
|
+
);
|
|
88
|
+
}
|
|
78
89
|
return {
|
|
79
90
|
incortaUrl,
|
|
91
|
+
internalIncortaUrl: internalIncortaUrl ? stripTrailingSlash(internalIncortaUrl) : void 0,
|
|
80
92
|
tenant,
|
|
81
93
|
clientId,
|
|
82
94
|
clientSecret,
|
|
@@ -88,6 +100,8 @@ function resolveConfig(input = {}) {
|
|
|
88
100
|
stateCookieName: `${cookieName}_state`,
|
|
89
101
|
sessionMaxAge: input.session?.maxAge ?? 12 * 60 * 60,
|
|
90
102
|
secureCookies: input.cookies?.secure ?? "auto",
|
|
103
|
+
cookieSameSite,
|
|
104
|
+
cookiePartitioned,
|
|
91
105
|
exposeAccessToken: input.exposeAccessToken ?? false,
|
|
92
106
|
issuer,
|
|
93
107
|
discoveryUrl: input.advanced?.discoveryUrl ?? `${issuer}/.well-known/openid-configuration`,
|
|
@@ -129,6 +143,7 @@ function serializeCookie(name, value, options = {}) {
|
|
|
129
143
|
if (options.secure) parts.push("Secure");
|
|
130
144
|
const sameSite = options.sameSite ?? "lax";
|
|
131
145
|
parts.push(`SameSite=${sameSite.charAt(0).toUpperCase()}${sameSite.slice(1)}`);
|
|
146
|
+
if (options.partitioned) parts.push("Partitioned");
|
|
132
147
|
return parts.join("; ");
|
|
133
148
|
}
|
|
134
149
|
function deleteCookie(name, options = {}) {
|
|
@@ -138,14 +153,20 @@ function deleteCookie(name, options = {}) {
|
|
|
138
153
|
// src/core/discovery.ts
|
|
139
154
|
var import_jose = require("jose");
|
|
140
155
|
var endpointsCache = /* @__PURE__ */ new Map();
|
|
156
|
+
function toInternal(config, url) {
|
|
157
|
+
const internal = config.internalIncortaUrl;
|
|
158
|
+
if (!internal || !url.startsWith(config.incortaUrl)) return url;
|
|
159
|
+
return internal + url.slice(config.incortaUrl.length);
|
|
160
|
+
}
|
|
141
161
|
function getEndpoints(config) {
|
|
142
|
-
const
|
|
162
|
+
const cacheKey = `${config.issuer}|${config.internalIncortaUrl ?? ""}`;
|
|
163
|
+
const cached = endpointsCache.get(cacheKey);
|
|
143
164
|
if (cached) return cached;
|
|
144
165
|
const promise = resolve(config).catch((error) => {
|
|
145
|
-
endpointsCache.delete(
|
|
166
|
+
endpointsCache.delete(cacheKey);
|
|
146
167
|
throw error;
|
|
147
168
|
});
|
|
148
|
-
endpointsCache.set(
|
|
169
|
+
endpointsCache.set(cacheKey, promise);
|
|
149
170
|
return promise;
|
|
150
171
|
}
|
|
151
172
|
async function resolve(config) {
|
|
@@ -157,7 +178,7 @@ async function resolve(config) {
|
|
|
157
178
|
};
|
|
158
179
|
let doc = fallback;
|
|
159
180
|
try {
|
|
160
|
-
const response = await config.fetch(config.discoveryUrl, {
|
|
181
|
+
const response = await config.fetch(toInternal(config, config.discoveryUrl), {
|
|
161
182
|
headers: { accept: "application/json" }
|
|
162
183
|
});
|
|
163
184
|
if (response.ok) {
|
|
@@ -171,14 +192,14 @@ async function resolve(config) {
|
|
|
171
192
|
}
|
|
172
193
|
} catch {
|
|
173
194
|
}
|
|
174
|
-
const jwks = config.jwksOverride ?? (0, import_jose.createRemoteJWKSet)(new URL(doc.jwks_uri), {
|
|
195
|
+
const jwks = config.jwksOverride ?? (0, import_jose.createRemoteJWKSet)(new URL(toInternal(config, doc.jwks_uri)), {
|
|
175
196
|
cacheMaxAge: 10 * 60 * 1e3,
|
|
176
197
|
cooldownDuration: 30 * 1e3
|
|
177
198
|
});
|
|
178
199
|
return {
|
|
179
200
|
issuer: doc.issuer,
|
|
180
201
|
authorizationEndpoint: doc.authorization_endpoint,
|
|
181
|
-
tokenEndpoint: doc.token_endpoint,
|
|
202
|
+
tokenEndpoint: toInternal(config, doc.token_endpoint),
|
|
182
203
|
jwks
|
|
183
204
|
};
|
|
184
205
|
}
|
|
@@ -393,8 +414,12 @@ function randomToken() {
|
|
|
393
414
|
function createHandler(config) {
|
|
394
415
|
const sessionCookieOptions = (secure) => ({
|
|
395
416
|
httpOnly: true,
|
|
396
|
-
|
|
397
|
-
|
|
417
|
+
// SameSite=None requires Secure — force the pair even on plain http
|
|
418
|
+
// (Chrome accepts Secure cookies from trustworthy origins like
|
|
419
|
+
// `*.localhost`; real cross-site embedding needs https anyway).
|
|
420
|
+
secure: config.cookieSameSite === "none" ? true : secure,
|
|
421
|
+
sameSite: config.cookieSameSite,
|
|
422
|
+
partitioned: config.cookiePartitioned,
|
|
398
423
|
path: "/"
|
|
399
424
|
});
|
|
400
425
|
async function login(request, url) {
|
|
@@ -697,6 +722,19 @@ async function updateClientRedirectUris(options) {
|
|
|
697
722
|
}
|
|
698
723
|
return getClient(options);
|
|
699
724
|
}
|
|
725
|
+
async function deleteClient(options) {
|
|
726
|
+
const { incortaUrl, tenant, clientId, registrationAccessToken, fetchImpl = fetch } = options;
|
|
727
|
+
const response = await fetchImpl(registrationEndpoint(incortaUrl, tenant, clientId), {
|
|
728
|
+
method: "DELETE",
|
|
729
|
+
headers: {
|
|
730
|
+
accept: "application/json",
|
|
731
|
+
authorization: `Bearer ${registrationAccessToken}`
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
if (!response.ok) {
|
|
735
|
+
await readJson(response, "Deleting the client");
|
|
736
|
+
}
|
|
737
|
+
}
|
|
700
738
|
|
|
701
739
|
// src/index.ts
|
|
702
740
|
function createIncortaAuth(config = {}) {
|
|
@@ -708,6 +746,7 @@ function createIncortaAuth(config = {}) {
|
|
|
708
746
|
0 && (module.exports = {
|
|
709
747
|
IncortaAuthError,
|
|
710
748
|
createIncortaAuth,
|
|
749
|
+
deleteClient,
|
|
711
750
|
getClient,
|
|
712
751
|
registerClient,
|
|
713
752
|
updateClientRedirectUris
|