Skip to content
Shortspan

Search documentation

Find a page by title, section, or summary.

Authentication

Bearer tokens, token abilities, the device authorization flow, and how the API answers a suspended account.

Bearer tokens

bash
curl -H "Authorization: Bearer $SHORTSPAN_TOKEN" \
     -H "Accept: application/json" \
     https://shortspan.dev/api/v1/auth/me

Tokens are issued by the device flow, by shortspan token create, or in the console under API tokens. They are shown once; only a hash is stored.

GET /api/v1/auth/me returns the authenticated user and the current token's abilities. It is the cheapest way to check that a token is live and correctly scoped.

Abilities

Each token carries abilities that narrow what it may do. They never widen it - the role check runs regardless, so a token with secrets:reveal held by a viewer reveals nothing.

bash
curl -X POST https://shortspan.dev/api/v1/tokens \
  -H "Authorization: Bearer $SHORTSPAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ci-deploy",
    "abilities": ["secrets:read", "ssh:use"]
  }'

Omitting abilities grants the standard interactive set: secrets:read, ssh:use, db:use, aws:inject, k8s:use, runbooks:execute, access:request. Note that secrets:reveal is not among them.

The full list is in API tokens and devices.

The device authorization flow

For clients that cannot receive a redirect - a CLI, a TV, a headless tool. Two endpoints, both unauthenticated.

1. Request a code

bash
curl -X POST https://shortspan.dev/api/v1/auth/device-code
json
{
  "data": {
    "device_code": "…",
    "user_code": "WDJB-MJHT",
    "verification_uri": "https://shortspan.dev/device",
    "expires_in": 600,
    "interval": 5
  }
}

2. Show the user code, and poll

Display user_code and verification_uri. The person opens the URL in a browser where they are signed in, checks that the code matches, and approves. Meanwhile, poll:

bash
curl -X POST https://shortspan.dev/api/v1/auth/device-token \
  -H "Content-Type: application/json" \
  -d '{"device_code": "…"}'
ResponseMeaning

400 authorization_pending

Not approved yet. Keep polling at interval.

400 expired_token

The ten-minute window closed. Start over.

400 access_denied

The user refused. Do not retry.

200 with a token

Approved. Store it and stop polling.

Codes live for ten minutes. Both the code and the poll are rate limited, per code and per IP, so a single honest login has its own budget while enumeration across many codes is bounded.

Authentication failures

Status and codeCauseCorrect client behaviour

401 UNAUTHENTICATED

Missing, malformed, expired, or revoked token.

Re-authenticate.

403 account_suspended

The account or workspace is suspended.

Do not re-authenticate. Surface the message; a new token will fail identically.

403 PERMISSION_DENIED

Role or ability insufficient.

Do not retry. The credential is fine; the permission is not.

403 CLI_VERSION_BLOCKED

This client version has been withdrawn.

Tell the user to upgrade.

409 ONBOARDING_REQUIRED

The account has no workspace yet.

Send them to the URL in the body.

426 HTTPS_REQUIRED

The request was not TLS.

Fix the client. Do not retry over plaintext.

Revoking

bash
# Revoke the token making the request
curl -X DELETE https://shortspan.dev/api/v1/auth/token \
  -H "Authorization: Bearer $SHORTSPAN_TOKEN"

# Revoke another one you own
curl -X DELETE https://shortspan.dev/api/v1/tokens/{tokenId} \
  -H "Authorization: Bearer $SHORTSPAN_TOKEN"

Self-revocation remains available to suspended accounts. Losing access must never mean losing the ability to hand a credential back.

Something here wrong or missing? Tell us.