authhero 0.2.3 → 0.2.4

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.
@@ -1,178 +0,0 @@
1
- import {
2
- jwksKeySchema,
3
- openIDConfigurationSchema,
4
- } from "@authhero/adapter-interfaces";
5
- import { Bindings } from "../../types";
6
- import { OpenAPIHono, createRoute } from "@hono/zod-openapi";
7
-
8
- export const wellKnownRoutes = new OpenAPIHono<{ Bindings: Bindings }>()
9
- // --------------------------------
10
- // GET /.well-known/jwks.json
11
- // --------------------------------
12
- .openapi(
13
- createRoute({
14
- tags: ["jwks"],
15
- method: "get",
16
- path: "/jwks.json",
17
- request: {},
18
- responses: {
19
- 200: {
20
- content: {
21
- "application/json": {
22
- schema: jwksKeySchema,
23
- },
24
- },
25
- description: "List of tenants",
26
- },
27
- },
28
- }),
29
- async (ctx) => {
30
- const { env } = ctx;
31
-
32
- // const certificates = await env.data.keys.list();
33
- // const keys = certificates.map((cert) => {
34
- // const { alg, n, e, kty } = JSON.parse(cert.public_key);
35
- // if (!alg || !e || !kty || !n) {
36
- // throw new Error("Invalid public key");
37
- // }
38
-
39
- // return jwksSchema.parse({
40
- // kid: cert.kid,
41
- // alg,
42
- // n,
43
- // e,
44
- // kty,
45
- // });
46
- // });
47
-
48
- // TODO: This is a stub implementation. Replace with the actual implementation
49
- const keys = [
50
- {
51
- alg: "RS256",
52
- e: "AQAB",
53
- kid: "hZ42TWGWLdmyKfwGVA6c2",
54
- kty: "RSA",
55
- n: "nUd-mktFZQNfVwmXufxcVcvJo6Lkb-jDuymtfQunmEhWCctOccWx9e7LX7_9uN15ZnRS7XJInPMRs9KLYdZ0GCnE2HM_QbrEoHpdkCRgyTE-KzmoaEv_AOVGE_Kg0-0ct3r9Z7aJLDVAsxXl1C9y8Gr7ZYkq0c4DyZr9VT8nQiwZQERbfxXdXw-5RLj21S_Lm-LL-AjKvry_TDBLpfUFJV18SVsM07lY_V45TwykNewRdaGLspFIeGdG5j5eByV8ifzBqvzOSptSCsmOTtW-ceWUk0FPD7g_KKzjjbzenoB0TC8mBb_4vWZlHnuGIAs2YoTFglp9uNu7t_OVl3Svo6ZE6alzUnaNfZNeAi78KPHYQ4tDWPjpYNfGynsiD0nojkDSPCIak56jWNYjj614cPEBiv9MVQRiSbBxpiGhMoHlW_QCCPMcXygLAaRs_tUksqoH4QB80krifG2yHPgGDPjXK1_0cYzV80iOcQIeoceqhkSSc6YxzzgDrQcsV2k3bizRQSL83GWkpdHhTZn-Q_JzsW_bDY_f9fjigYbRnoDSgS7038VFIPc92StE41MdgvIQMomcyEE4lYK1uv1Mo6cnXbCZhm8tvddo7VKNorOB4nsiv8DGrWPlzQBca9VN4C1oE2mH-3WLFR7XEkBHWVouOdTWM2S3K9F10YtahkM",
56
- },
57
- ];
58
-
59
- return ctx.json(
60
- { keys },
61
- {
62
- headers: {
63
- "access-control-allow-origin": "*",
64
- "access-control-allow-method": "GET",
65
- "cache-control": `public, max-age=${env.JWKS_CACHE_TIMEOUT_IN_SECONDS}, stale-while-revalidate=${
66
- env.JWKS_CACHE_TIMEOUT_IN_SECONDS * 2
67
- }, stale-if-error=86400`,
68
- },
69
- },
70
- );
71
- },
72
- )
73
- // --------------------------------
74
- // GET /.well-known/openid-configuration
75
- // --------------------------------
76
- .openapi(
77
- createRoute({
78
- tags: ["well known"],
79
- method: "get",
80
- path: "/openid-configuration",
81
- request: {},
82
- responses: {
83
- 200: {
84
- content: {
85
- "application/json": {
86
- schema: openIDConfigurationSchema,
87
- },
88
- },
89
- description: "List of tenants",
90
- },
91
- },
92
- }),
93
- async (ctx) => {
94
- const { env } = ctx;
95
- const { ISSUER } = env;
96
-
97
- const result = openIDConfigurationSchema.parse({
98
- issuer: ISSUER,
99
- authorization_endpoint: `${ISSUER}authorize`,
100
- token_endpoint: `${ISSUER}oauth/token`,
101
- device_authorization_endpoint: `${ISSUER}oauth/device/code`,
102
- userinfo_endpoint: `${ISSUER}userinfo`,
103
- mfa_challenge_endpoint: `${ISSUER}mfa/challenge`,
104
- jwks_uri: `${ISSUER}.well-known/jwks.json`,
105
- registration_endpoint: `${ISSUER}oidc/register`,
106
- revocation_endpoint: `${ISSUER}oauth/revoke`,
107
- scopes_supported: [
108
- "openid",
109
- "profile",
110
- "offline_access",
111
- "name",
112
- "given_name",
113
- "family_name",
114
- "nickname",
115
- "email",
116
- "email_verified",
117
- "picture",
118
- "created_at",
119
- "identities",
120
- "phone",
121
- "address",
122
- ],
123
- response_types_supported: [
124
- "code",
125
- "token",
126
- "id_token",
127
- "code token",
128
- "code id_token",
129
- "token id_token",
130
- "code token id_token",
131
- ],
132
- code_challenge_methods_supported: ["S256", "plain"],
133
- response_modes_supported: ["query", "fragment", "form_post"],
134
- subject_types_supported: ["public"],
135
- id_token_signing_alg_values_supported: ["HS256", "RS256"],
136
- token_endpoint_auth_methods_supported: [
137
- "client_secret_basic",
138
- "client_secret_post",
139
- "private_key_jwt",
140
- ],
141
- claims_supported: [
142
- "aud",
143
- "auth_time",
144
- "created_at",
145
- "email",
146
- "email_verified",
147
- "exp",
148
- "family_name",
149
- "given_name",
150
- "iat",
151
- "identities",
152
- "iss",
153
- "name",
154
- "nickname",
155
- "phone_number",
156
- "picture",
157
- "sub",
158
- ],
159
- request_uri_parameter_supported: false,
160
- request_parameter_supported: false,
161
- token_endpoint_auth_signing_alg_values_supported: [
162
- "RS256",
163
- "RS384",
164
- "PS256",
165
- ],
166
- });
167
-
168
- return ctx.json(result, {
169
- headers: {
170
- "access-control-allow-origin": "*",
171
- "access-control-allow-method": "GET",
172
- "cache-control": `public, max-age=${env.JWKS_CACHE_TIMEOUT_IN_SECONDS}, stale-while-revalidate=${
173
- env.JWKS_CACHE_TIMEOUT_IN_SECONDS * 2
174
- }, stale-if-error=86400`,
175
- },
176
- });
177
- },
178
- );
@@ -1,12 +0,0 @@
1
- import { DataAdapters } from "@authhero/adapter-interfaces";
2
-
3
- export type Bindings = {
4
- ISSUER: string;
5
- ENVIRONMENT: string;
6
- AUTH_URL: string;
7
-
8
- data: DataAdapters;
9
-
10
- // Constants
11
- JWKS_CACHE_TIMEOUT_IN_SECONDS: number;
12
- };
@@ -1,42 +0,0 @@
1
- import { z } from "@hono/zod-openapi";
2
-
3
- export const querySchema = z.object({
4
- page: z
5
- .string()
6
- .min(0)
7
- .optional()
8
- .default("0")
9
- .transform((p) => parseInt(p, 10))
10
- .openapi({
11
- description: "The page number where 0 is the first page",
12
- }),
13
- per_page: z
14
- .string()
15
- .min(1)
16
- .optional()
17
- .default("10")
18
- .transform((p) => parseInt(p, 10))
19
- .openapi({
20
- description: "The number of items per page",
21
- }),
22
- include_totals: z
23
- .string()
24
- .optional()
25
- .default("false")
26
- .transform((it) => it === "true")
27
- .openapi({
28
- description:
29
- "If the total number of items should be included in the response",
30
- }),
31
- sort: z
32
- .string()
33
- .regex(/^.+:(-1|1)$/)
34
- .optional()
35
- .openapi({
36
- description:
37
- "A property that should have the format 'string:-1' or 'string:1'",
38
- }),
39
- q: z.string().optional().openapi({
40
- description: "A lucene query string used to filter the results",
41
- }),
42
- });
@@ -1,3 +0,0 @@
1
- export type Variables = {
2
- tenant_id: string;
3
- };
@@ -1,3 +0,0 @@
1
- export * from "./Variables";
2
- export * from "./Bindings";
3
- export * from "./Query";
@@ -1,18 +0,0 @@
1
- export function parseSort(sort?: string):
2
- | undefined
3
- | {
4
- sort_by: string;
5
- sort_order: "asc" | "desc";
6
- } {
7
- if (!sort) {
8
- return undefined;
9
- }
10
-
11
- const [sort_by = "", orderString] = sort.split(":");
12
- const sort_order = orderString === "1" ? "asc" : "desc";
13
-
14
- return {
15
- sort_by,
16
- sort_order,
17
- };
18
- }
@@ -1,130 +0,0 @@
1
- import { User, UserDataAdapter } from "@authhero/adapter-interfaces";
2
-
3
- export async function getUsersByEmail(
4
- userAdapter: UserDataAdapter,
5
- tenantId: string,
6
- email: string,
7
- ): Promise<User[]> {
8
- const response = await userAdapter.list(tenantId, {
9
- page: 0,
10
- per_page: 10,
11
- include_totals: false,
12
- q: `email:${email}`,
13
- });
14
-
15
- return response.users;
16
- }
17
-
18
- interface GetUserByEmailAndProviderParams {
19
- userAdapter: UserDataAdapter;
20
- tenant_id: string;
21
- email: string;
22
- provider: string;
23
- }
24
-
25
- export async function getUserByEmailAndProvider({
26
- userAdapter,
27
- tenant_id,
28
- email,
29
- provider,
30
- }: GetUserByEmailAndProviderParams): Promise<User | null> {
31
- const { users } = await userAdapter.list(tenant_id, {
32
- page: 0,
33
- per_page: 10,
34
- include_totals: false,
35
- q: `email:${email} provider:${provider}`,
36
- });
37
-
38
- if (users.length > 1) {
39
- console.error("More than one user found for same email and provider");
40
- }
41
-
42
- return users[0] || null;
43
- }
44
-
45
- interface GetPrimaryUserByEmailParams {
46
- userAdapter: UserDataAdapter;
47
- tenant_id: string;
48
- email: string;
49
- }
50
-
51
- export async function getPrimaryUserByEmail({
52
- userAdapter,
53
- tenant_id,
54
- email,
55
- }: GetPrimaryUserByEmailParams): Promise<User | undefined> {
56
- const { users: usersWithUnverifiedPasswordAccounts } = await userAdapter.list(
57
- tenant_id,
58
- {
59
- page: 0,
60
- per_page: 10,
61
- include_totals: false,
62
- q: `email:${email}`,
63
- },
64
- );
65
-
66
- // filter out unverified accounts
67
- const users = usersWithUnverifiedPasswordAccounts.filter(
68
- // maybe we should do this for all providers
69
- (user) => !(user.provider === "auth2" && !user.email_verified),
70
- );
71
-
72
- if (users.length === 0) {
73
- return;
74
- }
75
-
76
- const primaryUsers = users.filter((user) => !user.linked_to);
77
-
78
- if (primaryUsers.length > 0) {
79
- if (primaryUsers.length > 1) {
80
- console.error("More than one primary user found for same email");
81
- }
82
-
83
- return primaryUsers[0];
84
- }
85
-
86
- // so now we have only linked users for this email address
87
-
88
- // I am going to assume that all the linked users with the same email address
89
- // are linked to the same primary account
90
-
91
- const primaryAccount = await userAdapter.get(tenant_id, users[0]?.linked_to!);
92
-
93
- if (!primaryAccount) {
94
- // this is a real error where we should interrupt the flow
95
- throw new Error("Primary account not found");
96
- }
97
-
98
- return primaryAccount;
99
- }
100
-
101
- interface GetPrimaryUserByEmailAndProviderParams {
102
- userAdapter: UserDataAdapter;
103
- tenant_id: string;
104
- email: string;
105
- provider: string;
106
- }
107
-
108
- export async function getPrimaryUserByEmailAndProvider({
109
- userAdapter,
110
- tenant_id,
111
- email,
112
- provider,
113
- }: GetPrimaryUserByEmailAndProviderParams): Promise<User | null> {
114
- const user = await getUserByEmailAndProvider({
115
- userAdapter,
116
- tenant_id,
117
- email,
118
- provider,
119
- });
120
-
121
- if (!user) {
122
- return null;
123
- }
124
-
125
- if (!user.linked_to) {
126
- return user;
127
- }
128
-
129
- return userAdapter.get(tenant_id, user.linked_to);
130
- }
package/src/vite-env.d.ts DELETED
@@ -1 +0,0 @@
1
- /// <reference types="vite/client" />
package/tsconfig.json DELETED
@@ -1,11 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- // "noEmit": true,
5
- "baseUrl": ".",
6
- "outDir": "./dist",
7
- "rootDir": "./src"
8
- },
9
- "include": ["src"],
10
- "references": [{ "path": "./tsconfig.node.json" }]
11
- }
@@ -1,4 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.node.json",
3
- "include": ["vite.config.ts"]
4
- }
package/vite.config.ts DELETED
@@ -1,41 +0,0 @@
1
- import path from "path";
2
- import { defineConfig } from "vite";
3
-
4
- const getPackageName = () => {
5
- return "authhero";
6
- };
7
-
8
- const getPackageNameCamelCase = () => {
9
- try {
10
- return getPackageName().replace(/-./g, (char) => char[1].toUpperCase());
11
- } catch (err) {
12
- throw new Error("Name property in package.json is missing.");
13
- }
14
- };
15
-
16
- const fileName = {
17
- es: `${getPackageName()}.mjs`,
18
- cjs: `${getPackageName()}.cjs`,
19
- iife: `${getPackageName()}.iife.js`,
20
- };
21
-
22
- const formats = Object.keys(fileName) as Array<keyof typeof fileName>;
23
-
24
- module.exports = defineConfig({
25
- base: "./",
26
- build: {
27
- outDir: "./dist",
28
- lib: {
29
- entry: path.resolve(__dirname, "src/index.ts"),
30
- name: getPackageNameCamelCase(),
31
- formats,
32
- fileName: (format) => fileName[format],
33
- },
34
- },
35
- resolve: {
36
- alias: [
37
- { find: "@", replacement: path.resolve(__dirname, "src") },
38
- { find: "@@", replacement: path.resolve(__dirname) },
39
- ],
40
- },
41
- });