Skip to content

Commit 9bf69b8

Browse files
committed
granular authorization based on access policy
1 parent d38c574 commit 9bf69b8

File tree

3 files changed

+22
-23
lines changed

3 files changed

+22
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Options:
3838
- `publishedTags` _optional_ if specified, will be published definitions only for specified tags
3939
- `paths` _optional_ openapi custom paths (will be merged with all standard and all customs paths)
4040
- `components` _optional_ openapi custom components (will be merged with all standard and all customs tags)
41-
- `useAuthentication` _optional_ require Directus authentication to access the docs interface (default false). When enabled, users must be authenticated via Directus admin cookie, static token, or Bearer JWT token to access `/api-docs` and `/api-docs/oas` endpoints
41+
- `useAuthentication` _optional_ (default false). When enabled, access to `/api-docs` and `/api-docs/oas` requires a Directus admin cookie, static token, or Bearer JWT. Authorization is applied per endpoint based on Directus Access Policies, ensuring users only see endpoints they are allowed to access.
4242

4343
Example below:
4444

src/index.ts

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { defineEndpoint } from '@directus/extensions-sdk';
33
// import { SchemaOverview } from '@directus/shared/types';
44
import { SchemaOverview } from '@directus/types';
55
import { Router, Request, Response, NextFunction } from 'express';
6-
import { getConfig, getOas, getPackage, merge, filterPaths } from './utils';
6+
import { getConfig, getOas, getOasAll, getPackage, merge, filterPaths } from './utils';
77

88
const swaggerUi = require('swagger-ui-express');
99
const OpenApiValidator = require('express-openapi-validator');
@@ -12,23 +12,9 @@ const config = getConfig();
1212

1313
const id = config.docsPath;
1414

15-
async function checkIfApiDocsPublic(req: Request, res: Response, next: NextFunction): Promise<void | Response> {
16-
if (config.useAuthentication) {
17-
try {
18-
const accountability = (req as any).accountability;
19-
if (!accountability?.user) {
20-
return res.status(401).json({ message: 'Unauthorized' });
21-
}
22-
} catch (error) {
23-
return res.status(403).json({ message: 'Forbidden' });
24-
}
25-
}
26-
return next();
27-
}
28-
2915
async function validate(router: Router, services: any, schema: SchemaOverview, paths: Array<string>): Promise<Router> {
3016
if (config?.paths) {
31-
const oas = await getOas(services, schema);
17+
const oas = await getOasAll(services, schema);
3218

3319
// replace with custom endpoints
3420
if (paths) {
@@ -76,15 +62,16 @@ export default {
7662
},
7763
};
7864

79-
router.use(checkIfApiDocsPublic);
80-
8165
router.use('/', swaggerUi.serve);
8266
router.get('/', swaggerUi.setup({}, options));
8367

84-
router.get('/oas', async (_req: Request, res: Response, next: NextFunction) => {
68+
router.get('/oas', async (req: Request, res: Response, next: NextFunction) => {
8569
try {
8670
const schema = await getSchema();
87-
const swagger = await getOas(services, schema);
71+
72+
const accountability = config.useAuthentication ? (req as any).accountability : { admin: true };
73+
74+
const swagger = await getOas(services, schema, accountability);
8875

8976
const pkg = await getPackage();
9077

src/utils.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@ export function getConfig(): oasConfig {
113113
}
114114
}
115115

116-
export async function getOas(services: any, schema: SchemaOverview): Promise<oas> {
116+
export async function getOasAll(services: any, schema: SchemaOverview): Promise<oas> {
117117
if (oasBuffer) return JSON.parse(oasBuffer);
118118

119119
const { SpecificationService } = services;
120120
const service = new SpecificationService({
121-
accountability: { admin: true }, // null or accountability.admin = true needed
121+
accountability: { admin: true },
122122
schema,
123123
});
124124

@@ -127,6 +127,18 @@ export async function getOas(services: any, schema: SchemaOverview): Promise<oas
127127
return JSON.parse(oasBuffer);
128128
}
129129

130+
export async function getOas(services: any, schema: SchemaOverview, accountability: any): Promise<oas> {
131+
const { SpecificationService } = services;
132+
const service = new SpecificationService({
133+
accountability,
134+
schema,
135+
});
136+
137+
const oas = JSON.stringify(await service.oas.generate());
138+
139+
return JSON.parse(oas);
140+
}
141+
130142
export async function getPackage() {
131143
try {
132144
const workspaceDir = await findWorkspaceDir('.');

0 commit comments

Comments
 (0)