@manta-eu/auth 0.1.10 → 0.2.1
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 +33 -0
- package/dist/custom-app-user-token.d.ts +33 -0
- package/dist/custom-app-user-token.d.ts.map +1 -0
- package/dist/custom-app-user-token.js +65 -0
- package/dist/custom-app-user-token.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +4 -1
- package/dist/token.js.map +1 -1
- package/dist/web.d.ts +1 -0
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +1 -0
- package/dist/web.js.map +1 -1
- package/package.json +3 -2
- package/src/custom-app-user-token.ts +111 -0
- package/src/index.ts +7 -0
- package/src/token.ts +4 -1
- package/src/web.ts +7 -0
package/README.md
CHANGED
|
@@ -117,6 +117,39 @@ const getAccessToken = cachedToken(() => mintWithClientCredentials({ baseUrl, re
|
|
|
117
117
|
|
|
118
118
|
Keep the secret on a server; never ship it to a browser.
|
|
119
119
|
|
|
120
|
+
## Tokens for your app's own users
|
|
121
|
+
|
|
122
|
+
A custom app with machine access gets a token for one of its own users, by the app's id for them, or
|
|
123
|
+
for a visitor it has not identified, by its session id for them. Manta keeps their chats, and no
|
|
124
|
+
memories:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { cachedToken, customAppUserAccessToken } from "@manta-eu/auth/web";
|
|
128
|
+
|
|
129
|
+
// One cached getter per person, so each reuses their token until it nears expiry. Evict idle entries in a real app.
|
|
130
|
+
const tokens = new Map<string, () => Promise<string>>();
|
|
131
|
+
const tokenFor = (userId: string) => {
|
|
132
|
+
let get = tokens.get(userId);
|
|
133
|
+
if (get === undefined) {
|
|
134
|
+
get = cachedToken(() =>
|
|
135
|
+
customAppUserAccessToken({ clientId, clientSecret, userId, name, email, teams: ["/Sales/EU"] }),
|
|
136
|
+
);
|
|
137
|
+
tokens.set(userId, get);
|
|
138
|
+
}
|
|
139
|
+
return get;
|
|
140
|
+
};
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
A visitor works the same way, with `anonymousId` in place of `userId`: a random id you keep for them, such as one in a
|
|
144
|
+
cookie or in your session, following the same rule of 1 to 128 letters, digits or `- _ . @ |`. Give exactly one of the
|
|
145
|
+
two. The same `anonymousId` brings back that visitor's chats, so keep it private.
|
|
146
|
+
|
|
147
|
+
It sends the app's secret, so it runs on the app's server only; the token it returns may go to the
|
|
148
|
+
browser. `datastores` narrows the token to some of the datastores the app reaches. `teams` places
|
|
149
|
+
the person in those teams of the app's organization: an empty list places them in none, and leaving
|
|
150
|
+
it out places them in every team the app reaches. A refusal throws `RefusedRequestError`, whose
|
|
151
|
+
`status` tells `isTransientStatus` whether a retry can help (429, 503) or not (401, 403).
|
|
152
|
+
|
|
120
153
|
## Issuer and discovery
|
|
121
154
|
|
|
122
155
|
`issuerUrl({ baseUrl, realm })` names the realm's issuer, and `discoveryUrl({ baseUrl, realm })` its
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type CustomAppUserProfile } from "@manta-eu/lib/custom-app";
|
|
2
|
+
import { type FetchLike } from "./http.js";
|
|
3
|
+
export type CustomAppUserGrantBase = {
|
|
4
|
+
/** The custom app's client ID and secret, held only by the app's server. */
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string;
|
|
7
|
+
/** Narrows the token to these datastores; leave out to reach every datastore the app reaches. */
|
|
8
|
+
datastores?: string[];
|
|
9
|
+
/**
|
|
10
|
+
* Places the person in these teams of the app's organization, by path like /Sales/EU, as a member of them. An empty
|
|
11
|
+
* list places them in no team; leaving it out places them in every team the app reaches.
|
|
12
|
+
*/
|
|
13
|
+
teams?: string[];
|
|
14
|
+
/** Manta's address, https://app.hiremanta.com unless you name another deployment. */
|
|
15
|
+
apiUrl?: string;
|
|
16
|
+
};
|
|
17
|
+
/** A person your app knows: Manta keeps their chats under your id for them, and no memories. */
|
|
18
|
+
export type IdentifiedCustomAppUser = CustomAppUserGrantBase & CustomAppUserProfile & {
|
|
19
|
+
userId: string;
|
|
20
|
+
anonymousId?: never;
|
|
21
|
+
};
|
|
22
|
+
/** A visitor your app has not identified, by your session id for them: they chat, and Manta keeps no memories. */
|
|
23
|
+
export type AnonymousCustomAppVisitor = CustomAppUserGrantBase & {
|
|
24
|
+
anonymousId: string;
|
|
25
|
+
userId?: never;
|
|
26
|
+
};
|
|
27
|
+
export type CustomAppUserAccessTokenOptions = IdentifiedCustomAppUser | AnonymousCustomAppVisitor;
|
|
28
|
+
/**
|
|
29
|
+
* Gets a Manta access token for one of the app's own users, or for an anonymous visitor. It sends the app's client
|
|
30
|
+
* secret, so call it on the app's server only; the token it returns may go to the browser.
|
|
31
|
+
*/
|
|
32
|
+
export declare function customAppUserAccessToken(options: CustomAppUserAccessTokenOptions, fetchImpl?: FetchLike): Promise<string>;
|
|
33
|
+
//# sourceMappingURL=custom-app-user-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-app-user-token.d.ts","sourceRoot":"","sources":["../src/custom-app-user-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,oBAAoB,EAE1B,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAAE,KAAK,SAAS,EAAyC,MAAM,WAAW,CAAC;AAElF,MAAM,MAAM,sBAAsB,GAAG;IACnC,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,qFAAqF;IACrF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,gGAAgG;AAChG,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,GAC1D,oBAAoB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAEjE,kHAAkH;AAClH,MAAM,MAAM,yBAAyB,GAAG,sBAAsB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAEzG,MAAM,MAAM,+BAA+B,GAAG,uBAAuB,GAAG,yBAAyB,CAAC;AAyBlG;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,+BAA+B,EACxC,SAAS,GAAE,SAAiB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAyCjB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { anonymousVisitorIdName, customAppClientIdProblem, customAppUserDatastoresProblem, customAppUserIdProblem, customAppUserProfileProblem, customAppUserTeamsProblem, customAppUserTokenPath, } from "@manta-eu/lib/custom-app";
|
|
2
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
3
|
+
import { defaultDeployment } from "./default-deployment.js";
|
|
4
|
+
import { postTo, readJson, RefusedRequestError } from "./http.js";
|
|
5
|
+
// Blank ids count as absent, as Manta reads them.
|
|
6
|
+
function isVisitor(options) {
|
|
7
|
+
return isPresent(options.anonymousId);
|
|
8
|
+
}
|
|
9
|
+
function requestFor(options) {
|
|
10
|
+
const { clientId, clientSecret, datastores, teams } = options;
|
|
11
|
+
const narrowed = { ...(datastores === undefined ? {} : { datastores }), ...(teams === undefined ? {} : { teams }) };
|
|
12
|
+
if (isVisitor(options)) {
|
|
13
|
+
return { client_id: clientId, client_secret: clientSecret, anonymous_id: options.anonymousId, ...narrowed };
|
|
14
|
+
}
|
|
15
|
+
const { userId, name, email, fields } = options;
|
|
16
|
+
return {
|
|
17
|
+
client_id: clientId,
|
|
18
|
+
client_secret: clientSecret,
|
|
19
|
+
user_id: userId,
|
|
20
|
+
...(name === undefined ? {} : { name }),
|
|
21
|
+
...(email === undefined ? {} : { email }),
|
|
22
|
+
...(fields === undefined ? {} : { fields }),
|
|
23
|
+
...narrowed,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Gets a Manta access token for one of the app's own users, or for an anonymous visitor. It sends the app's client
|
|
28
|
+
* secret, so call it on the app's server only; the token it returns may go to the browser.
|
|
29
|
+
*/
|
|
30
|
+
export async function customAppUserAccessToken(options, fetchImpl = fetch) {
|
|
31
|
+
if (typeof globalThis.document !== "undefined") {
|
|
32
|
+
throw new Error("customAppUserAccessToken runs on your server only: it sends the app's client secret");
|
|
33
|
+
}
|
|
34
|
+
const clientIdProblem = customAppClientIdProblem(options.clientId);
|
|
35
|
+
if (clientIdProblem !== undefined)
|
|
36
|
+
throw new Error(clientIdProblem);
|
|
37
|
+
if (!isPresent(options.clientSecret))
|
|
38
|
+
throw new Error("The app's client secret is required");
|
|
39
|
+
if (isPresent(options.userId) === isPresent(options.anonymousId)) {
|
|
40
|
+
throw new Error("Give exactly one of userId, for a person your app knows, and anonymousId, for a visitor");
|
|
41
|
+
}
|
|
42
|
+
const problem = (isVisitor(options)
|
|
43
|
+
? customAppUserIdProblem(options.anonymousId, anonymousVisitorIdName)
|
|
44
|
+
: customAppUserIdProblem(options.userId)) ??
|
|
45
|
+
customAppUserDatastoresProblem(options.datastores) ??
|
|
46
|
+
customAppUserTeamsProblem(options.teams) ??
|
|
47
|
+
(isVisitor(options) ? undefined : customAppUserProfileProblem(options));
|
|
48
|
+
if (problem !== undefined)
|
|
49
|
+
throw new Error(problem);
|
|
50
|
+
const endpoint = new URL(customAppUserTokenPath, options.apiUrl ?? defaultDeployment.apiUrl).toString();
|
|
51
|
+
const response = await postTo(endpoint, {
|
|
52
|
+
method: "POST",
|
|
53
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
54
|
+
body: JSON.stringify(requestFor(options)),
|
|
55
|
+
}, fetchImpl);
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const refusal = await readJson(response, endpoint).catch(() => ({}));
|
|
58
|
+
throw new RefusedRequestError(`Manta refused the custom app user token (${response.status}). ${refusal.error_description ?? ""}`.trim(), response.status);
|
|
59
|
+
}
|
|
60
|
+
const body = await readJson(response, endpoint);
|
|
61
|
+
if (typeof body.access_token !== "string")
|
|
62
|
+
throw new Error("Manta answered without an access token");
|
|
63
|
+
return body.access_token;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=custom-app-user-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-app-user-token.js","sourceRoot":"","sources":["../src/custom-app-user-token.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,5 @@ export { cachedToken, mintWithClientCredentials, withRenewal, type ClientCredent
|
|
|
9
9
|
export { discoveryUrl, issuerUrl, type OidcClient, type Realm } from "./oidc.js";
|
|
10
10
|
export { endWebLogin, finishWebLogin, refreshWebLogin, startWebLogin, webLogoutUrl, type StartWebLoginOptions, type WebLoginStart, type WebLogoutOptions, type WebTokens, } from "./web-login.js";
|
|
11
11
|
export { webLoginRoutes, type WebLoginRoutes, type WebLoginRoutesOptions, type WebSession } from "./web-routes.js";
|
|
12
|
+
export { customAppUserAccessToken, type AnonymousCustomAppVisitor, type CustomAppUserAccessTokenOptions, type CustomAppUserGrantBase, type IdentifiedCustomAppUser, } from "./custom-app-user-token.js";
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,KAAK,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,WAAW,EACX,yBAAyB,EACzB,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,WAAW,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,KAAK,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,WAAW,EACX,yBAAyB,EACzB,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACnH,OAAO,EACL,wBAAwB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,+BAA+B,EACpC,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,4 +9,5 @@ export { cachedToken, mintWithClientCredentials, withRenewal, } from "./token.js
|
|
|
9
9
|
export { discoveryUrl, issuerUrl } from "./oidc.js";
|
|
10
10
|
export { endWebLogin, finishWebLogin, refreshWebLogin, startWebLogin, webLogoutUrl, } from "./web-login.js";
|
|
11
11
|
export { webLoginRoutes } from "./web-routes.js";
|
|
12
|
+
export { customAppUserAccessToken, } from "./custom-app-user-token.js";
|
|
12
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,GAGhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GAKzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,GAMjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAkB,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,WAAW,EACX,yBAAyB,EACzB,WAAW,GAIZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAA+B,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,GAKb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAoE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,WAAW,EACX,YAAY,EACZ,gBAAgB,EAChB,KAAK,EACL,WAAW,EACX,MAAM,EACN,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,eAAe,GAGhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,GAKzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,GAMjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAkB,MAAM,WAAW,CAAC;AACpH,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EACL,WAAW,EACX,yBAAyB,EACzB,WAAW,GAIZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,SAAS,EAA+B,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,GAKb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAoE,MAAM,iBAAiB,CAAC;AACnH,OAAO,EACL,wBAAwB,GAKzB,MAAM,4BAA4B,CAAC"}
|
package/dist/token.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAkB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,WAAW,CAAC;AAErF,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AAGhD,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG;IAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAOxF,wBAAsB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAY9G;AAGD,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAG1C,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AA0BD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3E;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/D;AAqBD,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,iBAAiB,EAC9B,SAAS,GAAE,SAAiB,GAC3B,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAkB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,KAAK,SAAS,EAA4C,MAAM,WAAW,CAAC;AAErF,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AAGhD,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG;IAAE,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAOxF,wBAAsB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAY9G;AAGD,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAG1C,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AA0BD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3E;AAED,wBAAgB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/D;AAqBD,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,iBAAiB,EAC9B,SAAS,GAAE,SAAiB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,GAAE,MAAM,MAAiB,GAAG,oBAAoB,CA6BnG"}
|
package/dist/token.js
CHANGED
|
@@ -77,8 +77,11 @@ export async function mintWithClientCredentials(credentials, fetchImpl = fetch)
|
|
|
77
77
|
const endpoint = tokenEndpoint(baseUrl, realm);
|
|
78
78
|
const response = await postTo(endpoint, clientCredentialsRequest(credentials), fetchImpl);
|
|
79
79
|
if (!response.ok) {
|
|
80
|
+
const { error } = (await response.json().catch(() => ({})));
|
|
80
81
|
throw new Error(`Keycloak refused the client credentials for realm ${realm} with status ${response.status}. ` +
|
|
81
|
-
|
|
82
|
+
(error === "unauthorized_client"
|
|
83
|
+
? "This client may not mint tokens on its own: for a custom app, turn on Machine access."
|
|
84
|
+
: `Check the client id and the secret against ${endpoint}.`));
|
|
82
85
|
}
|
|
83
86
|
return readAccessToken(await response.json(), realm);
|
|
84
87
|
}
|
package/dist/token.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
|
package/dist/web.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { discoveryUrl, issuerUrl, type OidcClient, type Realm } from "./oidc.js"
|
|
|
5
5
|
export { accessTokenExpiresAt, cachedToken, mintWithClientCredentials, withRenewal, type ClientCredentials, type RenewableTokenSource, type TokenSource, } from "./token.js";
|
|
6
6
|
export { endWebLogin, finishWebLogin, refreshWebLogin, startWebLogin, webLogoutUrl, type StartWebLoginOptions, type WebLoginStart, type WebLogoutOptions, type WebTokens, } from "./web-login.js";
|
|
7
7
|
export { webLoginRoutes, type WebLoginRoutes, type WebLoginRoutesOptions, type WebSession } from "./web-routes.js";
|
|
8
|
+
export { customAppUserAccessToken, type AnonymousCustomAppVisitor, type CustomAppUserAccessTokenOptions, type CustomAppUserGrantBase, type IdentifiedCustomAppUser, } from "./custom-app-user-token.js";
|
|
8
9
|
//# sourceMappingURL=web.d.ts.map
|
package/dist/web.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,yBAAyB,EACzB,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,yBAAyB,EACzB,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,WAAW,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,KAAK,qBAAqB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACnH,OAAO,EACL,wBAAwB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,+BAA+B,EACpC,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,4BAA4B,CAAC"}
|
package/dist/web.js
CHANGED
|
@@ -4,4 +4,5 @@ export { discoveryUrl, issuerUrl } from "./oidc.js";
|
|
|
4
4
|
export { accessTokenExpiresAt, cachedToken, mintWithClientCredentials, withRenewal, } from "./token.js";
|
|
5
5
|
export { endWebLogin, finishWebLogin, refreshWebLogin, startWebLogin, webLogoutUrl, } from "./web-login.js";
|
|
6
6
|
export { webLoginRoutes } from "./web-routes.js";
|
|
7
|
+
export { customAppUserAccessToken, } from "./custom-app-user-token.js";
|
|
7
8
|
//# sourceMappingURL=web.js.map
|
package/dist/web.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAkB,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,SAAS,EAA+B,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,yBAAyB,EACzB,WAAW,GAIZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,GAKb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAoE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,mBAAmB,EAAkB,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,YAAY,EAAE,SAAS,EAA+B,MAAM,WAAW,CAAC;AACjF,OAAO,EACL,oBAAoB,EACpB,WAAW,EACX,yBAAyB,EACzB,WAAW,GAIZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,GAKb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAoE,MAAM,iBAAiB,CAAC;AACnH,OAAO,EACL,wBAAwB,GAKzB,MAAM,4BAA4B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manta-eu/auth",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Keycloak login for the SDK CLIs: browser and device-code login, silent token renewal, and credential storage; plus the default deployment the SDK targets",
|
|
5
5
|
"homepage": "https://developers.manta.eu",
|
|
6
6
|
"keywords": [
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"commander": "^15.0.0",
|
|
32
32
|
"jose": "^6.2.12",
|
|
33
|
-
"openid-client": "^6.8.8"
|
|
33
|
+
"openid-client": "^6.8.8",
|
|
34
|
+
"@manta-eu/lib": "0.2.1"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/node": "^24.13.3",
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
anonymousVisitorIdName,
|
|
3
|
+
customAppClientIdProblem,
|
|
4
|
+
customAppUserDatastoresProblem,
|
|
5
|
+
customAppUserIdProblem,
|
|
6
|
+
customAppUserProfileProblem,
|
|
7
|
+
customAppUserTeamsProblem,
|
|
8
|
+
customAppUserTokenPath,
|
|
9
|
+
type CustomAppUserProfile,
|
|
10
|
+
type CustomAppUserTokenRequest,
|
|
11
|
+
} from "@manta-eu/lib/custom-app";
|
|
12
|
+
import { isPresent } from "@manta-eu/lib/present";
|
|
13
|
+
import { defaultDeployment } from "./default-deployment.js";
|
|
14
|
+
import { type FetchLike, postTo, readJson, RefusedRequestError } from "./http.js";
|
|
15
|
+
|
|
16
|
+
export type CustomAppUserGrantBase = {
|
|
17
|
+
/** The custom app's client ID and secret, held only by the app's server. */
|
|
18
|
+
clientId: string;
|
|
19
|
+
clientSecret: string;
|
|
20
|
+
/** Narrows the token to these datastores; leave out to reach every datastore the app reaches. */
|
|
21
|
+
datastores?: string[];
|
|
22
|
+
/**
|
|
23
|
+
* Places the person in these teams of the app's organization, by path like /Sales/EU, as a member of them. An empty
|
|
24
|
+
* list places them in no team; leaving it out places them in every team the app reaches.
|
|
25
|
+
*/
|
|
26
|
+
teams?: string[];
|
|
27
|
+
/** Manta's address, https://app.hiremanta.com unless you name another deployment. */
|
|
28
|
+
apiUrl?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** A person your app knows: Manta keeps their chats under your id for them, and no memories. */
|
|
32
|
+
export type IdentifiedCustomAppUser = CustomAppUserGrantBase &
|
|
33
|
+
CustomAppUserProfile & { userId: string; anonymousId?: never };
|
|
34
|
+
|
|
35
|
+
/** A visitor your app has not identified, by your session id for them: they chat, and Manta keeps no memories. */
|
|
36
|
+
export type AnonymousCustomAppVisitor = CustomAppUserGrantBase & { anonymousId: string; userId?: never };
|
|
37
|
+
|
|
38
|
+
export type CustomAppUserAccessTokenOptions = IdentifiedCustomAppUser | AnonymousCustomAppVisitor;
|
|
39
|
+
|
|
40
|
+
// Blank ids count as absent, as Manta reads them.
|
|
41
|
+
function isVisitor(options: CustomAppUserAccessTokenOptions): options is AnonymousCustomAppVisitor {
|
|
42
|
+
return isPresent(options.anonymousId);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function requestFor(options: CustomAppUserAccessTokenOptions): CustomAppUserTokenRequest {
|
|
46
|
+
const { clientId, clientSecret, datastores, teams } = options;
|
|
47
|
+
const narrowed = { ...(datastores === undefined ? {} : { datastores }), ...(teams === undefined ? {} : { teams }) };
|
|
48
|
+
if (isVisitor(options)) {
|
|
49
|
+
return { client_id: clientId, client_secret: clientSecret, anonymous_id: options.anonymousId, ...narrowed };
|
|
50
|
+
}
|
|
51
|
+
const { userId, name, email, fields } = options;
|
|
52
|
+
return {
|
|
53
|
+
client_id: clientId,
|
|
54
|
+
client_secret: clientSecret,
|
|
55
|
+
user_id: userId,
|
|
56
|
+
...(name === undefined ? {} : { name }),
|
|
57
|
+
...(email === undefined ? {} : { email }),
|
|
58
|
+
...(fields === undefined ? {} : { fields }),
|
|
59
|
+
...narrowed,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Gets a Manta access token for one of the app's own users, or for an anonymous visitor. It sends the app's client
|
|
65
|
+
* secret, so call it on the app's server only; the token it returns may go to the browser.
|
|
66
|
+
*/
|
|
67
|
+
export async function customAppUserAccessToken(
|
|
68
|
+
options: CustomAppUserAccessTokenOptions,
|
|
69
|
+
fetchImpl: FetchLike = fetch,
|
|
70
|
+
): Promise<string> {
|
|
71
|
+
if (typeof (globalThis as { document?: unknown }).document !== "undefined") {
|
|
72
|
+
throw new Error("customAppUserAccessToken runs on your server only: it sends the app's client secret");
|
|
73
|
+
}
|
|
74
|
+
const clientIdProblem = customAppClientIdProblem(options.clientId);
|
|
75
|
+
if (clientIdProblem !== undefined) throw new Error(clientIdProblem);
|
|
76
|
+
if (!isPresent(options.clientSecret)) throw new Error("The app's client secret is required");
|
|
77
|
+
if (isPresent(options.userId) === isPresent(options.anonymousId)) {
|
|
78
|
+
throw new Error("Give exactly one of userId, for a person your app knows, and anonymousId, for a visitor");
|
|
79
|
+
}
|
|
80
|
+
const problem =
|
|
81
|
+
(isVisitor(options)
|
|
82
|
+
? customAppUserIdProblem(options.anonymousId, anonymousVisitorIdName)
|
|
83
|
+
: customAppUserIdProblem(options.userId)) ??
|
|
84
|
+
customAppUserDatastoresProblem(options.datastores) ??
|
|
85
|
+
customAppUserTeamsProblem(options.teams) ??
|
|
86
|
+
(isVisitor(options) ? undefined : customAppUserProfileProblem(options));
|
|
87
|
+
if (problem !== undefined) throw new Error(problem);
|
|
88
|
+
|
|
89
|
+
const endpoint = new URL(customAppUserTokenPath, options.apiUrl ?? defaultDeployment.apiUrl).toString();
|
|
90
|
+
const response = await postTo(
|
|
91
|
+
endpoint,
|
|
92
|
+
{
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: { "Content-Type": "application/json", Accept: "application/json" },
|
|
95
|
+
body: JSON.stringify(requestFor(options)),
|
|
96
|
+
},
|
|
97
|
+
fetchImpl,
|
|
98
|
+
);
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
const refusal = await readJson<{ error_description?: string }>(response, endpoint).catch(
|
|
101
|
+
(): { error_description?: string } => ({}),
|
|
102
|
+
);
|
|
103
|
+
throw new RefusedRequestError(
|
|
104
|
+
`Manta refused the custom app user token (${response.status}). ${refusal.error_description ?? ""}`.trim(),
|
|
105
|
+
response.status,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const body = await readJson<{ access_token?: string }>(response, endpoint);
|
|
109
|
+
if (typeof body.access_token !== "string") throw new Error("Manta answered without an access token");
|
|
110
|
+
return body.access_token;
|
|
111
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -58,3 +58,10 @@ export {
|
|
|
58
58
|
type WebTokens,
|
|
59
59
|
} from "./web-login.js";
|
|
60
60
|
export { webLoginRoutes, type WebLoginRoutes, type WebLoginRoutesOptions, type WebSession } from "./web-routes.js";
|
|
61
|
+
export {
|
|
62
|
+
customAppUserAccessToken,
|
|
63
|
+
type AnonymousCustomAppVisitor,
|
|
64
|
+
type CustomAppUserAccessTokenOptions,
|
|
65
|
+
type CustomAppUserGrantBase,
|
|
66
|
+
type IdentifiedCustomAppUser,
|
|
67
|
+
} from "./custom-app-user-token.js";
|
package/src/token.ts
CHANGED
|
@@ -110,9 +110,12 @@ export async function mintWithClientCredentials(
|
|
|
110
110
|
const response = await postTo(endpoint, clientCredentialsRequest(credentials), fetchImpl);
|
|
111
111
|
|
|
112
112
|
if (!response.ok) {
|
|
113
|
+
const { error } = (await response.json().catch(() => ({}))) as { error?: unknown };
|
|
113
114
|
throw new Error(
|
|
114
115
|
`Keycloak refused the client credentials for realm ${realm} with status ${response.status}. ` +
|
|
115
|
-
|
|
116
|
+
(error === "unauthorized_client"
|
|
117
|
+
? "This client may not mint tokens on its own: for a custom app, turn on Machine access."
|
|
118
|
+
: `Check the client id and the secret against ${endpoint}.`),
|
|
116
119
|
);
|
|
117
120
|
}
|
|
118
121
|
|
package/src/web.ts
CHANGED
|
@@ -23,3 +23,10 @@ export {
|
|
|
23
23
|
type WebTokens,
|
|
24
24
|
} from "./web-login.js";
|
|
25
25
|
export { webLoginRoutes, type WebLoginRoutes, type WebLoginRoutesOptions, type WebSession } from "./web-routes.js";
|
|
26
|
+
export {
|
|
27
|
+
customAppUserAccessToken,
|
|
28
|
+
type AnonymousCustomAppVisitor,
|
|
29
|
+
type CustomAppUserAccessTokenOptions,
|
|
30
|
+
type CustomAppUserGrantBase,
|
|
31
|
+
type IdentifiedCustomAppUser,
|
|
32
|
+
} from "./custom-app-user-token.js";
|