From 02fdf193386aff404f64ef761991e2d4f1e9fad9 Mon Sep 17 00:00:00 2001 From: Nico Kempe Date: Sat, 22 Mar 2025 20:54:32 +0100 Subject: [PATCH 1/2] feat(sessions): Add listSessions and revokeSession methods to GoTrueClient - Introduces two new public methods in GoTrueClient to enhance session management. - listSessions retrieves all active sessions for the current user via a GET request to the /sessions endpoint. - revokeSession revokes a specific session via a DELETE request to /sessions/{sessionId}. If the revoked session matches the current session, it removes the session from local storage. - Both methods follow the existing initialization, locking, and session handling patterns. - JSDoc comments have been added for documentation and clarity. More context: https://github.com/orgs/supabase/discussions/34340 --- src/GoTrueClient.ts | 69 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/GoTrueClient.ts b/src/GoTrueClient.ts index 517c7cb9..90b056b2 100644 --- a/src/GoTrueClient.ts +++ b/src/GoTrueClient.ts @@ -1824,6 +1824,75 @@ export default class GoTrueClient { } } + /** + * Retrieves all active sessions for the current user. + * + * This method calls the GET /sessions endpoint on the GoTrue server. + * It returns a promise that resolves with an object containing an array of Session objects + * or an error if the request fails. + * + * @returns {Promise<{ data: Session[] | null; error: AuthError | null }>} The active sessions and any error encountered. + */ + async listSessions(): Promise<{ data: Session[] | null; error: AuthError | null }> { + await this.initializePromise; + return await this._acquireLock(-1, async () => { + return await this._useSession(async (result) => { + const { data: { session }, error } = result; + if (error) return { data: null, error }; + if (!session) return { data: null, error: new AuthSessionMissingError() }; + const { data: sessionsData, error: sessionsError } = await _request( + this.fetch, + 'GET', + `${this.url}/sessions`, + { + headers: this.headers, + jwt: session.access_token, + xform: (r) => r, + } + ); + if (sessionsError) return { data: null, error: sessionsError }; + return { data: sessionsData as Session[], error: null }; + }); + }); + } + + /** + * Revokes a specific session for the current user. + * + * This method calls the DELETE /sessions/{sessionId} endpoint on the GoTrue server. + * It sends the request using the current session's access token. If the revoked session is the current one, + * the session is also removed from local storage. + * + * @param {string} sessionId - The unique identifier of the session to revoke. + * @returns {Promise<{ error: AuthError | null }>} An object containing an error if the revocation fails. + */ + async revokeSession(sessionId: string): Promise<{ error: AuthError | null }> { + await this.initializePromise; + return await this._acquireLock(-1, async () => { + return await this._useSession(async (result) => { + const { data: { session }, error } = result; + if (error) return { error }; + if (!session) return { error: new AuthSessionMissingError() }; + const { error: revokeError } = await _request( + this.fetch, + 'DELETE', + `${this.url}/sessions/${sessionId}`, + { + headers: this.headers, + jwt: session.access_token, + } + ); + if (revokeError) return { error: revokeError }; + // If the revoked session is the current one, remove it from storage. + const currentSession = session as Session & { id?: string }; + if (currentSession.id && currentSession.id === sessionId) { + await this._removeSession(); + } + return { error: null }; + }); + }); + } + /** * Generates a new JWT. * @param refreshToken A valid refresh token that was returned on login. From 90cfbfc8614306ae547998ab33a2012247f60a49 Mon Sep 17 00:00:00 2001 From: Nico Kempe Date: Sat, 22 Mar 2025 20:59:13 +0100 Subject: [PATCH 2/2] lint(sessions): Update formatting for listSessions and revokeSession methods --- src/GoTrueClient.ts | 46 +++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/GoTrueClient.ts b/src/GoTrueClient.ts index 90b056b2..f4c78a86 100644 --- a/src/GoTrueClient.ts +++ b/src/GoTrueClient.ts @@ -1834,12 +1834,15 @@ export default class GoTrueClient { * @returns {Promise<{ data: Session[] | null; error: AuthError | null }>} The active sessions and any error encountered. */ async listSessions(): Promise<{ data: Session[] | null; error: AuthError | null }> { - await this.initializePromise; + await this.initializePromise return await this._acquireLock(-1, async () => { return await this._useSession(async (result) => { - const { data: { session }, error } = result; - if (error) return { data: null, error }; - if (!session) return { data: null, error: new AuthSessionMissingError() }; + const { + data: { session }, + error, + } = result + if (error) return { data: null, error } + if (!session) return { data: null, error: new AuthSessionMissingError() } const { data: sessionsData, error: sessionsError } = await _request( this.fetch, 'GET', @@ -1849,11 +1852,11 @@ export default class GoTrueClient { jwt: session.access_token, xform: (r) => r, } - ); - if (sessionsError) return { data: null, error: sessionsError }; - return { data: sessionsData as Session[], error: null }; - }); - }); + ) + if (sessionsError) return { data: null, error: sessionsError } + return { data: sessionsData as Session[], error: null } + }) + }) } /** @@ -1867,12 +1870,15 @@ export default class GoTrueClient { * @returns {Promise<{ error: AuthError | null }>} An object containing an error if the revocation fails. */ async revokeSession(sessionId: string): Promise<{ error: AuthError | null }> { - await this.initializePromise; + await this.initializePromise return await this._acquireLock(-1, async () => { return await this._useSession(async (result) => { - const { data: { session }, error } = result; - if (error) return { error }; - if (!session) return { error: new AuthSessionMissingError() }; + const { + data: { session }, + error, + } = result + if (error) return { error } + if (!session) return { error: new AuthSessionMissingError() } const { error: revokeError } = await _request( this.fetch, 'DELETE', @@ -1881,16 +1887,16 @@ export default class GoTrueClient { headers: this.headers, jwt: session.access_token, } - ); - if (revokeError) return { error: revokeError }; + ) + if (revokeError) return { error: revokeError } // If the revoked session is the current one, remove it from storage. - const currentSession = session as Session & { id?: string }; + const currentSession = session as Session & { id?: string } if (currentSession.id && currentSession.id === sessionId) { - await this._removeSession(); + await this._removeSession() } - return { error: null }; - }); - }); + return { error: null } + }) + }) } /**