mirror of
https://github.com/supabase/supabase.git
synced 2026-05-06 08:56:46 -04:00
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? <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: https://github.com/supabase/supabase/pull/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 -->
This commit is contained in:
@@ -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 = ({
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value === 'public'}
|
||||
onCheckedChange={(checked) =>
|
||||
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}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
|
||||
{form.watch('client_type') === 'confidential' && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="token_endpoint_auth_method"
|
||||
render={({ field }) => (
|
||||
<FormItemLayout
|
||||
label="Token Endpoint Auth Method"
|
||||
description="How the client authenticates with the token endpoint. The client secret is included in either the Authorization header or the request body."
|
||||
className="px-5"
|
||||
>
|
||||
<FormControl>
|
||||
<Select_Shadcn_ value={field.value} onValueChange={field.onChange}>
|
||||
<SelectTrigger_Shadcn_ className="text-sm">
|
||||
<SelectValue_Shadcn_ />
|
||||
</SelectTrigger_Shadcn_>
|
||||
<SelectContent_Shadcn_>
|
||||
<SelectItem_Shadcn_ value="client_secret_basic" className="text-sm">
|
||||
HTTP Basic Auth header (client_secret_basic)
|
||||
</SelectItem_Shadcn_>
|
||||
<SelectItem_Shadcn_ value="client_secret_post" className="text-sm">
|
||||
Request body (client_secret_post)
|
||||
</SelectItem_Shadcn_>
|
||||
</SelectContent_Shadcn_>
|
||||
</Select_Shadcn_>
|
||||
</FormControl>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</form>
|
||||
</Form>
|
||||
</SheetSection>
|
||||
|
||||
Reference in New Issue
Block a user