diff --git a/packages/core/auth-js/src/GoTrueClient.ts b/packages/core/auth-js/src/GoTrueClient.ts index 53c073b38..9e27d658e 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,79 @@ 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(options: { + 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: options.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..186eb93e4 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 } @@ -1676,6 +1676,31 @@ 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 information */ + client: OAuthAuthorizationClient + /** 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 + +/** + * 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 +1747,25 @@ 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 Response with 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 options - Revocation options + * @param options.clientId - The OAuth client identifier (UUID) to revoke access for + * @returns Empty response on successful revocation + */ + revokeGrant(options: { clientId: string }): Promise }