Login
Device-code sign-in, and how a session is scoped to one workspace.
View as Markdownsctl loginTo sign in, open:
https://auth.saved.sh/device
and enter the code: WDJB-MJHT
Waiting for confirmation…
Signed in as you@example.com.The device code flow is the right one for a terminal: no local callback server, no browser embedded in a CLI, and it works over SSH. Approve it in a browser on any device, including your phone, and the CLI picks the session up.
Where the session lives
| Platform | Path |
|---|---|
| Linux | ~/.config/sctl/config.yaml |
| macOS | ~/Library/Application Support/sctl/config.yaml |
| Windows | %AppData%\sctl\config.yaml |
The directory is created 0700 and the file 0600 on Unix-like systems. On Windows it
inherits your user profile's ACL.
That file is a credential. It holds an access token and a refresh token. Treat it like an SSH private key: do not sync it to a shared drive, do not commit it, and delete it before handing a machine back.
Tokens are refreshed automatically. You will not normally sign in twice on the same machine.
Checking who you are
sctl auth whoamiUser: you@example.com
ID: 018f3c2a-...
Workspace: 4b7e1d90-...
Role: admin
Permissions:
- backups:read
- backups:write
...This is the fastest answer to "why was that refused": the permission list is exactly what the backend will enforce. If the permission you expected is missing, the problem is your role, not the command.
Workspaces
A session is scoped to exactly one workspace. Switching re-mints your token into the new one, so there is no token that spans two.
sctl workspace list
sctl workspace switch <workspace-id>
sctl workspace currentswitch takes the workspace ID, which sctl workspace list prints alongside the name.
sctl workspace create "analytics"Creating one makes you its admin, and it is human-only: a machine credential is refused, since a brand-new workspace has no permissions to check against.
If you have no workspace yet, sctl login says so and tells you to create one or accept an
invitation. A new user with no membership has no permissions anywhere, which is intentional.
Signing in for CI
Do not use your own session in a pipeline. Use an API key, and supply it through the environment rather than logging in.
export SCTL_ACCESS_TOKEN='sk_live_...'
export SCTL_WORKSPACE_ID='4b7e1d90-...'
sctl backup list$env:SCTL_ACCESS_TOKEN = 'sk_live_...'
$env:SCTL_WORKSPACE_ID = '4b7e1d90-...'
sctl backup listBoth variables are needed. A machine never ran sctl workspace switch, so nothing has told it
which workspace to act on.
A machine key cannot create a workspace, manage workers, manage other API keys, or touch billing, whatever permissions you try to grant it. See permissions.
Pointing at a different backend
sctl --backend-url https://api.staging.saved.sh workspace list
export SCTL_BACKEND_URL=https://api.staging.saved.shThe value is stored in the config file when you log in, so a session and the backend it was minted against stay together.
Environments are fully isolated. A session for one is worthless against another, and mixing
them is the usual cause of a confusing 401. If you work across two, keep two shells with
different SCTL_BACKEND_URL values rather than switching back and forth in one.
Signing out
There is no sctl logout. Delete the config file:
rm ~/.config/sctl/config.yaml # Linux
rm ~/Library/Application\ Support/sctl/config.yaml # macOSRemove-Item "$env:AppData\sctl\config.yaml"That removes the session from this machine. It does not revoke anything server-side: your account and any API keys are unaffected. To end access for a person, remove their membership; to end access for a machine, revoke its key.
Troubleshooting
| Message | Cause |
|---|---|
not signed in | No access token in the config file |
no workspace selected | Signed in, but no workspace chosen. In CI, SCTL_WORKSPACE_ID is unset |
401 on every command | The session is for a different backend, or the key was revoked |
403 naming a permission | The credential is valid and lacks that permission. Check sctl auth whoami |
| The browser approved but the CLI is still waiting | The code expired. Run sctl login again |