feat: show required permissions in mgmt api docs (#41151)

## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Show required FGA permissions for each route in the management API docs.

Permissions are pulled from the `fga_permissions` security field in the
OpenAPI spec.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* API reference docs now extract and display fine-grained access-control
permissions per endpoint. When present, a dedicated block lists required
permissions with a clear header explaining the token requirements.
* The permissions block appears alongside existing OAuth scope
information and only shows for endpoints that declare such permissions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Chris Chinchilla <chris.ward@supabase.io>
This commit is contained in:
HieuandChris Chinchilla authored and GitHub committed 2026-02-03 20:56:45 +00:00
1 parent 3a391d4f6b
commit e96efe695f
2 files changed
+29 -9

No files matched your search

@@ -118,7 +118,7 @@ interface IApiFormUrlEncodedDTO {
}
}
type ISecurityOption = IBearerSecurity | IOAuth2Security
type ISecurityOption = IBearerSecurity | IOAuth2Security | IFgaSecurity
interface IBearerSecurity {
bearer: []
@@ -128,6 +128,10 @@ interface IOAuth2Security {
oauth2: Array<'read' | 'write'>
}
interface IFgaSecurity {
fga_permissions: string[]
}
export function getTypeDisplayFromSchema(schema: ISchema) {
if ('allOf' in schema) {
if (schema.allOf.length === 1) {
+24 -8
View File
@@ -1,17 +1,20 @@
import { isFeatureEnabled } from 'common'
import { Fragment } from 'react'
import ReactMarkdown from 'react-markdown'
import {
Badge,
cn,
Tabs_Shadcn_,
TabsContent_Shadcn_,
TabsList_Shadcn_,
TabsTrigger_Shadcn_,
Tabs_Shadcn_,
cn,
} from 'ui'
import { isFeatureEnabled } from 'common'
import { type IApiEndPoint } from './Reference.api.utils'
import { RefInternalLink } from './Reference.navigation.client'
import { ApiOperationBodySchemeSelector } from './Reference.ui.client'
import ApiSchema from '~/components/ApiSchema'
import { clientSdkIds, REFERENCES } from '~/content/navigation.references'
import { REFERENCES, clientSdkIds } from '~/content/navigation.references'
import {
getApiEndpointById,
getCliSpec,
@@ -20,7 +23,7 @@ import {
getSelfHostedApiEndpointById,
getTypeSpec,
} from '~/features/docs/Reference.generated.singleton'
import { getRefMarkdown, MDXRemoteRefs } from '~/features/docs/Reference.mdx'
import { MDXRemoteRefs, getRefMarkdown } from '~/features/docs/Reference.mdx'
import type { MethodTypes } from '~/features/docs/Reference.typeSpec'
import { formatMethodSignature } from '~/features/docs/Reference.typeSpec'
import {
@@ -35,9 +38,6 @@ import {
import type { AbbrevApiReferenceSection } from '~/features/docs/Reference.utils'
import { normalizeMarkdown } from '~/features/docs/Reference.utils'
import { CodeBlock } from '~/features/ui/CodeBlock/CodeBlock'
import { type IApiEndPoint } from './Reference.api.utils'
import { RefInternalLink } from './Reference.navigation.client'
import { ApiOperationBodySchemeSelector } from './Reference.ui.client'
type RefSectionsProps = {
libraryId: string
@@ -286,6 +286,8 @@ async function ApiEndpointSection({ link, section, servicePath }: ApiEndpointSec
: await getApiEndpointById(section.id)
if (!endpointDetails) return null
const endpointFgaPermissions =
endpointDetails.security?.find((sec) => 'fga_permissions' in sec)?.fga_permissions ?? []
const pathParameters = (endpointDetails.parameters ?? []).filter((param) => param.in === 'path')
const queryParameters = (endpointDetails.parameters ?? []).filter((param) => param.in === 'query')
const bodyParameters =
@@ -358,6 +360,20 @@ async function ApiEndpointSection({ link, section, servicePath }: ApiEndpointSec
</ul>
</section>
)}
{endpointFgaPermissions.length > 0 && (
<section>
<h3 className="mb-3 text-base text-foreground">
The fine-grained token must include the following permissions to access this endpoint:
</h3>
<ul>
{endpointFgaPermissions.map((perm) => (
<li key={perm} className="list-['-'] ml-2 pl-2">
<span className="font-mono text-sm font-medium text-foreground">{perm}</span>
</li>
))}
</ul>
</section>
)}
{pathParameters.length > 0 && (
<section>
<h3 className="mb-3 text-base text-foreground">Path parameters</h3>