@absolutejs/auth 0.2.4 → 0.2.6

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/src/status.ts ADDED
@@ -0,0 +1,100 @@
1
+ import { Elysia } from 'elysia';
2
+ import { sessionStore } from './sessionStore';
3
+ import { isRefreshableProvider } from './typeGuards';
4
+ import { ClientProviders } from './types';
5
+
6
+ type StatusProps = {
7
+ clientProviders: ClientProviders;
8
+ statusRoute?: string;
9
+ onStatus?: () => void;
10
+ };
11
+
12
+ export const status = <UserType>({
13
+ clientProviders,
14
+ statusRoute = 'auth-status',
15
+ onStatus
16
+ }: StatusProps) =>
17
+ new Elysia()
18
+ .use(sessionStore<UserType>())
19
+ .get(
20
+ `/${statusRoute}`,
21
+ async ({
22
+ error,
23
+ cookie: { user_session_id, auth_provider },
24
+ store: { session }
25
+ }) => {
26
+ try {
27
+ if (user_session_id.value === undefined) {
28
+ return new Response(
29
+ JSON.stringify({ isLoggedIn: false, user: null }),
30
+ {
31
+ headers: { 'Content-Type': 'application/json' }
32
+ }
33
+ );
34
+ }
35
+
36
+ if (auth_provider.value === undefined) {
37
+ return new Response(
38
+ JSON.stringify({ isLoggedIn: false, user: null }),
39
+ {
40
+ headers: { 'Content-Type': 'application/json' }
41
+ }
42
+ );
43
+ }
44
+
45
+ const normalizedProvider =
46
+ auth_provider.value.toLowerCase();
47
+ const { providerInstance } =
48
+ clientProviders[normalizedProvider];
49
+
50
+ // Returns an error if the provider is not refreshable but
51
+ // consider another approach to be more inclusive of providers
52
+ if (!isRefreshableProvider(providerInstance)) {
53
+ return error(
54
+ 'Not Implemented',
55
+ 'Provider is not refreshable'
56
+ );
57
+ }
58
+
59
+ const userSession = session[user_session_id.value];
60
+ // console.log(
61
+ // 'Session:',
62
+ // session,
63
+ // 'User Session ID:',
64
+ // user_session_id.value
65
+ // );
66
+ // Return null because the user is not logged in, its not an error just a status
67
+ if (userSession === undefined) {
68
+ return new Response(
69
+ JSON.stringify({ isLoggedIn: false, user: null }),
70
+ {
71
+ headers: { 'Content-Type': 'application/json' }
72
+ }
73
+ );
74
+ }
75
+
76
+ const { user } = userSession;
77
+
78
+ onStatus?.();
79
+
80
+ return new Response(
81
+ JSON.stringify({ isLoggedIn: true, user }),
82
+ {
83
+ headers: { 'Content-Type': 'application/json' }
84
+ }
85
+ );
86
+ } catch (err) {
87
+ if (err instanceof Error) {
88
+ return error(
89
+ 'Internal Server Error',
90
+ `Error: ${err.message} - ${err.stack ?? ''}`
91
+ );
92
+ }
93
+
94
+ return error(
95
+ 'Internal Server Error',
96
+ `Unknown Error: ${err}`
97
+ );
98
+ }
99
+ }
100
+ );
@@ -0,0 +1,32 @@
1
+ import { OAuth2Tokens } from 'arctic';
2
+ import { providers } from './providers';
3
+ import { Providers } from './types';
4
+
5
+ export const isRefreshableProvider = (
6
+ provider: InstanceType<(typeof providers)[Providers]>
7
+ ): provider is InstanceType<(typeof providers)[Providers]> & {
8
+ refreshAccessToken: () => Promise<OAuth2Tokens>;
9
+ } =>
10
+ 'refreshAccessToken' in provider &&
11
+ typeof provider.refreshAccessToken === 'function';
12
+
13
+ export const isRevocableProvider = (
14
+ provider: InstanceType<(typeof providers)[Providers]>
15
+ ): provider is InstanceType<(typeof providers)[Providers]> & {
16
+ revokeAccessToken: (token: string) => Promise<void>;
17
+ } =>
18
+ 'revokeAccessToken' in provider &&
19
+ typeof provider.revokeAccessToken === 'function';
20
+
21
+ export const isValidProviderKey = (
22
+ provider: string
23
+ ): provider is keyof typeof providers =>
24
+ Object.keys(providers)
25
+ .map((key) => key.toLowerCase())
26
+ .includes(provider.toLowerCase());
27
+
28
+ export const isValidUser = <UserType>(user: unknown): user is UserType => true;
29
+
30
+ export const isNonEmptyString = (
31
+ str: string | null | undefined
32
+ ): str is string => str !== null && str !== undefined && str.trim() !== '';
package/src/types.ts ADDED
@@ -0,0 +1,78 @@
1
+ import { Cookie } from 'elysia';
2
+ import { providers } from './providers';
3
+
4
+ type SessionData<UserType> = {
5
+ user: UserType;
6
+ expiresAt: number;
7
+ };
8
+
9
+ type Oauth2ConfigOptions = {
10
+ [K in Providers]?: {
11
+ credentials: ConstructorParameters<(typeof providers)[K]>;
12
+ scopes?: string[];
13
+ searchParams?: [string, string][];
14
+ };
15
+ };
16
+
17
+ export type Providers = keyof typeof providers;
18
+
19
+ export type SessionRecord<UserType> = Record<
20
+ string,
21
+ SessionData<UserType> | undefined
22
+ >;
23
+
24
+ export type UserFunctionProps = {
25
+ authProvider: string;
26
+ decodedIdToken: {
27
+ [key: string]: string | undefined;
28
+ };
29
+ };
30
+
31
+ export type CreateUser<UserType> = ({
32
+ decodedIdToken,
33
+ authProvider
34
+ }: UserFunctionProps) => Promise<UserType>;
35
+
36
+ export type GetUser<UserType> = ({
37
+ decodedIdToken,
38
+ authProvider
39
+ }: UserFunctionProps) => Promise<UserType | null>;
40
+
41
+ export type OnCallback<UserType> = ({
42
+ authProvider,
43
+ decodedIdToken,
44
+ session,
45
+ user_session_id
46
+ }: {
47
+ authProvider: string;
48
+ decodedIdToken: {
49
+ [key: string]: string | undefined;
50
+ };
51
+ session: SessionRecord<UserType>;
52
+ user_session_id: Cookie<string | undefined>;
53
+ }) => void | Promise<void>;
54
+
55
+ export type AbsoluteAuthProps<UserType> = {
56
+ config: Oauth2ConfigOptions;
57
+ authorizeRoute?: string;
58
+ callbackRoute?: string;
59
+ refreshRoute?: string;
60
+ revokeRoute?: string;
61
+ logoutRoute?: string;
62
+ statusRoute?: string;
63
+ onAuthorize?: () => void;
64
+ onCallback?: OnCallback<UserType>;
65
+ onStatus?: () => void;
66
+ onRefresh?: () => void;
67
+ onLogout?: () => void;
68
+ onRevoke?: () => void;
69
+ };
70
+
71
+ export type ClientProviders = Record<
72
+ string,
73
+ {
74
+ providerInstance: InstanceType<(typeof providers)[Providers]>;
75
+ scopes: string[];
76
+ searchParams: [string, string][];
77
+ }
78
+ >;
package/src/utils.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Cookie } from 'elysia';
2
+ import { MILLISECONDS_IN_A_DAY } from './constants';
3
+ import { AbsoluteAuthProps, CreateUser, GetUser, SessionRecord } from './types';
4
+ import { isValidUser } from './typeGuards';
5
+
6
+ type InsantiateUserSessionProps<UserType> = {
7
+ authProvider: string;
8
+ decodedIdToken: {
9
+ [key: string]: string | undefined;
10
+ };
11
+ session: SessionRecord<UserType>;
12
+ user_session_id: Cookie<string | undefined>;
13
+ createUser?: CreateUser<UserType>;
14
+ getUser?: GetUser<UserType>;
15
+ };
16
+
17
+ export const instantiateUserSession = async <UserType>({
18
+ authProvider,
19
+ decodedIdToken,
20
+ user_session_id,
21
+ session,
22
+ getUser,
23
+ createUser
24
+ }: InsantiateUserSessionProps<UserType>) => {
25
+ let user = await getUser?.({
26
+ authProvider,
27
+ decodedIdToken
28
+ });
29
+ user = user ?? (await createUser?.({ authProvider, decodedIdToken }));
30
+
31
+ // TODO : See if theres a better way to check valid user and not throw an error
32
+ if (!isValidUser<UserType>(user))
33
+ throw new Error('Internal Server Error - Invalid user schema');
34
+
35
+ const sessionKey = crypto.randomUUID();
36
+
37
+ session[sessionKey] = {
38
+ expiresAt: Date.now() + MILLISECONDS_IN_A_DAY,
39
+ user
40
+ };
41
+
42
+ user_session_id.set({
43
+ httpOnly: true,
44
+ sameSite: 'lax',
45
+ secure: true,
46
+ value: sessionKey
47
+ });
48
+ };
49
+
50
+ export const createAuthConfig = <UserType>(
51
+ props: AbsoluteAuthProps<UserType>
52
+ ) => props;
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "esModuleInterop": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "outDir": "dist",
10
+ "strict": true,
11
+ "declaration": true,
12
+ "skipLibCheck": true,
13
+ "lib": ["DOM", "DOM.Iterable", "ESNext"]
14
+ },
15
+ "include": ["src/**/*", "example/**/*"],
16
+ "exclude": ["node_modules"]
17
+ }
@@ -1 +0,0 @@
1
- export declare const AuthOptions: () => import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- export declare const Example: () => import("react/jsx-runtime").JSX.Element;
@@ -1,6 +0,0 @@
1
- type HeadProps = {
2
- title?: string;
3
- icon?: string;
4
- };
5
- export declare const Head: ({ title, icon }: HeadProps) => import("react/jsx-runtime").JSX.Element;
6
- export {};
@@ -1,8 +0,0 @@
1
- import { ReactNode } from 'react';
2
- type ModalProps = {
3
- isOpen: boolean;
4
- onClose: () => void;
5
- children: ReactNode;
6
- };
7
- export declare const Modal: ({ isOpen, onClose, children }: ModalProps) => import("react/jsx-runtime").JSX.Element | null;
8
- export {};
@@ -1,10 +0,0 @@
1
- import type { Dispatch, SetStateAction } from 'react';
2
- import type { User } from '../db/schema';
3
- type NavbarProps = {
4
- user: User | undefined;
5
- modalOpen: boolean;
6
- handleLogOut: () => Promise<void>;
7
- setModalOpen: Dispatch<SetStateAction<boolean>>;
8
- };
9
- export declare const Navbar: ({ user, handleLogOut, modalOpen, setModalOpen }: NavbarProps) => import("react/jsx-runtime").JSX.Element;
10
- export {};
@@ -1 +0,0 @@
1
- export declare const NotAuthorized: () => import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- export declare const Protected: () => import("react/jsx-runtime").JSX.Element;
@@ -1 +0,0 @@
1
- export {};
@@ -1,248 +0,0 @@
1
- import { NeonHttpDatabase } from 'drizzle-orm/neon-http';
2
- export declare const users: import("drizzle-orm/pg-core").PgTableWithColumns<{
3
- name: "users";
4
- schema: undefined;
5
- columns: {
6
- given_name: import("drizzle-orm/pg-core").PgColumn<{
7
- name: "given_name";
8
- tableName: "users";
9
- dataType: "string";
10
- columnType: "PgVarchar";
11
- data: string;
12
- driverParam: string;
13
- notNull: false;
14
- hasDefault: false;
15
- isPrimaryKey: false;
16
- isAutoincrement: false;
17
- hasRuntimeDefault: false;
18
- enumValues: [string, ...string[]];
19
- baseColumn: never;
20
- identity: undefined;
21
- generated: undefined;
22
- }, {}, {
23
- length: 255;
24
- }>;
25
- family_name: import("drizzle-orm/pg-core").PgColumn<{
26
- name: "family_name";
27
- tableName: "users";
28
- dataType: "string";
29
- columnType: "PgVarchar";
30
- data: string;
31
- driverParam: string;
32
- notNull: false;
33
- hasDefault: false;
34
- isPrimaryKey: false;
35
- isAutoincrement: false;
36
- hasRuntimeDefault: false;
37
- enumValues: [string, ...string[]];
38
- baseColumn: never;
39
- identity: undefined;
40
- generated: undefined;
41
- }, {}, {
42
- length: 255;
43
- }>;
44
- email: import("drizzle-orm/pg-core").PgColumn<{
45
- name: "email";
46
- tableName: "users";
47
- dataType: "string";
48
- columnType: "PgVarchar";
49
- data: string;
50
- driverParam: string;
51
- notNull: false;
52
- hasDefault: false;
53
- isPrimaryKey: false;
54
- isAutoincrement: false;
55
- hasRuntimeDefault: false;
56
- enumValues: [string, ...string[]];
57
- baseColumn: never;
58
- identity: undefined;
59
- generated: undefined;
60
- }, {}, {
61
- length: 255;
62
- }>;
63
- created_at: import("drizzle-orm/pg-core").PgColumn<{
64
- name: "created_at";
65
- tableName: "users";
66
- dataType: "date";
67
- columnType: "PgTimestamp";
68
- data: Date;
69
- driverParam: string;
70
- notNull: true;
71
- hasDefault: true;
72
- isPrimaryKey: false;
73
- isAutoincrement: false;
74
- hasRuntimeDefault: false;
75
- enumValues: undefined;
76
- baseColumn: never;
77
- identity: undefined;
78
- generated: undefined;
79
- }, {}, {}>;
80
- auth_sub: import("drizzle-orm/pg-core").PgColumn<{
81
- name: "auth_sub";
82
- tableName: "users";
83
- dataType: "string";
84
- columnType: "PgVarchar";
85
- data: string;
86
- driverParam: string;
87
- notNull: true;
88
- hasDefault: false;
89
- isPrimaryKey: true;
90
- isAutoincrement: false;
91
- hasRuntimeDefault: false;
92
- enumValues: [string, ...string[]];
93
- baseColumn: never;
94
- identity: undefined;
95
- generated: undefined;
96
- }, {}, {
97
- length: 255;
98
- }>;
99
- picture: import("drizzle-orm/pg-core").PgColumn<{
100
- name: "picture";
101
- tableName: "users";
102
- dataType: "string";
103
- columnType: "PgVarchar";
104
- data: string;
105
- driverParam: string;
106
- notNull: false;
107
- hasDefault: false;
108
- isPrimaryKey: false;
109
- isAutoincrement: false;
110
- hasRuntimeDefault: false;
111
- enumValues: [string, ...string[]];
112
- baseColumn: never;
113
- identity: undefined;
114
- generated: undefined;
115
- }, {}, {
116
- length: 255;
117
- }>;
118
- };
119
- dialect: "pg";
120
- }>;
121
- export declare const schema: {
122
- users: import("drizzle-orm/pg-core").PgTableWithColumns<{
123
- name: "users";
124
- schema: undefined;
125
- columns: {
126
- given_name: import("drizzle-orm/pg-core").PgColumn<{
127
- name: "given_name";
128
- tableName: "users";
129
- dataType: "string";
130
- columnType: "PgVarchar";
131
- data: string;
132
- driverParam: string;
133
- notNull: false;
134
- hasDefault: false;
135
- isPrimaryKey: false;
136
- isAutoincrement: false;
137
- hasRuntimeDefault: false;
138
- enumValues: [string, ...string[]];
139
- baseColumn: never;
140
- identity: undefined;
141
- generated: undefined;
142
- }, {}, {
143
- length: 255;
144
- }>;
145
- family_name: import("drizzle-orm/pg-core").PgColumn<{
146
- name: "family_name";
147
- tableName: "users";
148
- dataType: "string";
149
- columnType: "PgVarchar";
150
- data: string;
151
- driverParam: string;
152
- notNull: false;
153
- hasDefault: false;
154
- isPrimaryKey: false;
155
- isAutoincrement: false;
156
- hasRuntimeDefault: false;
157
- enumValues: [string, ...string[]];
158
- baseColumn: never;
159
- identity: undefined;
160
- generated: undefined;
161
- }, {}, {
162
- length: 255;
163
- }>;
164
- email: import("drizzle-orm/pg-core").PgColumn<{
165
- name: "email";
166
- tableName: "users";
167
- dataType: "string";
168
- columnType: "PgVarchar";
169
- data: string;
170
- driverParam: string;
171
- notNull: false;
172
- hasDefault: false;
173
- isPrimaryKey: false;
174
- isAutoincrement: false;
175
- hasRuntimeDefault: false;
176
- enumValues: [string, ...string[]];
177
- baseColumn: never;
178
- identity: undefined;
179
- generated: undefined;
180
- }, {}, {
181
- length: 255;
182
- }>;
183
- created_at: import("drizzle-orm/pg-core").PgColumn<{
184
- name: "created_at";
185
- tableName: "users";
186
- dataType: "date";
187
- columnType: "PgTimestamp";
188
- data: Date;
189
- driverParam: string;
190
- notNull: true;
191
- hasDefault: true;
192
- isPrimaryKey: false;
193
- isAutoincrement: false;
194
- hasRuntimeDefault: false;
195
- enumValues: undefined;
196
- baseColumn: never;
197
- identity: undefined;
198
- generated: undefined;
199
- }, {}, {}>;
200
- auth_sub: import("drizzle-orm/pg-core").PgColumn<{
201
- name: "auth_sub";
202
- tableName: "users";
203
- dataType: "string";
204
- columnType: "PgVarchar";
205
- data: string;
206
- driverParam: string;
207
- notNull: true;
208
- hasDefault: false;
209
- isPrimaryKey: true;
210
- isAutoincrement: false;
211
- hasRuntimeDefault: false;
212
- enumValues: [string, ...string[]];
213
- baseColumn: never;
214
- identity: undefined;
215
- generated: undefined;
216
- }, {}, {
217
- length: 255;
218
- }>;
219
- picture: import("drizzle-orm/pg-core").PgColumn<{
220
- name: "picture";
221
- tableName: "users";
222
- dataType: "string";
223
- columnType: "PgVarchar";
224
- data: string;
225
- driverParam: string;
226
- notNull: false;
227
- hasDefault: false;
228
- isPrimaryKey: false;
229
- isAutoincrement: false;
230
- hasRuntimeDefault: false;
231
- enumValues: [string, ...string[]];
232
- baseColumn: never;
233
- identity: undefined;
234
- generated: undefined;
235
- }, {}, {
236
- length: 255;
237
- }>;
238
- };
239
- dialect: "pg";
240
- }>;
241
- };
242
- export type schemaType = typeof schema;
243
- export type User = typeof users.$inferSelect;
244
- export type NewUser = typeof users.$inferInsert;
245
- export type DatabaseFunctionProps = {
246
- db: NeonHttpDatabase<schemaType>;
247
- schema: schemaType;
248
- };
@@ -1,19 +0,0 @@
1
- export declare const useAuthStatus: () => {
2
- handleLogOut: () => Promise<void>;
3
- setUser: import("react").Dispatch<import("react").SetStateAction<{
4
- given_name: string | null;
5
- family_name: string | null;
6
- email: string | null;
7
- created_at: Date;
8
- auth_sub: string;
9
- picture: string | null;
10
- } | undefined>>;
11
- user: {
12
- given_name: string | null;
13
- family_name: string | null;
14
- email: string | null;
15
- created_at: Date;
16
- auth_sub: string;
17
- picture: string | null;
18
- } | undefined;
19
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export declare const getLocalIPAddress: () => string;
@@ -1,2 +0,0 @@
1
- import type { ComponentType } from 'react';
2
- export declare const handlePageRequest: (pageComponent: ComponentType, index: string) => Promise<Response>;
@@ -1,15 +0,0 @@
1
- import { CSSProperties } from 'react';
2
- export declare const styleReset = "\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-weight: inherit;\n }\n";
3
- export declare const bodyDefault: CSSProperties;
4
- export declare const mainDefault: CSSProperties;
5
- export declare const htmlDefault: CSSProperties;
6
- type ButtonStyleProps = {
7
- backgroundColor?: string;
8
- color?: string;
9
- width?: string;
10
- };
11
- export declare const buttonStyle: ({ backgroundColor, color, width }: ButtonStyleProps) => CSSProperties;
12
- export declare const authContainerStyle: CSSProperties;
13
- export declare const textButtonStyle: CSSProperties;
14
- export declare const contentStyle: CSSProperties;
15
- export {};
@@ -1,36 +0,0 @@
1
- import type { DatabaseFunctionProps, NewUser } from '../db/schema';
2
- import { UserFunctionProps } from '../../src/types';
3
- export declare const getDBUser: ({ authSub, db, schema }: DatabaseFunctionProps & {
4
- authSub: string;
5
- }) => Promise<{
6
- given_name: string | null;
7
- family_name: string | null;
8
- email: string | null;
9
- created_at: Date;
10
- auth_sub: string;
11
- picture: string | null;
12
- } | null>;
13
- export declare const createDBUser: ({ auth_sub, given_name, family_name, email, picture, db, schema }: DatabaseFunctionProps & NewUser) => Promise<{
14
- given_name: string | null;
15
- family_name: string | null;
16
- email: string | null;
17
- created_at: Date;
18
- auth_sub: string;
19
- picture: string | null;
20
- }>;
21
- export declare const createUser: ({ decodedIdToken, authProvider, db, schema }: UserFunctionProps & DatabaseFunctionProps) => Promise<{
22
- given_name: string | null;
23
- family_name: string | null;
24
- email: string | null;
25
- created_at: Date;
26
- auth_sub: string;
27
- picture: string | null;
28
- }>;
29
- export declare const getUser: ({ decodedIdToken, authProvider, db, schema }: UserFunctionProps & DatabaseFunctionProps) => Promise<{
30
- given_name: string | null;
31
- family_name: string | null;
32
- email: string | null;
33
- created_at: Date;
34
- auth_sub: string;
35
- picture: string | null;
36
- } | null>;