From 74e75ce965d48271ba8da301e997a34bd32b9911 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Wed, 5 Nov 2025 12:23:33 +0300 Subject: [PATCH 1/7] feat(auth): add OAuth grant listing and revocation endpoints --- packages/core/auth-js/src/GoTrueClient.ts | 75 +++++++++++++++++++++++ packages/core/auth-js/src/lib/types.ts | 54 ++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 53c073b38..5cda96582 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -109,6 +109,8 @@ import type { AuthOAuthServerApi, AuthOAuthAuthorizationDetailsResponse, AuthOAuthConsentResponse, + AuthOAuthGrantsResponse, + AuthOAuthRevokeGrantResponse, Prettify, Provider, ResendParams, @@ -339,6 +341,8 @@ export default class GoTrueClient { getAuthorizationDetails: this._getAuthorizationDetails.bind(this), approveAuthorization: this._approveAuthorization.bind(this), denyAuthorization: this._denyAuthorization.bind(this), + listGrants: this._listOAuthGrants.bind(this), + revokeGrant: this._revokeOAuthGrant.bind(this), } if (this.persistSession) { @@ -3544,6 +3548,77 @@ export default class GoTrueClient { } } + /** + * Lists all OAuth grants that the authenticated user has authorized. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + */ + private async _listOAuthGrants(): Promise { + try { + return await this._useSession(async (result) => { + const { + data: { session }, + error: sessionError, + } = result + + if (sessionError) { + return this._returnResult({ data: null, error: sessionError }) + } + + if (!session) { + return this._returnResult({ data: null, error: new AuthSessionMissingError() }) + } + + return await _request(this.fetch, 'GET', `${this.url}/user/oauth/grants`, { + headers: this.headers, + jwt: session.access_token, + xform: (data: any) => ({ data, error: null }), + }) + }) + } catch (error) { + if (isAuthError(error)) { + return this._returnResult({ data: null, error }) + } + + throw error + } + } + + /** + * Revokes a user's OAuth grant for a specific client. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + */ + private async _revokeOAuthGrant(clientId: string): Promise { + try { + return await this._useSession(async (result) => { + const { + data: { session }, + error: sessionError, + } = result + + if (sessionError) { + return this._returnResult({ data: null, error: sessionError }) + } + + if (!session) { + return this._returnResult({ data: null, error: new AuthSessionMissingError() }) + } + + return await _request(this.fetch, 'DELETE', `${this.url}/user/oauth/grants`, { + headers: this.headers, + jwt: session.access_token, + query: { client_id: clientId }, + xform: () => ({ data: {}, error: null }), + }) + }) + } catch (error) { + if (isAuthError(error)) { + return this._returnResult({ data: null, error }) + } + + throw error + } + } + private async fetchJwk(kid: string, jwks: { keys: JWK[] } = { keys: [] }): Promise { // try fetching from the supplied jwks let jwk = jwks.keys.find((key) => key.kid === kid) diff --git a/packages/core/auth-js/src/lib/types.ts b/packages/core/auth-js/src/lib/types.ts index 5a2327d63..b4300de9b 100644 --- a/packages/core/auth-js/src/lib/types.ts +++ b/packages/core/auth-js/src/lib/types.ts @@ -1676,6 +1676,40 @@ export type AuthOAuthConsentResponse = RequestResult<{ redirect_url: string }> +/** + * An OAuth grant representing a user's authorization of an OAuth client. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + */ +export type OAuthGrant = { + /** OAuth client identifier (UUID) */ + client_id: string + /** Human-readable name of the OAuth client */ + client_name: string + /** URI of the OAuth client's website */ + client_uri: string + /** URI of the OAuth client's logo */ + logo_uri: string + /** Array of scopes granted to this client */ + scopes: string[] + /** Timestamp when the grant was created (ISO 8601 date-time) */ + granted_at: string +} + +/** + * Response type for listing user's OAuth grants. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + */ +export type AuthOAuthGrantsResponse = RequestResult<{ + /** Array of OAuth grants authorized by the user */ + grants: OAuthGrant[] +}> + +/** + * Response type for revoking an OAuth grant. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + */ +export type AuthOAuthRevokeGrantResponse = RequestResult<{}> + /** * Contains all OAuth 2.1 authorization server user-facing methods. * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. @@ -1722,4 +1756,24 @@ export interface AuthOAuthServerApi { authorizationId: string, options?: { skipBrowserRedirect?: boolean } ): Promise + + /** + * Lists all OAuth grants that the authenticated user has authorized. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + * + * @returns Array of OAuth grants with client information and granted scopes + */ + listGrants(): Promise + + /** + * Revokes a user's OAuth grant for a specific client. + * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. + * + * Revocation marks consent as revoked, deletes active sessions for that OAuth client, + * and invalidates associated refresh tokens. + * + * @param clientId - The OAuth client identifier (UUID) to revoke access for + * @returns Empty response on successful revocation + */ + revokeGrant(clientId: string): Promise } From 8c13920b3a972340b64bf77af3f21f1cce53c8c0 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Wed, 5 Nov 2025 15:58:42 +0300 Subject: [PATCH 2/7] feat(auth): pass options object for future extensibility --- packages/core/auth-js/src/GoTrueClient.ts | 4 ++-- packages/core/auth-js/src/lib/types.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 5cda96582..9ff2141fe 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -3587,7 +3587,7 @@ export default class GoTrueClient { * Revokes a user's OAuth grant for a specific client. * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. */ - private async _revokeOAuthGrant(clientId: string): Promise { + private async _revokeOAuthGrant(options: { clientId: string }): Promise { try { return await this._useSession(async (result) => { const { @@ -3606,7 +3606,7 @@ export default class GoTrueClient { return await _request(this.fetch, 'DELETE', `${this.url}/user/oauth/grants`, { headers: this.headers, jwt: session.access_token, - query: { client_id: clientId }, + query: { client_id: options.clientId }, xform: () => ({ data: {}, error: null }), }) }) diff --git a/packages/core/auth-js/src/lib/types.ts b/packages/core/auth-js/src/lib/types.ts index b4300de9b..bca3dbaf1 100644 --- a/packages/core/auth-js/src/lib/types.ts +++ b/packages/core/auth-js/src/lib/types.ts @@ -1772,8 +1772,9 @@ export interface AuthOAuthServerApi { * Revocation marks consent as revoked, deletes active sessions for that OAuth client, * and invalidates associated refresh tokens. * - * @param clientId - The OAuth client identifier (UUID) to revoke access for + * @param options - Revocation options + * @param options.clientId - The OAuth client identifier (UUID) to revoke access for * @returns Empty response on successful revocation */ - revokeGrant(clientId: string): Promise + revokeGrant(options: { clientId: string }): Promise } From b136bb3e4ae55d7e334e106484fe0c156131e922 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Wed, 5 Nov 2025 15:59:28 +0300 Subject: [PATCH 3/7] fix(auth): format --- packages/core/auth-js/src/GoTrueClient.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 9ff2141fe..9e27d658e 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -3587,7 +3587,9 @@ export default class GoTrueClient { * Revokes a user's OAuth grant for a specific client. * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. */ - private async _revokeOAuthGrant(options: { clientId: string }): Promise { + private async _revokeOAuthGrant(options: { + clientId: string + }): Promise { try { return await this._useSession(async (result) => { const { From be3908ff7ed19b66478f299fd876eca41ba51c7a Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Wed, 5 Nov 2025 16:44:44 +0300 Subject: [PATCH 4/7] feat(auth): use existing client object --- packages/core/auth-js/src/GoTrueClient.ts | 19 ++++++++++++++++++- packages/core/auth-js/src/lib/types.ts | 10 ++-------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 9e27d658e..2c59884d6 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -3571,7 +3571,24 @@ export default class GoTrueClient { return await _request(this.fetch, 'GET', `${this.url}/user/oauth/grants`, { headers: this.headers, jwt: session.access_token, - xform: (data: any) => ({ data, error: null }), + xform: (data: any) => { + // Transform flat API response to nested client structure + return { + data: { + grants: data.grants.map((grant: any) => ({ + client: { + client_id: grant.client_id, + client_name: grant.client_name, + client_uri: grant.client_uri, + logo_uri: grant.logo_uri, + }, + scopes: grant.scopes, + granted_at: grant.granted_at, + })), + }, + error: null, + } + }, }) }) } catch (error) { diff --git a/packages/core/auth-js/src/lib/types.ts b/packages/core/auth-js/src/lib/types.ts index bca3dbaf1..051013fd5 100644 --- a/packages/core/auth-js/src/lib/types.ts +++ b/packages/core/auth-js/src/lib/types.ts @@ -1681,14 +1681,8 @@ export type AuthOAuthConsentResponse = RequestResult<{ * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. */ export type OAuthGrant = { - /** OAuth client identifier (UUID) */ - client_id: string - /** Human-readable name of the OAuth client */ - client_name: string - /** URI of the OAuth client's website */ - client_uri: string - /** URI of the OAuth client's logo */ - logo_uri: string + /** OAuth client information */ + client: OAuthAuthorizationClient /** Array of scopes granted to this client */ scopes: string[] /** Timestamp when the grant was created (ISO 8601 date-time) */ From 78646e58da4276d8e8b9fbbb69cd7036345121bf Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Thu, 6 Nov 2025 16:06:35 +0300 Subject: [PATCH 5/7] fix(auth): updated api response structure https://github.com/supabase/auth/pull/2247 --- packages/core/auth-js/src/GoTrueClient.ts | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 2c59884d6..9e27d658e 100644 --- a/packages/core/auth-js/src/GoTrueClient.ts +++ b/packages/core/auth-js/src/GoTrueClient.ts @@ -3571,24 +3571,7 @@ export default class GoTrueClient { return await _request(this.fetch, 'GET', `${this.url}/user/oauth/grants`, { headers: this.headers, jwt: session.access_token, - xform: (data: any) => { - // Transform flat API response to nested client structure - return { - data: { - grants: data.grants.map((grant: any) => ({ - client: { - client_id: grant.client_id, - client_name: grant.client_name, - client_uri: grant.client_uri, - logo_uri: grant.logo_uri, - }, - scopes: grant.scopes, - granted_at: grant.granted_at, - })), - }, - error: null, - } - }, + xform: (data: any) => ({ data, error: null }), }) }) } catch (error) { From 05b45acf81f7160692fc12253ab7e63b637d38a0 Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Fri, 7 Nov 2025 13:34:30 +0300 Subject: [PATCH 6/7] fix(auth): update the client obj keys --- packages/core/auth-js/src/lib/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core/auth-js/src/lib/types.ts b/packages/core/auth-js/src/lib/types.ts index 051013fd5..60432e2eb 100644 --- a/packages/core/auth-js/src/lib/types.ts +++ b/packages/core/auth-js/src/lib/types.ts @@ -1630,11 +1630,11 @@ export interface GoTrueAdminOAuthApi { */ export type OAuthAuthorizationClient = { /** Unique identifier for the OAuth client (UUID) */ - client_id: string + id: string /** Human-readable name of the OAuth client */ - client_name: string + name: string /** URI of the OAuth client's website */ - client_uri: string + uri: string /** URI of the OAuth client's logo */ logo_uri: string } From c7ea4f1c666c26097a67f9eb4222a058905a358b Mon Sep 17 00:00:00 2001 From: Cemal Kilic Date: Fri, 7 Nov 2025 13:41:32 +0300 Subject: [PATCH 7/7] feat(auth): update grant response structure --- packages/core/auth-js/src/lib/types.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/core/auth-js/src/lib/types.ts b/packages/core/auth-js/src/lib/types.ts index 60432e2eb..186eb93e4 100644 --- a/packages/core/auth-js/src/lib/types.ts +++ b/packages/core/auth-js/src/lib/types.ts @@ -1693,10 +1693,7 @@ export type OAuthGrant = { * Response type for listing user's OAuth grants. * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. */ -export type AuthOAuthGrantsResponse = RequestResult<{ - /** Array of OAuth grants authorized by the user */ - grants: OAuthGrant[] -}> +export type AuthOAuthGrantsResponse = RequestResult /** * Response type for revoking an OAuth grant. @@ -1755,7 +1752,7 @@ export interface AuthOAuthServerApi { * Lists all OAuth grants that the authenticated user has authorized. * Only relevant when the OAuth 2.1 server is enabled in Supabase Auth. * - * @returns Array of OAuth grants with client information and granted scopes + * @returns Response with array of OAuth grants with client information and granted scopes */ listGrants(): Promise