@quatrain/auth-supabase 1.2.2 → 1.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,7 +1,25 @@
1
1
  import { User } from '@quatrain/backend';
2
2
  import { AbstractAuthAdapter, AuthParameters } from '@quatrain/auth';
3
+ import { ApiMiddleware } from '@quatrain/api';
4
+ /**
5
+ * Authentication adapter implementing the Supabase SDK ecosystem.
6
+ * Acts as a centralized bridge handling signup, tokens, and middleware enforcement.
7
+ */
3
8
  export declare class SupabaseAuthAdapter extends AbstractAuthAdapter {
4
9
  protected _client: any;
10
+ /**
11
+ * Initializes a new instance securely with Supabase configuration keys.
12
+ *
13
+ * @param config - Must contain `supabaseUrl` and `supabaseKey`.
14
+ * @returns A constructed SupabaseAuthAdapter or null on invalid params.
15
+ */
16
+ static factory(config: any): SupabaseAuthAdapter | null;
17
+ /**
18
+ * Express middleware capturing Bearer JWT tokens to execute auth verification.
19
+ *
20
+ * @returns The middleware function.
21
+ */
22
+ middleware(): ApiMiddleware;
5
23
  constructor(params?: AuthParameters);
6
24
  /**
7
25
  * Register new user in authentication
@@ -9,15 +27,63 @@ export declare class SupabaseAuthAdapter extends AbstractAuthAdapter {
9
27
  * @returns user unique id
10
28
  */
11
29
  register(user: User, clearPassword?: string): Promise<any>;
30
+ /**
31
+ * Resolves a raw Bearer token via the Supabase Auth API (`getUser`).
32
+ *
33
+ * @param bearer - Raw JWT string.
34
+ * @returns The decoded user object.
35
+ * @throws {Error} If verification fails.
36
+ */
12
37
  getAuthToken(bearer: string): Promise<any>;
38
+ /**
39
+ * Obtains a new JWT access token by exchanging the persistent refresh token.
40
+ *
41
+ * @param refreshToken - The token.
42
+ * @returns Resolves the token packet.
43
+ */
13
44
  refreshToken(refreshToken: string): Promise<any>;
45
+ /**
46
+ * Instructs the Supabase client to destroy the current session.
47
+ *
48
+ * @param token - Target token.
49
+ */
14
50
  revokeAuthToken(token: string): Promise<false | undefined>;
51
+ /**
52
+ * Executes a direct login / session instantiation via `signInWithPassword`.
53
+ *
54
+ * @param login - Email string.
55
+ * @param password - Raw password.
56
+ * @returns Resolved user session.
57
+ */
15
58
  signup(login: string, password: string): Promise<false | {
16
59
  user: any;
17
60
  session: any;
18
61
  }>;
62
+ /**
63
+ * Disconnects and destroys the active session context.
64
+ *
65
+ * @returns True if successful.
66
+ */
19
67
  signout(): Promise<any>;
68
+ /**
69
+ * Modifies a Supabase Auth user record.
70
+ *
71
+ * @param user - Target user.
72
+ * @param updatable - The delta properties.
73
+ */
20
74
  update(user: User, updatable: any): Promise<any>;
75
+ /**
76
+ * (Unimplemented) Destroys the user context inside Supabase.
77
+ *
78
+ * @param user - Target user.
79
+ */
21
80
  delete(user: User): Promise<any>;
81
+ /**
82
+ * Merges specific attributes into the Supabase `user_metadata` field using the admin API.
83
+ *
84
+ * @param id - The target user ID.
85
+ * @param claims - The payload of new claims.
86
+ * @returns Resolved updated user wrapper.
87
+ */
22
88
  setCustomUserClaims(id: string, claims: any): Promise<any>;
23
89
  }
@@ -47,7 +47,47 @@ const auth_1 = require("@quatrain/auth");
47
47
  const supabase_js_1 = require("@supabase/supabase-js");
48
48
  const nativeFetch = __importStar(require("node-fetch-native"));
49
49
  // Create a single supabase client for interacting with your database
50
+ /**
51
+ * Authentication adapter implementing the Supabase SDK ecosystem.
52
+ * Acts as a centralized bridge handling signup, tokens, and middleware enforcement.
53
+ */
50
54
  class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
