> Source: https://www.gitdash.info/docs/access-control · GitDash v4.7.1

# Access control

Organization mode

In organization mode an admin decides who sees which features. Features are the same switches people used to flip for themselves in Settings; now an admin grants them per group, and the server enforces the grant.

## The model

| Concept | How it works |
| --- | --- |
| Identity | The numeric GitHub id of the signed-in token, looked up from GitHub on every request (cached for a minute). |
| Groups | Fixed: `admin`, `devops`, `security`, `dev`, `pm`. A person can be in several. |
| Grants | An admin turns features on per group. A person gets every feature any of their groups has. |
| Admins | Members of `admin` get every feature and the admin screens. Ids in `GITDASH_ADMIN_GITHUB_IDS` are always admins, even with no group row. |
| No group | Signed in, but no access: the person waits on /pending until an admin adds them to a group. |
| Personal choice | People can still switch off features they were granted, in Settings → My features. They can never switch on a feature they were not granted. |

## Managing access

Admins manage access in **Admin** (sidebar) or in **Settings → Access by group / Members / Audit log** — both edit the same data. Every change is written to the audit log with who made it and what changed.

![Admin: users and their groups](https://www.gitdash.info/screenshots/admin-users.jpg)

![Admin: features granted to each group](https://www.gitdash.info/screenshots/admin-permissions.jpg)

![Admin: audit log of access changes](https://www.gitdash.info/screenshots/admin-audit.jpg)

The last admin cannot be removed: a change that would leave nobody in `admin` (apart from the ids in `GITDASH_ADMIN_GITHUB_IDS`) is refused.

## Waiting for access

Someone who signs in without a group lands on `/pending`. The page shows their GitHub login and numeric id to send to an admin, checks again every 15 seconds, and moves on by itself once a group is granted — usually within a minute, because group lookups are cached for 60 seconds.

## Enforcement

Every request passes through `src/proxy.ts`, which classifies the route and checks the grant before the route runs. A feature's pages redirect and its API routes answer 403 without the grant — also when called directly. API routes that are not registered are denied. Grants and revocations reach new requests within 60 seconds.

The grant decides which *GitDash features* someone can use; it never widens what their own GitHub token can read. Data GitDash serves from its own database (Reports, alert rules) is filtered by what the viewer's token can see on GitHub.

## Settings and rollout

```bash
DATABASE_URL=postgres://...        # required: users, groups, grants and the audit log
GITDASH_ADMIN_GITHUB_IDS=12345678   # required: numeric ids (gh api user --jq .id), comma-separated
GITDASH_ALLOWED_ORGS=my-org         # optional: only active members of these orgs may sign in
GITDASH_RBAC_ENFORCE=false          # rollout switch; set true once groups are assigned
```

1

#### Deploy with enforcement off

With `GITDASH_RBAC_ENFORCE` unset or `false`, everyone keeps full access; only the admin screens are restricted. The app refuses to start in organization mode without `DATABASE_URL` and a valid `GITDASH_ADMIN_GITHUB_IDS`, and `/api/health` answers 503.

2

#### Let people sign in, then assign

Grant features to groups, then put people in groups. New sign-ins appear in the users list automatically.

3

#### Turn enforcement on

Set `GITDASH_RBAC_ENFORCE=true` and redeploy. On Vercel, environment variable changes only apply to new deployments.

## When sign-in is refused

With `GITDASH_ALLOWED_ORGS` set, GitDash asks GitHub whether the account is an active member. If GitHub will not say, sign-in is refused — GitDash cannot tell a member from a stranger — and the server log records GitHub's reason.

| Cause | Fix |
| --- | --- |
| The org restricts OAuth Apps (every “Continue with GitHub” sign-in fails) | An org owner approves the GitDash OAuth App in the org's Third-party access settings. Unapproved, the app also cannot read the org's private repositories. |
| A fine-grained PAT created under the user | Create it with the **organization as resource owner** and grant `Members: read`. If the org approves fine-grained tokens, an owner must approve it first. |
| A classic PAT the org does not accept | It needs `read:org`; some orgs also reject classic tokens that live longer than 366 days. |
