backstage / backstage/backstage
[TechDocs] Add permission framework integration for documentation access control
- Dominant language
- TypeScript
- Stars
- 34.4k
- Forks
- 7.6k
- Avg merge
- 8h 57m
- Merged PRs (30d)
- 50
Description
### 📜 Issue Labels
- [x] Please familiarize yourself with the issue labels used in this project: [LABELS.md](https://github.com/backstage/backstage/blob/master/LABELS.md)
### 🔎 Search Terms
```plain
techdocs permissions, techdocs access control, techdocs permission framework, techdocs entity read, docs tab restrict access, techdocs backend authorize
```
### 🗃️ Project Area
TechDocs
### 🔖 Need
Currently the TechDocs backend serves static documentation assets (HTML, JS, assets) directly from object storage (S3, GCS, Azure Blob) without consulting the Backstage permission framework. This means it is **impossible** to restrict access to documentation content independently from catalog entity metadata visibility.
This gap affects any organization that needs to host documentation for private or sensitive repositories in a shared Backstage deployment. Use cases include:
- **Private repository docs**: Teams with internal-only source code want TechDocs visible only to entity owners, while still allowing the catalog entry (name, description, owner, tags) to be discoverable by everyone.
- **Compliance-sensitive content**: Security runbooks, architecture decision records, or regulated-product documentation should be readable only by authorized groups.
- **Multi-tenant deployments**: Organizations running a single Backstage instance for many teams need per-entity content gating, not just catalog-metadata gating.
Today the only workaround is a **frontend-only gate** — a component that hides the Docs tab in the UI. This does not protect the underlying docs API endpoint (`/api/techdocs/...`) or the direct S3/storage asset URLs, so it is not a genuine access control mechanism.
`catalog.entity.read` already exists and gates the catalog API correctly. TechDocs should offer an equivalent so that documentation and metadata can have independent visibility policies.
### 📝 Proposal
Add a `techdocs.entity.read` resource permission to the TechDocs plugin, using `catalog-entity` as the resource type (consistent with how `catalog.entity.read` works).
### Permission definition
In `@backstage/plugin-techdocs-common` (or a new `@backstage/plugin-techdocs-node`), export:
```
import { createPermission } from '@backstage/plugin-permission-common';
export const techDocsEntityReadPermission = createPermission({
name: 'techdocs.entity.read',
attributes: { action: 'read' },
resourceType: 'catalog-entity',
});
export const techDocsPermissions = [techDocsEntityReadPermission];
```
Backend integration
In @backstage/plugin-techdocs-backend, before serving any documentation content (HTML, assets, search index), call:
```
const decision = await permissions.authorize(
[{ permission: techDocsEntityReadPermission, resourceRef: stringifyEntityRef(entity) }],
{ credentials },
);
if (decision[0].result === AuthorizeResult.DENY) {
throw new NotAllowedError('Access to TechDocs for this entity is not permitted');
}
```
### 🔄 Alternatives
_No response_
### Have you read the Code of Conduct?
- [x] I have read the [Code of Conduct](https://github.com/backstage/backstage/blob/master/CODE_OF_CONDUCT.md)
### Are you willing to submit a PR?
Yes, and I have enough information to get started
Contributor guide
Research direction
Start in @backstage/plugin-techdocs-backend and trace the handlers serving /api/techdocs/... content, including HTML, assets, and the search index. Read the proposed permission definition in @backstage/plugin-techdocs-common or @backstage/plugin-techdocs-node alongside the existing catalog.entity.read pattern. Done means documentation requests authorize the entity with the request credentials and deny unauthorized access.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authorization, backend, documentation
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100