# Sign agents in with access you control

> Canonical HTML: https://screenrig.ai/docs/authentication/

Every agent, app and script that works on your screens signs in with its own
session. A person approves each one in the dashboard, chooses Read only,
Propose or Manage, and can end it from the Access page at any time.

## How sign-in works

screenRIG issues short-lived signed access tokens and long-lived refresh
tokens. The bundled CLI keeps both in its private config file and renews them
on its own, so an agent never handles a token and never pastes one into a
conversation.

| Credential | Lifetime |
| --- | --- |
| Access token | 15 minutes |
| Refresh token | Rotates on every use. It ends 90 days after its last use, and at most one year after sign-in. |
| Sign-in code (`screenrig login`) | 24 hours |
| Service client token | 15 minutes, with no refresh token: the client asks for a new one |

There are four ways in:

| Who | How it signs in | Approved by |
| --- | --- | --- |
| A new agent with no account | `screenrig agent enroll` creates the organization, the Screens project and the session in one command | Enrollment itself; the person's emailed invitation follows |
| An agent for an existing account | `screenrig login` prints a code that a person approves in the dashboard | A project member, in the dashboard |
| A connected app (Claude, ChatGPT, Grok) | The app opens the screenRIG consent page; see [remote server](https://screenrig.ai/docs/mcp.md#connect-with-oauth) | A project member, on the consent page |
| A server, script or CI job | A [service client](https://screenrig.ai/docs/service-clients.md) signs in with its own key or secret | Created by a project member |

## Sign in with `screenrig login`

Use `screenrig login` when the person already has screenRIG and wants this
agent installation to work in one of their projects. A new installation with
no account starts with `screenrig agent enroll` instead; see
[Start](https://screenrig.ai/docs/start.md).

```sh
screenrig login
```

1. The CLI prints a dashboard address and an eight-letter code such as
   `BCDF-GHJK`, then waits.
2. The person opens `https://screenrig.ai/dashboard/connect`, signs in, and
   enters the code, or follows the full link that already carries it.
3. The dashboard shows the request on one screen: the installation name the
   device reported, when and where it asked, and the code. The person checks
   that the code matches the terminal, adjusts the project, the access level or
   the capabilities if they want, and presses Connect. A dashboard sign-in from
   the last hour is the proof, so Connect asks for nothing more; an older
   sign-in asks for a passkey. The dashboard then opens the new agent.
4. The CLI stores the session, selects the approved project and reports
   `status: signed_in` with the project, organization and access level.

Approve only a sign-in you started yourself, on your own computer. The
dashboard never approves anything on load, and an expired code needs a new
`screenrig login`.

| Flag | Effect |
| --- | --- |
| `--access read`, `--access propose` or `--access manage` | Ask for Read only, Propose or Manage. The default is `manage`; the person makes the final choice. |
| `--project prj_ID` | Suggest the project the person approves. |
| `--name NAME` | Name this installation, up to 80 characters. |
| `--no-wait` | Return at once with the address, the code and a `login_` handle. |
| `--resume login_ID` | Wait for that pending sign-in to be approved and store its session. |

When the agent has to pass the address to a person in another channel first,
use `--no-wait`. The handle holds no secret, and the pending sign-in stays in
the private config file:

```sh
screenrig login --no-wait
screenrig login --resume login_HANDLE
```

The sign-in address and its code are for the person who approves it. Send them
only to that person, and keep them out of logs and shared channels.

### Add a project or raise access

An installation that is already signed in runs `screenrig login` again to add
another project, or to raise a Read only or Propose project to Manage:

```sh
screenrig login --project prj_ID --access manage
```

The person approves that one change, and the installation keeps its other
projects. `screenrig project list` shows every project the installation can
use, and `screenrig project use ID` selects one.

## Read only, Propose and Manage

Every session carries one of three access levels, chosen by the person who
approves it. Each level includes everything the one before it can do.

| | Read only | Propose | Manage |
| --- | --- | --- | --- |
| List and read screens, playlists, media, events and playback | Yes | Yes | Yes |
| Upload and edit media, write project notes, capture screenshots, send feedback and support messages, draft ad creatives and campaigns | No | Yes | Yes |
| Create and update playlists; assign, schedule or take over screens | No | Yes, as a [review](https://screenrig.ai/docs/agents.md#reviews) a person approves | Yes |
| Delete, pair, archive, reload, reboot, send toasts, set display power, tag screens, write application K/V, manage webhooks and project settings | No | No | Yes |
| Spend credit on purchases, campaigns or image generation | No | No | Yes |
| Read webhook receiver URLs | No: the URL reads as redacted | Yes | Yes |
| Billed per request like every agent request | Yes | Yes | Yes |

Read only means the session cannot change or buy anything. It does not mean
free: each agent request and billed listen-stream event counts against the
project's [included requests](https://screenrig.ai/pricing.md), as it does for
Propose and Manage.

Propose lets an agent do the work while a person keeps the final say over what
plays. Its playlist and screen changes answer `202` with
`status: pending_review` and a link to the review, and nothing changes on a
screen until a person approves. Its media uploads, and its tag and folder
changes to approved media, wait for review too: screens keep playing what was
approved until a person approves the change, a rejection puts a changed item
back, and a rejected upload stays off the screens. It cannot delete, control
screens or spend.

A session that tries something its level cannot do gets
`403 insufficient_access`. The CLI names the next step: a person approves
Manage with `screenrig login --access manage`.

Agent sign-ins default to Manage, and connected apps to Read only. To lower an
installation, disconnect it, then sign in again with
`screenrig login --access read` or `--access propose`. A session's level is
never lowered silently: the review settings below hold sessions to Propose
without changing them, and the Access page shows when they do.

### Capabilities

Within its access level, a session works only in the capability areas the
person approved: `screens`, `content`, `playlists`, `advertising`, `reports`
and `project`. Enrollment grants all six on the project it creates. A command
outside the approved areas returns `403 forbidden` naming the missing
capability. Capabilities stay as approved for an installation's project; for
more, a person approves a new installation that has them.

## Require review for agent changes

Two settings hold agents to Propose without signing them in again. Both apply
on every request, so they cover sessions that already exist.

- **Require review for agent changes**, on the dashboard's
  [Project](https://screenrig.ai/dashboard/project) page. While it is on, every
  agent, connected app and service client in the project works at Propose at
  most: changes to what plays wait in
  [Reviews](https://screenrig.ai/docs/agents.md#reviews) until a person
  approves them. The project owner or an admin of its organization changes it,
  and turning it off asks for their passkey. Reviews already waiting stay open
  to decide.
- **Can approve**, for each member on the project's People page. The project
  owner always can approve. A member who cannot approve does not decide
  reviews and cannot give an agent Manage, and the agents that member is
  responsible for work at Propose at most.

The lowest level that applies wins. `screenrig agent status` reports the
session's `access`, its `effective_access` and, when a setting lowers it,
`access_limited_by`: `project` or `person`. Signing in again does not lift a
setting; the project owner changes it. While a setting applies, the sign-in
and connection approval screens offer Read only and Propose, and show why
Manage is unavailable.

## The Access page

The dashboard's [Access](https://screenrig.ai/dashboard/access) page lists
everything that can act on the current project:

| Section | What it lists |
| --- | --- |
| Pending | Sign-ins and connection requests waiting for approval |
| People | Members and open invitations |
| Agents | CLI and plugin installations, enrolled or signed in |
| Connected apps | AI assistants a person connected, one entry per app |
| Service clients | Servers, scripts and CI jobs, with their keys and secrets |

Each entry shows how it got access and who approved it, its access level and
capabilities, and when it was created and last used. When a review setting
holds an entry below its level, the entry shows the level it works at and why,
for example "Propose — project requires review". **Disconnect** ends an
agent or app; **Revoke** ends a service client. Each asks the person to confirm
with their passkey.

## Sign out and revoke

| To end | Run or do |
| --- | --- |
| This installation's sign-in | `screenrig logout` |
| This installation's access to the current project | `screenrig agent disconnect --yes` |
| This installation everywhere | `screenrig agent revoke-identity --yes` |
| Any agent or connected app | **Disconnect** on the Access page |
| A service client | **Revoke** on the Access page, or `screenrig service-client revoke ID --yes` |

`screenrig logout` revokes the sign-in on the server, then removes the stored
tokens. If the request might not have reached the server, the tokens stay, so
running it again is safe. A Read only session can always disconnect itself.

A revoked session cannot renew: no new token is issued after the revoke. Its
access tokens stop working within seconds. Deactivating the person responsible
for an agent ends its sessions the same way, and deleting a project ends every
session's access to that project.

## Session length

Each use of the refresh token moves its end 90 days forward, up to one year
after sign-in. `screenrig doctor` shows when this installation's session ends,
and every command warns in its last 30 days. To continue, a person approves a new
`screenrig login`.

## Existing credentials

Installations that signed in before these sessions keep working. On its next
command, the bundled CLI exchanges the stored credential for a session with the
same projects and capabilities, without a prompt and without output. Update the
official plugin to get that CLI; nothing else changes for the agent.

## Reference

These endpoints follow OAuth 2.0. The bundled CLI, connected apps and service
clients use them; an agent working through the plugin never calls them
directly.

| Item | Value |
| --- | --- |
| Issuer | `https://api.screenrig.ai` |
| Authorization server metadata | `https://api.screenrig.ai/.well-known/oauth-authorization-server` |
| Protected resource metadata | `https://api.screenrig.ai/.well-known/oauth-protected-resource/api` |
| Token endpoint | `https://api.screenrig.ai/oauth/token` |
| Device authorization | `https://api.screenrig.ai/oauth/device_authorization` |
| Authorization endpoint | `https://api.screenrig.ai/oauth/authorize` |
| Revocation | `https://api.screenrig.ai/oauth/revoke` |
| Grant types | `authorization_code` (PKCE `S256` only), `refresh_token`, `urn:ietf:params:oauth:grant-type:device_code`, `client_credentials`, `urn:ietf:params:oauth:grant-type:token-exchange` |
| Client authentication | `none`, `private_key_jwt` (`EdDSA`, `ES256`, `RS256`), `client_secret_basic` |
| Scopes | `access:read`, `access:propose`, `access:manage`, `identity`, and the capabilities `screens`, `content`, `playlists`, `advertising`, `reports`, `project` |
| Resources | `https://api.screenrig.ai/api` (the default) and `https://api.screenrig.ai/mcp` |

Access tokens are JWTs signed with Ed25519 (`EdDSA`): an EdDSA-only profile
using the claim conventions of RFC 9068 (`typ: at+jwt`, `iss`, `aud`, `sub`,
`client_id`, `scope`, `jti`, `iat`, `exp`). Treat them as opaque: send each one
as `Authorization: Bearer` and request a new one when it expires.

Token endpoint errors are RFC 6749 JSON (`error`, `error_description`) with
`Cache-Control: no-store`:

| `error` | Meaning | CLI problem |
| --- | --- | --- |
| `invalid_grant` | The session was revoked, expired or reused, or a code is wrong | `session_ended`: run `screenrig login` |
| `invalid_client` | Unknown client, or a wrong key, secret or assertion | `client_auth_failed` |
| `invalid_scope` | More access or capabilities than were approved | `insufficient_access` |
| `invalid_target` | A `resource` other than the two above | `invalid_request` |
| `authorization_pending`, `slow_down` | A sign-in still waiting for approval | The CLI keeps waiting |
| `access_denied` | The person denied the sign-in | `login_denied` |
| `expired_token` | The sign-in code expired | `login_expired`: run `screenrig login` |
| `temporarily_unavailable` | Try again shortly | `service_unavailable` |
| `rate_limited` | Wait for `Retry-After` | `rate_limited` |

Requests to `/api` with an expired or revoked access token answer `401` with
`WWW-Authenticate: Bearer error="invalid_token"`; the CLI renews once and
retries once. A token calling something its access level cannot do answers
`403` `insufficient_access` with
`WWW-Authenticate: Bearer error="insufficient_scope"` and the `scope` that
allows it.

The token and revocation endpoints accept 1,200 requests per client address per
hour, 60 renewals per session per hour and 600 service-client tokens per client
per hour. Sign-in starts are limited to 10 per address per hour.

## Related

- [Start](https://screenrig.ai/docs/start.md): install the official plugin and create a project.
- [Service clients](https://screenrig.ai/docs/service-clients.md): sign servers, scripts and CI jobs in with client credentials.
- [Reviews](https://screenrig.ai/docs/agents.md#reviews): approve, reject or request changes to what an agent proposes.
- [CLI reference](https://screenrig.ai/docs/cli.md#sign-in): `login`, `logout` and the agent commands.
- [Remote server](https://screenrig.ai/docs/mcp.md): connect Claude, ChatGPT or Grok.
