Skip to content

Commit 019d10a

Browse files
authored
feat(studio): add token_endpoint_auth_method field to OAuth app (supabase#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? <img width="1244" height="1660" alt="image-KvVBmAG6@2x" src="https://github.com/user-attachments/assets/76ab2687-6be4-4b74-a830-e670a2bb4be2" /> <img width="1264" height="1652" alt="image-gLARAPwt@2x" src="https://github.com/user-attachments/assets/fd5770d5-acfd-4edb-bd5e-af582108f092" /> related: supabase#43128 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## 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 <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent 5c7370f commit 019d10a

1 file changed

Lines changed: 62 additions & 5 deletions

File tree

apps/studio/components/interfaces/Auth/OAuthApps/CreateOrUpdateOAuthAppSheet.tsx

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ import {
1818
FormField,
1919
FormLabel,
2020
Input_Shadcn_,
21+
Select_Shadcn_,
22+
SelectContent_Shadcn_,
23+
SelectItem_Shadcn_,
24+
SelectTrigger_Shadcn_,
25+
SelectValue_Shadcn_,
2126
Separator,
2227
Sheet,
2328
SheetClose,
@@ -62,6 +67,9 @@ const FormSchema = z.object({
6267
.array()
6368
.min(1, 'At least one redirect URI is required'),
6469
client_type: z.enum(['public', 'confidential']).default('confidential'),
70+
token_endpoint_auth_method: z
71+
.enum(['client_secret_basic', 'client_secret_post', 'none'])
72+
.default('client_secret_basic'),
6573
client_id: z.string().optional(),
6674
client_secret: z.string().optional(),
6775
logo_uri: z.string().optional(),
@@ -74,6 +82,7 @@ const initialValues = {
7482
type: 'manual' as const,
7583
redirect_uris: [{ value: '' }],
7684
client_type: 'confidential' as const,
85+
token_endpoint_auth_method: 'client_secret_basic' as const,
7786
client_id: '',
7887
client_secret: '',
7988
logo_uri: '',
@@ -140,6 +149,11 @@ export const CreateOrUpdateOAuthAppSheet = ({
140149
? appToEdit.redirect_uris.map((uri) => ({ value: uri }))
141150
: [{ value: '' }],
142151
client_type: appToEdit.client_type,
152+
token_endpoint_auth_method:
153+
(appToEdit.token_endpoint_auth_method as
154+
| 'client_secret_basic'
155+
| 'client_secret_post'
156+
| 'none') || 'client_secret_basic',
143157
client_id: appToEdit.client_id,
144158
client_secret: '****************************************************************',
145159
logo_uri: appToEdit.logo_uri || undefined,
@@ -184,10 +198,12 @@ export const CreateOrUpdateOAuthAppSheet = ({
184198
}
185199

186200
if (isEditMode && appToEdit) {
187-
const payload: UpdateOAuthClientParams = {
201+
const payload: UpdateOAuthClientParams & { token_endpoint_auth_method?: string } = {
188202
client_name: data.name,
189203
redirect_uris: validRedirectUris,
190204
logo_uri: uploadedLogoUri,
205+
token_endpoint_auth_method:
206+
data.client_type === 'public' ? 'none' : data.token_endpoint_auth_method,
191207
}
192208

193209
updateOAuthApp({
@@ -197,12 +213,18 @@ export const CreateOrUpdateOAuthAppSheet = ({
197213
...payload,
198214
})
199215
} else {
200-
const payload: CreateOAuthClientParams & { logo_uri?: string; client_type?: string } = {
216+
const payload: CreateOAuthClientParams & {
217+
logo_uri?: string
218+
client_type?: string
219+
token_endpoint_auth_method?: string
220+
} = {
201221
client_name: data.name,
202222
client_uri: '',
203223
client_type: data.client_type,
204224
redirect_uris: validRedirectUris,
205225
logo_uri: uploadedLogoUri || undefined,
226+
token_endpoint_auth_method:
227+
data.client_type === 'public' ? 'none' : data.token_endpoint_auth_method,
206228
}
207229

208230
createOAuthApp({
@@ -438,15 +460,50 @@ export const CreateOrUpdateOAuthAppSheet = ({
438460
<FormControl>
439461
<Switch
440462
checked={field.value === 'public'}
441-
onCheckedChange={(checked) =>
442-
field.onChange(checked ? 'public' : 'confidential')
443-
}
463+
onCheckedChange={(checked) => {
464+
const newType = checked ? 'public' : 'confidential'
465+
field.onChange(newType)
466+
form.setValue(
467+
'token_endpoint_auth_method',
468+
newType === 'public' ? 'none' : 'client_secret_basic'
469+
)
470+
}}
444471
disabled={isEditMode}
445472
/>
446473
</FormControl>
447474
</FormItemLayout>
448475
)}
449476
/>
477+
478+
{form.watch('client_type') === 'confidential' && (
479+
<FormField
480+
control={form.control}
481+
name="token_endpoint_auth_method"
482+
render={({ field }) => (
483+
<FormItemLayout
484+
label="Token Endpoint Auth Method"
485+
description="How the client authenticates with the token endpoint. The client secret is included in either the Authorization header or the request body."
486+
className="px-5"
487+
>
488+
<FormControl>
489+
<Select_Shadcn_ value={field.value} onValueChange={field.onChange}>
490+
<SelectTrigger_Shadcn_ className="text-sm">
491+
<SelectValue_Shadcn_ />
492+
</SelectTrigger_Shadcn_>
493+
<SelectContent_Shadcn_>
494+
<SelectItem_Shadcn_ value="client_secret_basic" className="text-sm">
495+
HTTP Basic Auth header (client_secret_basic)
496+
</SelectItem_Shadcn_>
497+
<SelectItem_Shadcn_ value="client_secret_post" className="text-sm">
498+
Request body (client_secret_post)
499+
</SelectItem_Shadcn_>
500+
</SelectContent_Shadcn_>
501+
</Select_Shadcn_>
502+
</FormControl>
503+
</FormItemLayout>
504+
)}
505+
/>
506+
)}
450507
</form>
451508
</Form>
452509
</SheetSection>

0 commit comments

Comments
 (0)