Who may read a page is decided by the access key in the repository's .speicher.yaml files, and nowhere else. This page explains how access works, how folders narrow it, and how to grant access to individual people and to the public.
Granting access to a repository
Every repository needs an access key in its root .speicher.yaml. It lists the groups whose members may read the repository:
version: 1
access: [staff]
The names are Speicher's own group names, which an administrator maps to groups of your identity provider. See Create groups.
The list above is a shorthand. The full form also lets you grant access to individual people:
version: 1
access:
groups: [staff]
users:
- email: [email protected]
until: 2027-03-31
Caution
A root .speicher.yaml without access is rejected, and the repository is not published. To unpublish a repository on purpose, delete its root .speicher.yaml.
Narrowing access in folders
A folder can have its own .speicher.yaml with an access key. It can only narrow what the folder inherits, never widen it: a reader needs to be allowed at every level, from the repository root down to the folder. A folder without its own .speicher.yaml inherits its parent's access unchanged.
For example:
handbook/
├── .speicher.yaml access: [staff, sales, leadership]
├── onboarding.md
├── sales/
│ ├── .speicher.yaml access: [sales, leadership]
│ └── pricing.md
└── leadership/
├── .speicher.yaml access: [leadership]
└── board-minutes.md
| Page | staff |
sales |
leadership |
|---|---|---|---|
onboarding.md |
yes | yes | yes |
sales/pricing.md |
yes | yes | |
leadership/board-minutes.md |
yes |
Someone in several groups sees everything any of their groups may see.
Caution
A folder cannot add a group that its parent did not grant. If the root grants [staff] and a folder says access: [sales], nobody can read that folder, and the sync reports no readers specified. Grant every group at the root, then narrow it down in the folders.
Granting access to individual people
Under users, you can grant access to a person directly, for example an external collaborator who is in none of your groups. Every individual grant needs an expiry date in until:
version: 1
access:
groups: [staff]
users:
# By email address
- email: [email protected]
until: 2027-03-31
# By the identity provider's subject id, which needs a note saying who it is
- provider: entra
subject: 4f6c1a9e-2b7d-4c1e-9a3f-0d5e8b7c6a21
note: Jane Doe, external auditor
until: 2027-03-31
Each grant names a person in exactly one of two ways:
email: matched against the email address the identity provider reports when the person signs in. If the provider has a directory configured, Speicher looks the address up during each sync and stores the person's subject id instead.subjectwith anote: the person's permanent id at the identity provider. It never changes and is never reused for someone else, so it is the safer choice. The note records who it is, since the id itself means nothing to a reader.
provider names the identity provider the person signs in with, by the short id it has in the instance configuration. You can leave it out when the instance has only one provider, or when an administrator has set auth.default_provider. Otherwise the grant is rejected.
until is a date such as 2027-03-31. The grant is valid until the end of that day (UTC). After that, Speicher syncs the repository again and drops the grant.
Making pages public
Publishing a page to the internet takes two steps, and both are required:
-
An administrator allows the repository to be public by listing it under
public.reposin the instance configuration:public: repos: [acme/handbook] -
The repository grants access to
public, a reserved group that everyone has, including visitors who are not signed in:version: 1 access: [public, staff]
If the repository names public without being listed under public.repos, the configuration is rejected.
Folders narrow public access like any other group. To keep one folder internal, grant both at the root and narrow the folder:
handbook/
├── .speicher.yaml access: [public, staff]
├── index.md everyone
└── internal/
├── .speicher.yaml access: [staff]
└── roadmap.md staff only
Maintainers
The root .speicher.yaml can name the maintainers of a repository. Maintainers can see the repository's sync status and the problems its last sync ran into. They get no other dashboard access, and no access to the content itself. To read the pages, they need to be in access as well.
version: 1
access: [staff]
maintainers:
groups: [docs-team]
users:
- email: [email protected]
until: 2027-03-31
maintainers always uses the full form with groups and users, and it cannot name public.
Images and other files
An image or other file is readable by the people who may read the folder it is stored in, not the page that links to it. If a page in onboarding/ shows an image stored in sales/, readers who are not allowed into sales/ see a broken image. Keep files next to the pages that use them.
Frontmatter cannot change access
A page's frontmatter has no say in who may read it. A page whose frontmatter contains access, maintainers, groups or users is rejected, and its folder is not updated until the key is removed. To restrict a single page, move it into a folder with its own .speicher.yaml.
When a configuration is rejected
A rejected .speicher.yaml never makes content more visible. When the sync rejects a configuration, for example because of an unknown group name or a missing until, the affected part of the repository is not updated. Readers keep seeing what was published there before. If the root configuration is rejected, none of the commit's changes are published.
The problems are listed on the repository's Sync status page in the dashboard.
All access keys
The full list of .speicher.yaml keys is in the repository configuration reference.
| Key | Type | Default | Required | Description |
|---|---|---|---|---|
access |
list of string or object | Who may read the pages at this level. Required in the root .speicher.yaml. In a folder, it can only narrow what the folder inherits: a reader must be allowed at every level from the root down. |
||
access.groups |
list of string | Group names whose members may read. Each name must be a group configured on the instance, or public if the instance lists this repository under public.repos. |
||
access.users |
list of object | Individual people who may read, each with an expiry date. | ||
access.users[] |
object | One person, named by email or by subject with a note. Set exactly one of: subject + note, email. |
||
access.users[].provider |
string | Short id of the identity provider the person signs in with. Can be left out when the instance has one provider or sets auth.default_provider. |
||
access.users[].subject |
string | The person's permanent id at the identity provider, the value of its subject claim. It never changes and is never reused. For a magic-link provider, it is the email address. Needs a note. |
||
access.users[].email |
string (email) | The person's email address, matched against the address the identity provider reports at sign-in. If the provider has a directory, it is resolved to the person's subject id during each sync. | ||
access.users[].note |
string | Who this grant is for, such as a name and role. Required with subject. Up to 200 characters. |
||
access.users[].until |
string (date) | yes | Date the grant ends, as YYYY-MM-DD. It is valid until the end of that day (UTC). The repository then syncs again and the grant is dropped. |