Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions packages/core/auth-js/src/GoTrueAdminApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,23 @@ import {
PageParams,
SIGN_OUT_SCOPES,
SignOutScope,
GoTrueAdminOAuthApi,
CreateOAuthClientParams,
OAuthClientResponse,
OAuthClientListResponse,
} from './lib/types'
import { AuthError, isAuthError } from './lib/errors'

export default class GoTrueAdminApi {
/** Contains all MFA administration methods. */
mfa: GoTrueAdminMFAApi

/**
* Contains all OAuth client administration methods.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
oauth: GoTrueAdminOAuthApi

protected url: string
protected headers: {
[key: string]: string
Expand All @@ -52,6 +62,13 @@ export default class GoTrueAdminApi {
listFactors: this._listFactors.bind(this),
deleteFactor: this._deleteFactor.bind(this),
}
this.oauth = {
listClients: this._listOAuthClients.bind(this),
createClient: this._createOAuthClient.bind(this),
getClient: this._getOAuthClient.bind(this),
deleteClient: this._deleteOAuthClient.bind(this),
regenerateClientSecret: this._regenerateOAuthClientSecret.bind(this),
}
}

/**
Expand Down Expand Up @@ -349,4 +366,150 @@ export default class GoTrueAdminApi {
throw error
}
}

/**
* Lists all OAuth clients with optional pagination.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
private async _listOAuthClients(params?: PageParams): Promise<OAuthClientListResponse> {
try {
const pagination: Pagination = { nextPage: null, lastPage: 0, total: 0 }
const response = await _request(this.fetch, 'GET', `${this.url}/admin/oauth/clients`, {
headers: this.headers,
noResolveJson: true,
query: {
page: params?.page?.toString() ?? '',
per_page: params?.perPage?.toString() ?? '',
},
xform: _noResolveJsonResponse,
})
if (response.error) throw response.error

const clients = await response.json()
const total = response.headers.get('x-total-count') ?? 0
const links = response.headers.get('link')?.split(',') ?? []
if (links.length > 0) {
links.forEach((link: string) => {
const page = parseInt(link.split(';')[0].split('=')[1].substring(0, 1))
const rel = JSON.parse(link.split(';')[1].split('=')[1])
pagination[`${rel}Page`] = page
})

pagination.total = parseInt(total)
}
return { data: { ...clients, ...pagination }, error: null }
} catch (error) {
if (isAuthError(error)) {
return { data: { clients: [] }, error }
}
throw error
}
}

/**
* Creates a new OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
private async _createOAuthClient(
params: CreateOAuthClientParams
): Promise<OAuthClientResponse> {
try {
return await _request(this.fetch, 'POST', `${this.url}/admin/oauth/clients`, {
body: params,
headers: this.headers,
xform: (client: any) => {
return { data: client, error: null }
},
})
} catch (error) {
if (isAuthError(error)) {
return { data: null, error }
}

throw error
}
}

/**
* Gets details of a specific OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
private async _getOAuthClient(clientId: string): Promise<OAuthClientResponse> {
try {
return await _request(this.fetch, 'GET', `${this.url}/admin/oauth/clients/${clientId}`, {
headers: this.headers,
xform: (client: any) => {
return { data: client, error: null }
},
})
} catch (error) {
if (isAuthError(error)) {
return { data: null, error }
}

throw error
}
}

/**
* Deletes an OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
private async _deleteOAuthClient(clientId: string): Promise<OAuthClientResponse> {
try {
return await _request(
this.fetch,
'DELETE',
`${this.url}/admin/oauth/clients/${clientId}`,
{
headers: this.headers,
xform: (client: any) => {
return { data: client, error: null }
},
}
)
} catch (error) {
if (isAuthError(error)) {
return { data: null, error }
}

throw error
}
}

/**
* Regenerates the secret for an OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
private async _regenerateOAuthClientSecret(clientId: string): Promise<OAuthClientResponse> {
try {
return await _request(
this.fetch,
'POST',
`${this.url}/admin/oauth/clients/${clientId}/regenerate_secret`,
{
headers: this.headers,
xform: (client: any) => {
return { data: client, error: null }
},
}
)
} catch (error) {
if (isAuthError(error)) {
return { data: null, error }
}

throw error
}
}
}
142 changes: 142 additions & 0 deletions packages/core/auth-js/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1448,3 +1448,145 @@ export interface JWK {

export const SIGN_OUT_SCOPES = ['global', 'local', 'others'] as const
export type SignOutScope = (typeof SIGN_OUT_SCOPES)[number]

/**
* OAuth client grant types supported by the OAuth 2.1 server.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClientGrantType = 'authorization_code' | 'refresh_token'

/**
* OAuth client response types supported by the OAuth 2.1 server.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClientResponseType = 'code'

/**
* OAuth client type indicating whether the client can keep credentials confidential.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClientType = 'public' | 'confidential'

/**
* OAuth client registration type.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClientRegistrationType = 'dynamic' | 'manual'

/**
* OAuth client object returned from the OAuth 2.1 server.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClient = {
/** Unique identifier for the OAuth client */
client_id: string
/** Human-readable name of the OAuth client */
client_name: string
/** Client secret (only returned on registration and regeneration) */
client_secret?: string
/** Type of OAuth client */
client_type: OAuthClientType
/** Token endpoint authentication method */
token_endpoint_auth_method: string
/** Registration type of the client */
registration_type: OAuthClientRegistrationType
/** URI of the OAuth client */
client_uri?: string
/** Array of allowed redirect URIs */
redirect_uris: string[]
/** Array of allowed grant types */
grant_types: OAuthClientGrantType[]
/** Array of allowed response types */
response_types: OAuthClientResponseType[]
/** Scope of the OAuth client */
scope?: string
/** Timestamp when the client was created */
created_at: string
/** Timestamp when the client was last updated */
updated_at: string
}

/**
* Parameters for creating a new OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type CreateOAuthClientParams = {
/** Human-readable name of the OAuth client */
client_name: string
/** URI of the OAuth client */
client_uri?: string
/** Array of allowed redirect URIs */
redirect_uris: string[]
/** Array of allowed grant types (optional, defaults to authorization_code and refresh_token) */
grant_types?: OAuthClientGrantType[]
/** Array of allowed response types (optional, defaults to code) */
response_types?: OAuthClientResponseType[]
/** Scope of the OAuth client */
scope?: string
}

/**
* Response type for OAuth client operations.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClientResponse = RequestResult<OAuthClient>

/**
* Response type for listing OAuth clients.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export type OAuthClientListResponse =
| {
data: { clients: OAuthClient[]; aud: string } & Pagination
error: null
}
| {
data: { clients: [] }
error: AuthError
}

/**
* Contains all OAuth client administration methods.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*/
export interface GoTrueAdminOAuthApi {
/**
* Lists all OAuth clients with optional pagination.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
listClients(params?: PageParams): Promise<OAuthClientListResponse>

/**
* Creates a new OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
createClient(params: CreateOAuthClientParams): Promise<OAuthClientResponse>

/**
* Gets details of a specific OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
getClient(clientId: string): Promise<OAuthClientResponse>

/**
* Deletes an OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
deleteClient(clientId: string): Promise<OAuthClientResponse>

/**
* Regenerates the secret for an OAuth client.
* Only relevant when the OAuth 2.1 server is enabled in Supabase Auth.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
*/
regenerateClientSecret(clientId: string): Promise<OAuthClientResponse>
}
Loading