@kamod-ch/otok-oauth 2.0.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/LICENSE +21 -0
- package/README.md +163 -0
- package/dist/adapter/index.d.ts +2 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +2 -0
- package/dist/adapter/index.js.map +1 -0
- package/dist/adapter/types.d.ts +30 -0
- package/dist/adapter/types.d.ts.map +1 -0
- package/dist/adapter/types.js +2 -0
- package/dist/adapter/types.js.map +1 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/flow.d.ts +28 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +238 -0
- package/dist/flow.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin.d.ts +21 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +60 -0
- package/dist/plugin.js.map +1 -0
- package/dist/profile/github.d.ts +3 -0
- package/dist/profile/github.d.ts.map +1 -0
- package/dist/profile/github.js +45 -0
- package/dist/profile/github.js.map +1 -0
- package/dist/profile/gitlab.d.ts +3 -0
- package/dist/profile/gitlab.d.ts.map +1 -0
- package/dist/profile/gitlab.js +25 -0
- package/dist/profile/gitlab.js.map +1 -0
- package/dist/profile/google.d.ts +3 -0
- package/dist/profile/google.d.ts.map +1 -0
- package/dist/profile/google.js +24 -0
- package/dist/profile/google.js.map +1 -0
- package/dist/profile/microsoft.d.ts +3 -0
- package/dist/profile/microsoft.d.ts.map +1 -0
- package/dist/profile/microsoft.js +26 -0
- package/dist/profile/microsoft.js.map +1 -0
- package/dist/providers/github.d.ts +7 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +10 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/gitlab.d.ts +11 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +9 -0
- package/dist/providers/gitlab.js.map +1 -0
- package/dist/providers/google.d.ts +7 -0
- package/dist/providers/google.d.ts.map +1 -0
- package/dist/providers/google.js +10 -0
- package/dist/providers/google.js.map +1 -0
- package/dist/providers/microsoft.d.ts +11 -0
- package/dist/providers/microsoft.d.ts.map +1 -0
- package/dist/providers/microsoft.js +9 -0
- package/dist/providers/microsoft.js.map +1 -0
- package/dist/providers/types.d.ts +9 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/redirect.d.ts +3 -0
- package/dist/redirect.d.ts.map +1 -0
- package/dist/redirect.js +6 -0
- package/dist/redirect.js.map +1 -0
- package/dist/state.d.ts +22 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +73 -0
- package/dist/state.js.map +1 -0
- package/package.json +88 -0
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { definePlugin } from "@kamod-ch/otok";
|
|
2
|
+
import { getAuthRuntime, tryGetAuthRuntime } from "@kamod-ch/otok-auth/registry";
|
|
3
|
+
import { createOAuthFlow } from "./flow.js";
|
|
4
|
+
function resolveSecret(options) {
|
|
5
|
+
const secret = options.secret ?? process.env.AUTH_SECRET ?? process.env.OAUTH_SECRET;
|
|
6
|
+
if (!secret || secret.length < 32) {
|
|
7
|
+
throw new Error("otok-oauth: provide secret (min 32 bytes) or set AUTH_SECRET");
|
|
8
|
+
}
|
|
9
|
+
return secret;
|
|
10
|
+
}
|
|
11
|
+
function buildFlowOptions(options) {
|
|
12
|
+
const authRuntime = tryGetAuthRuntime();
|
|
13
|
+
return {
|
|
14
|
+
secret: resolveSecret(options),
|
|
15
|
+
adapter: options.adapter,
|
|
16
|
+
createSession: async (c, userId) => {
|
|
17
|
+
const runtime = getAuthRuntime();
|
|
18
|
+
await runtime.sessions.createSession(c, userId);
|
|
19
|
+
},
|
|
20
|
+
providers: options.providers,
|
|
21
|
+
basePath: options.basePath,
|
|
22
|
+
loginPath: options.loginPath ?? authRuntime?.loginPath,
|
|
23
|
+
redirectAllowlist: options.redirectAllowlist ?? authRuntime?.redirectAllowlist,
|
|
24
|
+
secure: options.secure,
|
|
25
|
+
onSuccess: options.onSuccess,
|
|
26
|
+
onError: options.onError,
|
|
27
|
+
tokenRefresh: options.tokenRefresh,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const oauthPluginFactory = definePlugin({
|
|
31
|
+
name: "@kamod-ch/otok-oauth",
|
|
32
|
+
version: "1.1.0",
|
|
33
|
+
schema: {
|
|
34
|
+
parse(input) {
|
|
35
|
+
if (!input || typeof input !== "object") {
|
|
36
|
+
throw new Error("oauth() options must be an object");
|
|
37
|
+
}
|
|
38
|
+
const record = input;
|
|
39
|
+
if (!record.adapter || typeof record.adapter !== "object") {
|
|
40
|
+
throw new Error("oauth() requires an OAuthAdapter");
|
|
41
|
+
}
|
|
42
|
+
if (!record.providers || typeof record.providers !== "object") {
|
|
43
|
+
throw new Error("oauth() requires providers");
|
|
44
|
+
}
|
|
45
|
+
return input;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
/** Otok plugin factory — register after auth() in otok.config.ts. */
|
|
50
|
+
export default function oauth(options) {
|
|
51
|
+
const plugin = oauthPluginFactory(options);
|
|
52
|
+
const flow = createOAuthFlow(buildFlowOptions(options));
|
|
53
|
+
plugin.configureApp = ({ app }) => {
|
|
54
|
+
flow.mount(app);
|
|
55
|
+
};
|
|
56
|
+
return plugin;
|
|
57
|
+
}
|
|
58
|
+
/** Programmatic setup — backward compatible with createOAuthFlow(). */
|
|
59
|
+
export { createOAuthFlow };
|
|
60
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAEjF,OAAO,EAAE,eAAe,EAAyB,MAAM,WAAW,CAAC;AAiBnE,SAAS,aAAa,CAAC,OAA2C;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACrF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAQ,OAAkC;IACjE,MAAM,WAAW,GAAG,iBAAiB,EAAE,CAAC;IACxC,OAAO;QACL,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,aAAa,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE;YACjC,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;YACjC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC;QACD,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,WAAW,EAAE,SAAS;QACtD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,WAAW,EAAE,iBAAiB;QAC9E,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,kBAAkB,GAAG,YAAY,CAAqB;IAC1D,IAAI,EAAE,sBAAsB;IAC5B,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE;QACN,KAAK,CAAC,KAAK;YACT,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;YACvD,CAAC;YACD,MAAM,MAAM,GAAG,KAAgC,CAAC;YAChD,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAC9D,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAChD,CAAC;YACD,OAAO,KAA2B,CAAC;QACrC,CAAC;KACF;CACF,CAAC,CAAC;AAEH,qEAAqE;AACrE,MAAM,CAAC,OAAO,UAAU,KAAK,CAAkB,OAAkC;IAC/E,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAA6B,CAAC,CAAC;IACjE,MAAM,IAAI,GAAG,eAAe,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IACxD,MAAM,CAAC,YAAY,GAAG,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;QAChC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uEAAuE;AACvE,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/profile/github.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAiBxD,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA+CnF"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { OAuthFlowError } from "../errors.js";
|
|
2
|
+
export async function fetchGitHubProfile(accessToken) {
|
|
3
|
+
const [userRes, emailsRes] = await Promise.all([
|
|
4
|
+
fetch("https://api.github.com/user", {
|
|
5
|
+
headers: {
|
|
6
|
+
Authorization: `Bearer ${accessToken}`,
|
|
7
|
+
Accept: "application/vnd.github+json",
|
|
8
|
+
"User-Agent": "otok-oauth",
|
|
9
|
+
},
|
|
10
|
+
}),
|
|
11
|
+
fetch("https://api.github.com/user/emails", {
|
|
12
|
+
headers: {
|
|
13
|
+
Authorization: `Bearer ${accessToken}`,
|
|
14
|
+
Accept: "application/vnd.github+json",
|
|
15
|
+
"User-Agent": "otok-oauth",
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
]);
|
|
19
|
+
if (!userRes.ok) {
|
|
20
|
+
throw new OAuthFlowError("profile_error", `GitHub /user failed with ${userRes.status}`);
|
|
21
|
+
}
|
|
22
|
+
const user = (await userRes.json());
|
|
23
|
+
let email = user.email;
|
|
24
|
+
let emailVerified = false;
|
|
25
|
+
if (emailsRes.ok) {
|
|
26
|
+
const emails = (await emailsRes.json());
|
|
27
|
+
const primary = emails.find((entry) => entry.primary && entry.verified) ??
|
|
28
|
+
emails.find((entry) => entry.verified) ??
|
|
29
|
+
emails.find((entry) => entry.primary) ??
|
|
30
|
+
null;
|
|
31
|
+
if (primary) {
|
|
32
|
+
email = primary.email;
|
|
33
|
+
emailVerified = primary.verified;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
provider: "github",
|
|
38
|
+
providerAccountId: String(user.id),
|
|
39
|
+
email,
|
|
40
|
+
emailVerified,
|
|
41
|
+
name: user.name ?? user.login ?? null,
|
|
42
|
+
avatarUrl: user.avatar_url ?? null,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/profile/github.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAgB9C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IAC1D,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC7C,KAAK,CAAC,6BAA6B,EAAE;YACnC,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,WAAW,EAAE;gBACtC,MAAM,EAAE,6BAA6B;gBACrC,YAAY,EAAE,YAAY;aAC3B;SACF,CAAC;QACF,KAAK,CAAC,oCAAoC,EAAE;YAC1C,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,WAAW,EAAE;gBACtC,MAAM,EAAE,6BAA6B;gBACrC,YAAY,EAAE,YAAY;aAC3B;SACF,CAAC;KACH,CAAC,CAAC;IAEH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,4BAA4B,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAe,CAAC;IAClD,IAAI,KAAK,GAAkB,IAAI,CAAC,KAAK,CAAC;IACtC,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,IAAI,SAAS,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,CAAkB,CAAC;QACzD,MAAM,OAAO,GACX,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC;YACvD,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC;YACrC,IAAI,CAAC;QACP,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YACtB,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC;QACnC,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,QAAQ;QAClB,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,KAAK;QACL,aAAa;QACb,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI;QACrC,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/profile/gitlab.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAYxD,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,SAAuB,GAC7B,OAAO,CAAC,YAAY,CAAC,CAyBvB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { OAuthFlowError } from "../errors.js";
|
|
2
|
+
export async function fetchGitLabProfile(accessToken, baseURL = "https://gitlab.com") {
|
|
3
|
+
const origin = baseURL.replace(/\/+$/, "");
|
|
4
|
+
const response = await fetch(`${origin}/api/v4/user`, {
|
|
5
|
+
headers: {
|
|
6
|
+
Authorization: `Bearer ${accessToken}`,
|
|
7
|
+
},
|
|
8
|
+
});
|
|
9
|
+
if (!response.ok) {
|
|
10
|
+
throw new OAuthFlowError("profile_error", `GitLab /api/v4/user failed with ${response.status}`);
|
|
11
|
+
}
|
|
12
|
+
const user = (await response.json());
|
|
13
|
+
if (user.id == null) {
|
|
14
|
+
throw new OAuthFlowError("profile_error", "GitLab profile missing id");
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
provider: "gitlab",
|
|
18
|
+
providerAccountId: String(user.id),
|
|
19
|
+
email: user.email ?? null,
|
|
20
|
+
emailVerified: Boolean(user.confirmed_at),
|
|
21
|
+
name: user.name ?? user.username ?? null,
|
|
22
|
+
avatarUrl: user.avatar_url ?? null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=gitlab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/profile/gitlab.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAW9C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,OAAO,GAAG,oBAAoB;IAE9B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,cAAc,EAAE;QACpD,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,mCAAmC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAe,CAAC;IACnD,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;QACpB,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,2BAA2B,CAAC,CAAC;IACzE,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,QAAQ;QAClB,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;QACzB,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;QACzC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI;QACxC,SAAS,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;KACnC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/profile/google.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAWxD,wBAAsB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAwBnF"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { OAuthFlowError } from "../errors.js";
|
|
2
|
+
export async function fetchGoogleProfile(accessToken) {
|
|
3
|
+
const response = await fetch("https://openidconnect.googleapis.com/v1/userinfo", {
|
|
4
|
+
headers: {
|
|
5
|
+
Authorization: `Bearer ${accessToken}`,
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new OAuthFlowError("profile_error", `Google userinfo failed with ${response.status}`);
|
|
10
|
+
}
|
|
11
|
+
const info = (await response.json());
|
|
12
|
+
if (!info.sub) {
|
|
13
|
+
throw new OAuthFlowError("profile_error", "Google userinfo missing sub");
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
provider: "google",
|
|
17
|
+
providerAccountId: info.sub,
|
|
18
|
+
email: info.email ?? null,
|
|
19
|
+
emailVerified: Boolean(info.email_verified),
|
|
20
|
+
name: info.name ?? null,
|
|
21
|
+
avatarUrl: info.picture ?? null,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/profile/google.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAU9C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,WAAmB;IAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kDAAkD,EAAE;QAC/E,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,+BAA+B,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAmB,CAAC;IACvD,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACd,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,6BAA6B,CAAC,CAAC;IAC3E,CAAC;IAED,OAAO;QACL,QAAQ,EAAE,QAAQ;QAClB,iBAAiB,EAAE,IAAI,CAAC,GAAG;QAC3B,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI;QACzB,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC;QAC3C,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,IAAI;QACvB,SAAS,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.d.ts","sourceRoot":"","sources":["../../src/profile/microsoft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAcxD,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CA2BtF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { OAuthFlowError } from "../errors.js";
|
|
2
|
+
export async function fetchMicrosoftProfile(accessToken) {
|
|
3
|
+
const response = await fetch("https://graph.microsoft.com/v1.0/me", {
|
|
4
|
+
headers: {
|
|
5
|
+
Authorization: `Bearer ${accessToken}`,
|
|
6
|
+
},
|
|
7
|
+
});
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new OAuthFlowError("profile_error", `Microsoft Graph /me failed with ${response.status}`);
|
|
10
|
+
}
|
|
11
|
+
const info = (await response.json());
|
|
12
|
+
const providerAccountId = info.id ?? info.sub;
|
|
13
|
+
if (!providerAccountId) {
|
|
14
|
+
throw new OAuthFlowError("profile_error", "Microsoft profile missing id");
|
|
15
|
+
}
|
|
16
|
+
const email = info.mail ?? info.userPrincipalName ?? info.email ?? null;
|
|
17
|
+
return {
|
|
18
|
+
provider: "microsoft",
|
|
19
|
+
providerAccountId: String(providerAccountId),
|
|
20
|
+
email,
|
|
21
|
+
emailVerified: Boolean(email),
|
|
22
|
+
name: info.displayName ?? info.name ?? null,
|
|
23
|
+
avatarUrl: null,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=microsoft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.js","sourceRoot":"","sources":["../../src/profile/microsoft.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAa9C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,WAAmB;IAC7D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,qCAAqC,EAAE;QAClE,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,mCAAmC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB,CAAC;IAC1D,MAAM,iBAAiB,GAAG,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC;IAC9C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,MAAM,IAAI,cAAc,CAAC,eAAe,EAAE,8BAA8B,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC;IAExE,OAAO;QACL,QAAQ,EAAE,WAAW;QACrB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,CAAC;QAC5C,KAAK;QACL,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC;QAC7B,IAAI,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI;QAC3C,SAAS,EAAE,IAAI;KAChB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { GitHub } from "arctic";
|
|
2
|
+
import { DEFAULT_GITHUB_SCOPES, type OAuthProviderConfig } from "./types.js";
|
|
3
|
+
export declare function createGitHubClient(config: OAuthProviderConfig): GitHub;
|
|
4
|
+
export declare function githubScopes(config: OAuthProviderConfig): string[];
|
|
5
|
+
export { DEFAULT_GITHUB_SCOPES };
|
|
6
|
+
export type { OAuthProviderConfig };
|
|
7
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE7E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAEtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAElE;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GitHub } from "arctic";
|
|
2
|
+
import { DEFAULT_GITHUB_SCOPES } from "./types.js";
|
|
3
|
+
export function createGitHubClient(config) {
|
|
4
|
+
return new GitHub(config.clientId, config.clientSecret, config.redirectUri);
|
|
5
|
+
}
|
|
6
|
+
export function githubScopes(config) {
|
|
7
|
+
return config.scopes ?? [...DEFAULT_GITHUB_SCOPES];
|
|
8
|
+
}
|
|
9
|
+
export { DEFAULT_GITHUB_SCOPES };
|
|
10
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/providers/github.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAA4B,MAAM,YAAY,CAAC;AAE7E,MAAM,UAAU,kBAAkB,CAAC,MAA2B;IAC5D,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAA2B;IACtD,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;AACrD,CAAC;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GitLab } from "arctic";
|
|
2
|
+
import type { OAuthProviderConfig } from "./types.js";
|
|
3
|
+
export declare const DEFAULT_GITLAB_SCOPES: readonly ["read_user"];
|
|
4
|
+
export type GitLabProviderConfig = OAuthProviderConfig & {
|
|
5
|
+
/** GitLab base URL. Defaults to `https://gitlab.com`. */
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function gitlabScopes(config: OAuthProviderConfig): string[];
|
|
9
|
+
export declare function createGitLabClient(config: GitLabProviderConfig): GitLab;
|
|
10
|
+
export type { OAuthProviderConfig };
|
|
11
|
+
//# sourceMappingURL=gitlab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.d.ts","sourceRoot":"","sources":["../../src/providers/gitlab.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,eAAO,MAAM,qBAAqB,wBAAyB,CAAC;AAE5D,MAAM,MAAM,oBAAoB,GAAG,mBAAmB,GAAG;IACvD,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAElE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAOvE;AAED,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GitLab } from "arctic";
|
|
2
|
+
export const DEFAULT_GITLAB_SCOPES = ["read_user"];
|
|
3
|
+
export function gitlabScopes(config) {
|
|
4
|
+
return config.scopes ?? [...DEFAULT_GITLAB_SCOPES];
|
|
5
|
+
}
|
|
6
|
+
export function createGitLabClient(config) {
|
|
7
|
+
return new GitLab(config.baseURL ?? "https://gitlab.com", config.clientId, config.clientSecret, config.redirectUri);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=gitlab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab.js","sourceRoot":"","sources":["../../src/providers/gitlab.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,WAAW,CAAU,CAAC;AAO5D,MAAM,UAAU,YAAY,CAAC,MAA2B;IACtD,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAA4B;IAC7D,OAAO,IAAI,MAAM,CACf,MAAM,CAAC,OAAO,IAAI,oBAAoB,EACtC,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,YAAY,EACnB,MAAM,CAAC,WAAW,CACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Google } from "arctic";
|
|
2
|
+
import { DEFAULT_GOOGLE_SCOPES, type OAuthProviderConfig } from "./types.js";
|
|
3
|
+
export declare function createGoogleClient(config: OAuthProviderConfig): Google;
|
|
4
|
+
export declare function googleScopes(config: OAuthProviderConfig): string[];
|
|
5
|
+
export { DEFAULT_GOOGLE_SCOPES };
|
|
6
|
+
export type { OAuthProviderConfig };
|
|
7
|
+
//# sourceMappingURL=google.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE7E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAEtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAElE;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Google } from "arctic";
|
|
2
|
+
import { DEFAULT_GOOGLE_SCOPES } from "./types.js";
|
|
3
|
+
export function createGoogleClient(config) {
|
|
4
|
+
return new Google(config.clientId, config.clientSecret, config.redirectUri);
|
|
5
|
+
}
|
|
6
|
+
export function googleScopes(config) {
|
|
7
|
+
return config.scopes ?? [...DEFAULT_GOOGLE_SCOPES];
|
|
8
|
+
}
|
|
9
|
+
export { DEFAULT_GOOGLE_SCOPES };
|
|
10
|
+
//# sourceMappingURL=google.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/providers/google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAA4B,MAAM,YAAY,CAAC;AAE7E,MAAM,UAAU,kBAAkB,CAAC,MAA2B;IAC5D,OAAO,IAAI,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAA2B;IACtD,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,qBAAqB,CAAC,CAAC;AACrD,CAAC;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MicrosoftEntraId } from "arctic";
|
|
2
|
+
import type { OAuthProviderConfig } from "./types.js";
|
|
3
|
+
export declare const DEFAULT_MICROSOFT_SCOPES: readonly ["openid", "email", "profile", "User.Read"];
|
|
4
|
+
export type MicrosoftProviderConfig = OAuthProviderConfig & {
|
|
5
|
+
/** Entra ID tenant. Defaults to `common`. */
|
|
6
|
+
tenant?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function microsoftScopes(config: OAuthProviderConfig): string[];
|
|
9
|
+
export declare function createMicrosoftClient(config: MicrosoftProviderConfig): MicrosoftEntraId;
|
|
10
|
+
export type { OAuthProviderConfig };
|
|
11
|
+
//# sourceMappingURL=microsoft.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.d.ts","sourceRoot":"","sources":["../../src/providers/microsoft.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD,eAAO,MAAM,wBAAwB,sDAAuD,CAAC;AAE7F,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,GAAG;IAC1D,6CAA6C;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,eAAe,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAErE;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,uBAAuB,GAAG,gBAAgB,CAOvF;AAED,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MicrosoftEntraId } from "arctic";
|
|
2
|
+
export const DEFAULT_MICROSOFT_SCOPES = ["openid", "email", "profile", "User.Read"];
|
|
3
|
+
export function microsoftScopes(config) {
|
|
4
|
+
return config.scopes ?? [...DEFAULT_MICROSOFT_SCOPES];
|
|
5
|
+
}
|
|
6
|
+
export function createMicrosoftClient(config) {
|
|
7
|
+
return new MicrosoftEntraId(config.tenant ?? "common", config.clientId, config.clientSecret, config.redirectUri);
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=microsoft.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"microsoft.js","sourceRoot":"","sources":["../../src/providers/microsoft.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAG1C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,CAAU,CAAC;AAO7F,MAAM,UAAU,eAAe,CAAC,MAA2B;IACzD,OAAO,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,wBAAwB,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAA+B;IACnE,OAAO,IAAI,gBAAgB,CACzB,MAAM,CAAC,MAAM,IAAI,QAAQ,EACzB,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,YAAY,EACnB,MAAM,CAAC,WAAW,CACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type OAuthProviderConfig = {
|
|
2
|
+
clientId: string;
|
|
3
|
+
clientSecret: string;
|
|
4
|
+
redirectUri: string;
|
|
5
|
+
scopes?: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare const DEFAULT_GITHUB_SCOPES: readonly ["user:email"];
|
|
8
|
+
export declare const DEFAULT_GOOGLE_SCOPES: readonly ["openid", "email", "profile"];
|
|
9
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,qBAAqB,yBAA0B,CAAC;AAC7D,eAAO,MAAM,qBAAqB,yCAA0C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,YAAY,CAAU,CAAC;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect.d.ts","sourceRoot":"","sources":["../src/redirect.ts"],"names":[],"mappings":"AAEA,oEAAoE;AACpE,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAC9B,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAC5B,MAAM,GAAG,IAAI,CAEf"}
|
package/dist/redirect.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { safeRedirectPath } from "@kamod-ch/otok-auth/redirect";
|
|
2
|
+
/** Only same-origin relative paths within an optional allowlist. */
|
|
3
|
+
export function safeNextPath(raw, allowlist) {
|
|
4
|
+
return safeRedirectPath(raw, allowlist ?? ["/"]);
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=redirect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect.js","sourceRoot":"","sources":["../src/redirect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAC1B,GAA8B,EAC9B,SAA6B;IAE7B,OAAO,gBAAgB,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/state.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OAuthProviderId } from "./adapter/types.js";
|
|
2
|
+
export type OAuthStatePayload = {
|
|
3
|
+
provider: OAuthProviderId;
|
|
4
|
+
state: string;
|
|
5
|
+
codeVerifier: string | null;
|
|
6
|
+
next: string | null;
|
|
7
|
+
link?: boolean;
|
|
8
|
+
issuedAt: number;
|
|
9
|
+
};
|
|
10
|
+
declare const DEFAULT_MAX_AGE_MS: number;
|
|
11
|
+
export declare function encodePayload(payload: string): string;
|
|
12
|
+
export declare function decodePayload(encoded: string): string | null;
|
|
13
|
+
export declare function signPayload(encodedPayload: string, secret: string): string;
|
|
14
|
+
export declare function seal(value: string, secret: string): string;
|
|
15
|
+
export declare function unseal(token: string, secret: string): string | null;
|
|
16
|
+
export declare function sealOAuthState(payload: OAuthStatePayload, secret: string): string;
|
|
17
|
+
export declare function unsealOAuthState(token: string, secret: string, options?: {
|
|
18
|
+
maxAgeMs?: number;
|
|
19
|
+
now?: number;
|
|
20
|
+
}): OAuthStatePayload | null;
|
|
21
|
+
export { DEFAULT_MAX_AGE_MS };
|
|
22
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,QAAA,MAAM,kBAAkB,QAAiB,CAAC;AAE1C,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM5D;AAED,wBAAgB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAcnE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjF;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C,iBAAiB,GAAG,IAAI,CAkB1B;AAkBD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
package/dist/state.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
2
|
+
const DEFAULT_MAX_AGE_MS = 10 * 60 * 1000;
|
|
3
|
+
export function encodePayload(payload) {
|
|
4
|
+
return Buffer.from(payload, "utf8").toString("base64url");
|
|
5
|
+
}
|
|
6
|
+
export function decodePayload(encoded) {
|
|
7
|
+
try {
|
|
8
|
+
return Buffer.from(encoded, "base64url").toString("utf8");
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function signPayload(encodedPayload, secret) {
|
|
15
|
+
return createHmac("sha256", secret).update(encodedPayload).digest("base64url");
|
|
16
|
+
}
|
|
17
|
+
export function seal(value, secret) {
|
|
18
|
+
const encoded = encodePayload(value);
|
|
19
|
+
return `${encoded}.${signPayload(encoded, secret)}`;
|
|
20
|
+
}
|
|
21
|
+
export function unseal(token, secret) {
|
|
22
|
+
const separator = token.lastIndexOf(".");
|
|
23
|
+
if (separator <= 0)
|
|
24
|
+
return null;
|
|
25
|
+
const encoded = token.slice(0, separator);
|
|
26
|
+
const signature = token.slice(separator + 1);
|
|
27
|
+
if (!encoded || !signature)
|
|
28
|
+
return null;
|
|
29
|
+
const expected = signPayload(encoded, secret);
|
|
30
|
+
const left = Buffer.from(signature);
|
|
31
|
+
const right = Buffer.from(expected);
|
|
32
|
+
if (left.length !== right.length || !timingSafeEqual(left, right))
|
|
33
|
+
return null;
|
|
34
|
+
return decodePayload(encoded);
|
|
35
|
+
}
|
|
36
|
+
export function sealOAuthState(payload, secret) {
|
|
37
|
+
return seal(JSON.stringify(payload), secret);
|
|
38
|
+
}
|
|
39
|
+
export function unsealOAuthState(token, secret, options) {
|
|
40
|
+
const raw = unseal(token, secret);
|
|
41
|
+
if (!raw)
|
|
42
|
+
return null;
|
|
43
|
+
let parsed;
|
|
44
|
+
try {
|
|
45
|
+
parsed = JSON.parse(raw);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (!isOAuthStatePayload(parsed))
|
|
51
|
+
return null;
|
|
52
|
+
const maxAgeMs = options?.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
|
|
53
|
+
const now = options?.now ?? Date.now();
|
|
54
|
+
if (now - parsed.issuedAt > maxAgeMs)
|
|
55
|
+
return null;
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
function isOAuthStatePayload(value) {
|
|
59
|
+
if (!value || typeof value !== "object")
|
|
60
|
+
return false;
|
|
61
|
+
const record = value;
|
|
62
|
+
return ((record.provider === "github" ||
|
|
63
|
+
record.provider === "google" ||
|
|
64
|
+
record.provider === "microsoft" ||
|
|
65
|
+
record.provider === "gitlab") &&
|
|
66
|
+
typeof record.state === "string" &&
|
|
67
|
+
(typeof record.codeVerifier === "string" || record.codeVerifier === null) &&
|
|
68
|
+
(typeof record.next === "string" || record.next === null) &&
|
|
69
|
+
(record.link === undefined || typeof record.link === "boolean") &&
|
|
70
|
+
typeof record.issuedAt === "number");
|
|
71
|
+
}
|
|
72
|
+
export { DEFAULT_MAX_AGE_MS };
|
|
73
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kamod-ch/otok-oauth",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "OAuth login helpers (GitHub, Google, Microsoft, GitLab) for Otok apps.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/kamod-ch/otok/tree/main/packages/otok-oauth#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/kamod-ch/otok/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/kamod-ch/otok.git",
|
|
13
|
+
"directory": "packages/otok-oauth"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./adapter": {
|
|
26
|
+
"types": "./dist/adapter/index.d.ts",
|
|
27
|
+
"default": "./dist/adapter/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./providers/github": {
|
|
30
|
+
"types": "./dist/providers/github.d.ts",
|
|
31
|
+
"default": "./dist/providers/github.js"
|
|
32
|
+
},
|
|
33
|
+
"./providers/google": {
|
|
34
|
+
"types": "./dist/providers/google.d.ts",
|
|
35
|
+
"default": "./dist/providers/google.js"
|
|
36
|
+
},
|
|
37
|
+
"./state": {
|
|
38
|
+
"types": "./dist/state.d.ts",
|
|
39
|
+
"default": "./dist/state.js"
|
|
40
|
+
},
|
|
41
|
+
"./plugin": {
|
|
42
|
+
"types": "./dist/plugin.d.ts",
|
|
43
|
+
"default": "./dist/plugin.js"
|
|
44
|
+
},
|
|
45
|
+
"./providers/microsoft": {
|
|
46
|
+
"types": "./dist/providers/microsoft.d.ts",
|
|
47
|
+
"default": "./dist/providers/microsoft.js"
|
|
48
|
+
},
|
|
49
|
+
"./providers/gitlab": {
|
|
50
|
+
"types": "./dist/providers/gitlab.d.ts",
|
|
51
|
+
"default": "./dist/providers/gitlab.js"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@kamod-ch/otok": ">=0.6.1",
|
|
56
|
+
"@kamod-ch/otok-auth": ">=2.0.0",
|
|
57
|
+
"arctic": ">=3.0.0",
|
|
58
|
+
"hono": ">=4"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"otok": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"@kamod-ch/otok-auth": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/node": "^24.12.2",
|
|
70
|
+
"arctic": "^3.7.0",
|
|
71
|
+
"hono": "^4.12.25",
|
|
72
|
+
"typescript": "~6.0.2",
|
|
73
|
+
"vitest": "^4.1.2",
|
|
74
|
+
"@kamod-ch/otok": "0.6.1",
|
|
75
|
+
"@kamod-ch/otok-auth": "2.0.0"
|
|
76
|
+
},
|
|
77
|
+
"engines": {
|
|
78
|
+
"node": ">=20"
|
|
79
|
+
},
|
|
80
|
+
"publishConfig": {
|
|
81
|
+
"access": "public"
|
|
82
|
+
},
|
|
83
|
+
"scripts": {
|
|
84
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
85
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
86
|
+
"test": "vitest run"
|
|
87
|
+
}
|
|
88
|
+
}
|