From 019d10aab65da4272cdc8ecc2b4a3dd7aef5df9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cemal=20K=C4=B1l=C4=B1=C3=A7?= Date: Tue, 5 May 2026 12:02:31 +0200 Subject: [PATCH] feat(studio): add `token_endpoint_auth_method` field to OAuth app (#45519) ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## Summary - Added token_endpoint_auth_method field to the OAuth app create/update sheet, visible only when client type is set to "Confidential" - Supports client_secret_basic (HTTP Basic Auth header) and client_secret_post (request body) options; public clients automatically use none - Wired the field into both create and update API payloads ## Test plan - Create a confidential OAuth app -> Token Endpoint Auth Method selector should appear and submit correctly for both options - Create a public OAuth app -> selector should not appear; none is sent in the payload - Edit an existing confidential app -> selector should pre-populate from the saved value ## What is the new behavior? image-KvVBmAG6@2x image-gLARAPwt@2x related: https://github.com/supabase/supabase/pull/43128 ## Summary by CodeRabbit * **New Features** * Added token endpoint authentication method configuration for OAuth app creation and updates * Authentication method automatically adjusts based on client type (public clients use 'none') * Token endpoint auth method field conditionally displayed for confidential clients only --- .../OAuthApps/CreateOrUpdateOAuthAppSheet.tsx | 67 +++++++++++++++++-- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/apps/studio/components/interfaces/Auth/OAuthApps/CreateOrUpdateOAuthAppSheet.tsx b/apps/studio/components/interfaces/Auth/OAuthApps/CreateOrUpdateOAuthAppSheet.tsx index 10165b72bb..0b72b150ec 100644 --- a/apps/studio/components/interfaces/Auth/OAuthApps/CreateOrUpdateOAuthAppSheet.tsx +++ b/apps/studio/components/interfaces/Auth/OAuthApps/CreateOrUpdateOAuthAppSheet.tsx @@ -18,6 +18,11 @@ import { FormField, FormLabel, Input_Shadcn_, + Select_Shadcn_, + SelectContent_Shadcn_, + SelectItem_Shadcn_, + SelectTrigger_Shadcn_, + SelectValue_Shadcn_, Separator, Sheet, SheetClose, @@ -62,6 +67,9 @@ const FormSchema = z.object({ .array() .min(1, 'At least one redirect URI is required'), client_type: z.enum(['public', 'confidential']).default('confidential'), + token_endpoint_auth_method: z + .enum(['client_secret_basic', 'client_secret_post', 'none']) + .default('client_secret_basic'), client_id: z.string().optional(), client_secret: z.string().optional(), logo_uri: z.string().optional(), @@ -74,6 +82,7 @@ const initialValues = { type: 'manual' as const, redirect_uris: [{ value: '' }], client_type: 'confidential' as const, + token_endpoint_auth_method: 'client_secret_basic' as const, client_id: '', client_secret: '', logo_uri: '', @@ -140,6 +149,11 @@ export const CreateOrUpdateOAuthAppSheet = ({ ? appToEdit.redirect_uris.map((uri) => ({ value: uri })) : [{ value: '' }], client_type: appToEdit.client_type, + token_endpoint_auth_method: + (appToEdit.token_endpoint_auth_method as + | 'client_secret_basic' + | 'client_secret_post' + | 'none') || 'client_secret_basic', client_id: appToEdit.client_id, client_secret: '****************************************************************', logo_uri: appToEdit.logo_uri || undefined, @@ -184,10 +198,12 @@ export const CreateOrUpdateOAuthAppSheet = ({ } if (isEditMode && appToEdit) { - const payload: UpdateOAuthClientParams = { + const payload: UpdateOAuthClientParams & { token_endpoint_auth_method?: string } = { client_name: data.name, redirect_uris: validRedirectUris, logo_uri: uploadedLogoUri, + token_endpoint_auth_method: + data.client_type === 'public' ? 'none' : data.token_endpoint_auth_method, } updateOAuthApp({ @@ -197,12 +213,18 @@ export const CreateOrUpdateOAuthAppSheet = ({ ...payload, }) } else { - const payload: CreateOAuthClientParams & { logo_uri?: string; client_type?: string } = { + const payload: CreateOAuthClientParams & { + logo_uri?: string + client_type?: string + token_endpoint_auth_method?: string + } = { client_name: data.name, client_uri: '', client_type: data.client_type, redirect_uris: validRedirectUris, logo_uri: uploadedLogoUri || undefined, + token_endpoint_auth_method: + data.client_type === 'public' ? 'none' : data.token_endpoint_auth_method, } createOAuthApp({ @@ -438,15 +460,50 @@ export const CreateOrUpdateOAuthAppSheet = ({ - field.onChange(checked ? 'public' : 'confidential') - } + onCheckedChange={(checked) => { + const newType = checked ? 'public' : 'confidential' + field.onChange(newType) + form.setValue( + 'token_endpoint_auth_method', + newType === 'public' ? 'none' : 'client_secret_basic' + ) + }} disabled={isEditMode} /> )} /> + + {form.watch('client_type') === 'confidential' && ( + ( + + + + + + + + + HTTP Basic Auth header (client_secret_basic) + + + Request body (client_secret_post) + + + + + + )} + /> + )}