55
+ /**
56
+ * Initializes a new instance securely with Supabase configuration keys.
57
+ *
58
+ * @param config - Must contain `supabaseUrl` and `supabaseKey`.
59
+ * @returns A constructed SupabaseAuthAdapter or null on invalid params.
60
+ */
61
+ static factory(config) {
62
+ if (!config.supabaseUrl || !config.supabaseKey)
63
+ return null;
64
+ return new SupabaseAuthAdapter({ config });
65
+ }
66
+ /**
67
+ * Express middleware capturing Bearer JWT tokens to execute auth verification.
68
+ *
69
+ * @returns The middleware function.
70
+ */
71
+ middleware() {
72
+ return (req, res) => __awaiter(this, void 0, void 0, function* () {
73
+ var _a;
74
+ const bearer = (((_a = req.headers) === null || _a === void 0 ? void 0 : _a.authorization) || '').split(' ')[1] || '';
75
+ if (bearer) {
76
+ try {
77
+ const user = yield this.getAuthToken(bearer);
78
+ if (user) {
79
+ return true; // Authorized
80
+ }
81
+ }
82
+ catch (e) {
83
+ auth_1.Auth.error(`[SupabaseAuthAdapter] Middleware token verification failed: ${e.message}`);
84
+ }
85
+ }
86
+ res.setHeader('WWW-Authenticate', 'Bearer realm="Core API"');
87
+ res.status(401).send('Authentication required.');
88
+ return false;
89
+ });
90
+ }
51
91
  constructor(params = {}) {
52
92
  super(params);
53
93
  this._client = (0, supabase_js_1.createClient)(params.config.supabaseUrl, params.config.supabaseKey, {
@@ -88,6 +128,13 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
88
128
  }
89
129
  });
90
130
  }
131
+ /**
132
+ * Resolves a raw Bearer token via the Supabase Auth API (`getUser`).
133
+ *
134
+ * @param bearer - Raw JWT string.
135
+ * @returns The decoded user object.
136
+ * @throws {Error} If verification fails.
137
+ */
91
138
  getAuthToken(bearer) {
92
139
  return __awaiter(this, void 0, void 0, function* () {
93
140
  const token = yield this._client.auth.getUser(bearer);
@@ -97,6 +144,12 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
97
144
  throw new Error('Unable to retrieve auth token from Supabase');
98
145
  });
99
146
  }
147
+ /**
148
+ * Obtains a new JWT access token by exchanging the persistent refresh token.
149
+ *
150
+ * @param refreshToken - The token.
151
+ * @returns Resolves the token packet.
152
+ */
100
153
  refreshToken(refreshToken) {
101
154
  return __awaiter(this, void 0, void 0, function* () {
102
155
  const url = `${this._params.config.supabaseUrl}/auth/v1/token?grant_type=refresh_token`;
@@ -113,6 +166,11 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
113
166
  return data;
114
167
  });
115
168
  }
169
+ /**
170
+ * Instructs the Supabase client to destroy the current session.
171
+ *
172
+ * @param token - Target token.
173
+ */
116
174
  revokeAuthToken(token) {
117
175
  return __awaiter(this, void 0, void 0, function* () {
118
176
  // Careful, this only delete tokens on client side, not on server side
@@ -123,6 +181,13 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
123
181
  }
124
182
  });
125
183
  }
