fix(openapi): align OAuth security metadata

This commit is contained in:
saltbo
2026-08-07 13:32:27 -04:00
parent b92df828ab
commit 095daf8b30
2 changed files with 12 additions and 50 deletions
+6 -22
View File
@@ -198,9 +198,10 @@ export function createApp(platform: Platform, auth: Auth, deps: Deps = createDep
return c.json({
resource: `${origin}/api`,
authorization_servers: [authorizationServer],
bearer_methods_supported: ['header'],
bearer_methods_supported: [],
scopes_supported: OAUTH_RESOURCE_SCOPES,
dpop_signing_alg_values_supported: ['ES256', 'EdDSA'],
dpop_bound_access_tokens_required: true,
resource_name: 'ZPan API',
})
})
@@ -284,26 +285,6 @@ export function createApp(platform: Platform, auth: Auth, deps: Deps = createDep
oauthAuthorizationServer: '/.well-known/oauth-authorization-server/api/auth',
oauthProtectedResource: '/.well-known/oauth-protected-resource/api',
},
'x-cli-config': {
profiles: {
default: {
credentials: {
oauth2: {
auth: {
type: 'api-key',
params: {
in: 'header',
name: 'Authorization',
value: 'DPoP',
provider: 'realmroot-target',
scopes: OAUTH_RESOURCE_SCOPES.join(' '),
},
},
},
},
},
},
},
})
addRequestIdOpenApi(doc)
@@ -471,7 +452,10 @@ function getCorsOrigins(platform: Platform): Set<string> {
}
function agentScopeDescriptions(): Record<string, string> {
return { ...OAUTH_SCOPE_DESCRIPTIONS }
return {
...OAUTH_SCOPE_DESCRIPTIONS,
[AuthorizationScope.WORKSPACES_DISCOVER]: 'Discover workspaces available to the connected account',
}
}
export type AppType = ReturnType<typeof createApp>
+6 -28
View File
@@ -240,7 +240,7 @@ describe('global OpenAPI document', () => {
expect(await headResponse.text()).toBe('')
})
it('publishes the external OAuth scope catalog with delegated CLI authentication', async () => {
it('publishes the external OAuth scope catalog without client-owned credential configuration', async () => {
const { app } = await createTestApp({ DOWNLOAD_TOKEN_SECRET: 'test-download-token-secret' })
const res = await app.request('/api/openapi.json')
const doc = (await res.json()) as {
@@ -250,17 +250,7 @@ describe('global OpenAPI document', () => {
{ type?: string; scheme?: string; flows?: { authorizationCode?: { scopes?: Record<string, string> } } }
>
}
'x-cli-config'?: {
profiles?: Record<
string,
{
credentials?: Record<
string,
{ auth?: { params?: Record<string, unknown> }; params?: Record<string, unknown> }
>
}
>
}
'x-cli-config'?: unknown
}
expect(doc.components?.securitySchemes?.oauth2).toMatchObject({
@@ -271,6 +261,7 @@ describe('global OpenAPI document', () => {
tokenUrl: '/api/auth/oauth2/token',
refreshUrl: '/api/auth/oauth2/token',
scopes: expect.objectContaining({
[AuthorizationScope.WORKSPACES_DISCOVER]: 'Discover workspaces available to the connected account',
[AuthorizationScope.OBJECTS_READ]: 'List, inspect, and download objects',
[AuthorizationScope.OBJECTS_CREATE]: 'Create folders and upload objects',
[AuthorizationScope.SHARES_CREATE]: 'Create public shares',
@@ -280,22 +271,7 @@ describe('global OpenAPI document', () => {
},
})
expect(doc.components?.securitySchemes?.agentApiKey).toBeUndefined()
expect(doc['x-cli-config']?.profiles?.default?.credentials?.oauth2).toEqual({
auth: {
type: 'api-key',
params: {
in: 'header',
name: 'Authorization',
value: 'DPoP',
provider: 'realmroot-target',
scopes: expect.stringContaining(AuthorizationScope.OBJECTS_CREATE),
},
},
})
expect(doc['x-cli-config']?.profiles?.default?.credentials?.oauth2.auth?.params?.scopes).toContain(
AuthorizationScope.OBJECTS_PURGE,
)
expect(Object.keys(doc['x-cli-config']?.profiles ?? {})).toEqual(['default'])
expect(doc['x-cli-config']).toBeUndefined()
})
it('publishes scopes through authorization-server metadata without a duplicate catalog endpoint', async () => {
@@ -345,7 +321,9 @@ describe('global OpenAPI document', () => {
expect(await protectedResource.json()).toMatchObject({
resource: 'http://localhost/api',
authorization_servers: ['http://localhost:3000/api/auth'],
bearer_methods_supported: [],
scopes_supported: expect.arrayContaining([AuthorizationScope.OBJECTS_READ]),
dpop_bound_access_tokens_required: true,
})
const protectedHead = await app.request('/.well-known/oauth-protected-resource/api', { method: 'HEAD' })