184
+ /**
185
+ * Executes a direct login / session instantiation via `signInWithPassword`.
186
+ *
187
+ * @param login - Email string.
188
+ * @param password - Raw password.
189
+ * @returns Resolved user session.
190
+ */
126
191
  signup(login, password) {
127
192
  return __awaiter(this, void 0, void 0, function* () {
128
193
  const { data, error } = yield this._client.auth.signInWithPassword({
@@ -136,6 +201,11 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
136
201
  return { user: data.user, session: data.session };
137
202
  });
138
203
  }
204
+ /**
205
+ * Disconnects and destroys the active session context.
206
+ *
207
+ * @returns True if successful.
208
+ */
139
209
  signout() {
140
210
  return __awaiter(this, void 0, void 0, function* () {
141
211
  const { error } = yield this._client.auth.signOut();
@@ -146,6 +216,12 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
146
216
  return true;
147
217
  });
148
218
  }
219
+ /**
220
+ * Modifies a Supabase Auth user record.
221
+ *
222
+ * @param user - Target user.
223
+ * @param updatable - The delta properties.
224
+ */
149
225
  update(user, updatable) {
150
226
  return __awaiter(this, void 0, void 0, function* () {
151
227
  auth_1.Auth.debug('auth data to update', JSON.stringify(updatable));
@@ -164,11 +240,23 @@ class SupabaseAuthAdapter extends auth_1.AbstractAuthAdapter {
164
240
  }
165
241
  });
166
242
  }
243
+ /**
244
+ * (Unimplemented) Destroys the user context inside Supabase.
245
+ *
246
+ * @param user - Target user.
247
+ */
167
248
  delete(user) {
168
249
  return __awaiter(this, void 0, void 0, function* () {
169
250
  // return await getAuth().deleteUser(user.uid)
170
251
  });
171
252
  }
253
+ /**
254
+ * Merges specific attributes into the Supabase `user_metadata` field using the admin API.
255
+ *
256
+ * @param id - The target user ID.
257
+ * @param claims - The payload of new claims.
258
+ * @returns Resolved updated user wrapper.
259
+ */
172
260
  setCustomUserClaims(id, claims) {
173
261
  return __awaiter(this, void 0, void 0, function* () {
174
262
  auth_1.Auth.debug(`Updating user ${id} with claims ${JSON.stringify(claims)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/auth-supabase",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -19,8 +19,9 @@
19
19
  },
20
20
  "author": "Quatrain Développement SAS <developers@quatrain.com>",
21
21
  "dependencies": {
22
- "@quatrain/auth": "^1.2.1",
23
- "@quatrain/backend": "^1.2.5",
22
+ "@quatrain/api": "^1.1.5",
23
+ "@quatrain/auth": "^1.2.2",
24
+ "@quatrain/backend": "^1.2.6",
24
25
  "@supabase/supabase-js": "^2.87.3",
25
26
  "node-fetch-native": "^1.6.4"
26
27
  },
@@ -5,13 +5,55 @@ import {
5
5
  AuthenticationError,
6
6
  AuthParameters,
7
7
  } from '@quatrain/auth'
8
+ import { ApiMiddleware, ApiRequest, ApiResponse } from '@quatrain/api'
8
9
  import { createClient } from '@supabase/supabase-js'
9
10
  import * as nativeFetch from 'node-fetch-native'
10
11
 
11
12
  // Create a single supabase client for interacting with your database
13
+ /**
14
+ * Authentication adapter implementing the Supabase SDK ecosystem.
15
+ * Acts as a centralized bridge handling signup, tokens, and middleware enforcement.
16
+ */
12
17
  export class SupabaseAuthAdapter extends AbstractAuthAdapter {
13
18
  protected _client: any
14
19
 
20
+ /**
21
+ * Initializes a new instance securely with Supabase configuration keys.
22
+ *
23
+ * @param config - Must contain `supabaseUrl` and `supabaseKey`.
24
+ * @returns A constructed SupabaseAuthAdapter or null on invalid params.
25
+ */
26
+ static factory(config: any): SupabaseAuthAdapter | null {
27
+ if (!config.supabaseUrl || !config.supabaseKey) return null
28
+ return new SupabaseAuthAdapter({ config })
29
+ }
30
+
31
+ /**
32
+ * Express middleware capturing Bearer JWT tokens to execute auth verification.
33
+ *
34
+ * @returns The middleware function.
35
+ */
36
+ public middleware(): ApiMiddleware {
37
+ return async (req: ApiRequest, res: ApiResponse): Promise<boolean> => {
38
+ const bearer = ((req.headers?.authorization as string) || '').split(' ')[1] || ''
39
+
40
+ if (bearer) {
41
+ try {
42
+ const user = await this.getAuthToken(bearer)
43
+ if (user) {
44
+ return true // Authorized
45
+ }
46
+ } catch(e) {
47
+ Auth.error(`[SupabaseAuthAdapter] Middleware token verification failed: ${(e as Error).message}`)
48
+ }
49
+ }
50
+
51
+ res.setHeader('WWW-Authenticate', 'Bearer realm="Core API"')
52
+ res.status(401).send('Authentication required.')
53
+ return false
54
+ }
55
+ }
56
+
15
57
  constructor(params: AuthParameters = {}) {
16
58
  super(params)
17
59
  this._client = createClient(
@@ -63,6 +105,13 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
63
105
  }
64
106
  }
65
107
 
108
+ /**
109
+ * Resolves a raw Bearer token via the Supabase Auth API (`getUser`).
110
+ *
111
+ * @param bearer - Raw JWT string.
112
+ * @returns The decoded user object.
113
+ * @throws {Error} If verification fails.
114
+ */
66
115
  async getAuthToken(bearer: string) {
67
116
  const token = await this._client.auth.getUser(bearer)
68
117
  if (token.data && token.data.user) {
@@ -71,6 +120,12 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
71
120
  throw new Error('Unable to retrieve auth token from Supabase')
72
121
  }
73
122
 
123
+ /**
124
+ * Obtains a new JWT access token by exchanging the persistent refresh token.
125
+ *
126
+ * @param refreshToken - The token.
127
+ * @returns Resolves the token packet.
128
+ */
74
129
  async refreshToken(refreshToken: string) {
75
130
  const url = `${this._params.config.supabaseUrl}/auth/v1/token?grant_type=refresh_token`
76
131
  const response = await nativeFetch.fetch(url, {
@@ -88,6 +143,11 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
88
143
  return data
89
144
  }
90
145
 
146
+ /**
147
+ * Instructs the Supabase client to destroy the current session.
148
+ *
149
+ * @param token - Target token.
150
+ */
91
151
  async revokeAuthToken(token: string) {
92
152
  // Careful, this only delete tokens on client side, not on server side
93
153
  const { error } = await this.signout()
@@ -97,6 +157,13 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
97
157
  }
98
158
  }
99
159
 
160
+ /**
161
+ * Executes a direct login / session instantiation via `signInWithPassword`.
162
+ *
163
+ * @param login - Email string.
164
+ * @param password - Raw password.
165
+ * @returns Resolved user session.
166
+ */
100
167
  async signup(login: string, password: string) {
101
168
  const { data, error } = await this._client.auth.signInWithPassword({
102
169
  email: login,
@@ -111,6 +178,11 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
111
178
  return { user: data.user, session: data.session }
112
179
  }
113
180
 
181
+ /**
182
+ * Disconnects and destroys the active session context.
183
+ *
184
+ * @returns True if successful.
185
+ */
114
186
  async signout(): Promise<any> {
115
187
  const { error } = await this._client.auth.signOut()
116
188
  if (error !== null) {
@@ -120,6 +192,12 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
120
192
  return true
121
193
  }
122
194
 
195
+ /**
196
+ * Modifies a Supabase Auth user record.
197
+ *
198
+ * @param user - Target user.
199
+ * @param updatable - The delta properties.
200
+ */
123
201
  async update(user: User, updatable: any): Promise<any> {
124
202
  Auth.debug('auth data to update', JSON.stringify(updatable))
125
203
 
@@ -140,10 +218,22 @@ export class SupabaseAuthAdapter extends AbstractAuthAdapter {
140
218
  }
141
219
  }
142
220
 
221
+ /**
222
+ * (Unimplemented) Destroys the user context inside Supabase.
223
+ *
224
+ * @param user - Target user.
225
+ */
143
226
  async delete(user: User): Promise<any> {
144
227
  // return await getAuth().deleteUser(user.uid)
145
228
  }
146
229
 
230
+ /**
231
+ * Merges specific attributes into the Supabase `user_metadata` field using the admin API.
232
+ *
233
+ * @param id - The target user ID.
234
+ * @param claims - The payload of new claims.
235
+ * @returns Resolved updated user wrapper.
236
+ */
147
237
  async setCustomUserClaims(id: string, claims: any) {
148
238
  Auth.debug(`Updating user ${id} with claims ${JSON.stringify(claims)}`)
149
239
  const { data, error } = await this._client.auth.admin.updateUserById(id, {