Skip to content

Getting started

Signing in

Three ways to give an agent, editor or script access to Slurry. The first two need no key copying: you approve a sign-in in the browser and the tool gets its own credential.

MethodBest forWhat the tool gets
OAuth for MCP clientsClaude Code, Cursor, VS Code, Claude.ai connectorsAccess token (1 hour) and a rotating refresh token (60 days)
Device loginAgents, CLIs, CI set-up scripts, headless machinesTokens, or one named account key for a single environment variable
Account keysAnything that takes a static headerslurry_acct_live_... created on the API keys page

Whichever you use, the credential acts as you in the organisation you pick, with the access you choose at consent: read only, or read and write. It never exceeds your role: viewers can only grant read, and if your role drops or you leave the organisation, the credential stops working at once. Everything you connect is listed under Connected apps on the API keys page, where you (or an owner or admin) can disconnect it.

OAuth for MCP clients

The Slurry MCP server implements the MCP authorization specification (2025-06-18). Give your client the URL https://api.slurry.io/mcp and nothing else: it discovers Slurry's authorization server, registers itself, opens a browser tab for you to approve, and handles tokens from then on.

Claude Code

terminal
claude mcp add --transport http slurry https://api.slurry.io/mcp
# then run /mcp in Claude Code and choose "Authenticate"

Cursor

.cursor/mcp.json
{
  "mcpServers": {
    "slurry": { "url": "https://api.slurry.io/mcp" }
  }
}

VS Code

.vscode/mcp.json
{
  "servers": {
    "slurry": { "type": "http", "url": "https://api.slurry.io/mcp" }
  }
}

In Claude.ai, add a custom connector with the same URL. The consent screen shows the app's name (as the app reports it), where it will send you back to, and the access it asks for.

What happens underneath

For people writing their own client. Each step follows the RFC named.

discovery and registration
# 1. an unauthenticated call is refused with a pointer to the metadata
curl -si https://api.slurry.io/mcp -X POST -H "content-type: application/json" -d '{}' | grep -i www-authenticate
# WWW-Authenticate: Bearer resource_metadata="https://api.slurry.io/.well-known/oauth-protected-resource"

# 2. protected resource metadata (RFC 9728) names the authorization server
curl -s https://api.slurry.io/.well-known/oauth-protected-resource

# 3. authorization server metadata (RFC 8414)
curl -s https://api.slurry.io/.well-known/oauth-authorization-server

# 4. dynamic client registration (RFC 7591): public clients only
curl -s https://api.slurry.io/oauth/register -H "content-type: application/json" \
  -d '{"client_name":"My MCP client","redirect_uris":["http://127.0.0.1:33418/callback"]}'

Then send the user to the authorization endpoint with PKCE (S256 only; plain is refused). The redirect URI must exactly match one you registered: https, http on localhost, 127.0.0.1 or [::1], or a desktop app scheme.

authorization request
https://slurry.io/oauth/authorize?response_type=code
  &client_id=slc_...
  &redirect_uri=http://127.0.0.1:33418/callback
  &code_challenge=<base64url(sha256(code_verifier))>
  &code_challenge_method=S256
  &state=<random>
  &scope=simulations:read%20simulations:write
  &resource=https%3A%2F%2Fapi.slurry.io%2Fmcp

Slurry redirects back with code, your state and iss. Codes are single use and expire after 60 seconds. Exchange the code:

token request
curl -s https://api.slurry.io/oauth/token \
  -d grant_type=authorization_code \
  -d client_id=slc_... \
  -d code="$CODE" \
  -d redirect_uri=http://127.0.0.1:33418/callback \
  -d code_verifier="$CODE_VERIFIER" \
  -d resource=https://api.slurry.io/mcp
  • Access tokens (slurry_oat_...) last one hour and work on the MCP server and the management API.
  • Refresh tokens (slurry_ort_...) last 60 days and rotate on every use. Presenting a used refresh token again revokes the whole sign-in: treat that as a leak.
  • The resource parameter (RFC 8707) must be https://api.slurry.io/mcp when you send it.
  • Registrations that never complete a sign-in are deleted after a day.

Device login for agents and scripts

The OAuth device authorization grant (RFC 8628) works anywhere a program can make HTTP requests and show you a short code, including headless machines. Use the public client id slurry-cli (no registration needed) and give it a client_name you will recognise on the consent screen.

1. start
curl -s https://api.slurry.io/oauth/device_authorization \
  -d client_id=slurry-cli \
  -d client_name="Nightly test runner" \
  -d scope="simulations:read simulations:write"
response
{
  "device_code": "Jc5Wq...",
  "user_code": "WDJB-MJHT",
  "verification_uri": "https://slurry.io/device",
  "verification_uri_complete": "https://slurry.io/device?user_code=WDJB-MJHT",
  "expires_in": 600,
  "interval": 5
}

Open verification_uri_complete (or go to slurry.io/device and type the code), check the code matches, pick the organisation and access, and approve. Codes expire after ten minutes. Meanwhile, poll the token endpoint no faster than interval seconds:

2. poll
curl -s https://api.slurry.io/oauth/token \
  -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
  -d client_id=slurry-cli \
  -d device_code="$DEVICE_CODE"
errorMeaning
authorization_pendingNot approved yet: wait interval seconds and poll again.
slow_downToo fast: add 5 seconds to the interval for every later poll.
access_deniedYou pressed Deny. Stop polling.
expired_tokenTen minutes passed. Start again.
approved
{
  "access_token": "slurry_oat_...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "slurry_ort_...",
  "scope": "simulations:read simulations:write"
}

Ask for an account key instead

Many agents want one environment variable rather than tokens to refresh. Add account_key to the scope and the approved device receives a named, long-lived account key, exactly once. It appears in your key list and under Connected apps with the name the device gave, and you can revoke it there. Viewers cannot receive account keys.

account key by device login
curl -s https://api.slurry.io/oauth/device_authorization \
  -d client_id=slurry-cli \
  -d client_name="Codex on build box" \
  -d scope="account_key simulations:read simulations:write"

# after approval, polling returns the key once:
# { "access_token": "slurry_acct_live_...", "account_key": "slurry_acct_live_...",
#   "token_type": "Bearer", "scope": "account_key simulations:read simulations:write",
#   "key_id": "...", "key_prefix": "slurry_acct_live_ab" }
slurry-login.sh
#!/usr/bin/env bash
# Sign in once, then keep the key in your secret store.
set -euo pipefail
start=$(curl -s https://api.slurry.io/oauth/device_authorization \
  -d client_id=slurry-cli -d client_name="$(hostname) script" \
  -d scope="account_key simulations:read simulations:write")
echo "Open $(echo "$start" | jq -r .verification_uri_complete) and approve code $(echo "$start" | jq -r .user_code)"
device=$(echo "$start" | jq -r .device_code); wait=$(echo "$start" | jq -r .interval)
while true; do
  sleep "$wait"
  out=$(curl -s https://api.slurry.io/oauth/token -d client_id=slurry-cli \
    -d grant_type=urn:ietf:params:oauth:grant-type:device_code -d device_code="$device")
  case $(echo "$out" | jq -r '.error // "ok"') in
    ok) echo "$out" | jq -r .account_key; break ;;
    authorization_pending) ;;
    slow_down) wait=$((wait + 5)) ;;
    *) echo "$out" >&2; exit 1 ;;
  esac
done

Using, refreshing and revoking tokens

call the API
curl https://api.slurry.io/v1/usage -H "Authorization: Bearer $ACCESS_TOKEN"
refresh (rotates the refresh token)
curl -s https://api.slurry.io/oauth/token \
  -d grant_type=refresh_token \
  -d client_id=slurry-cli \
  -d refresh_token="$REFRESH_TOKEN"
revoke (RFC 7009)
curl -s https://api.slurry.io/oauth/revoke \
  -d client_id=slurry-cli \
  -d token="$REFRESH_TOKEN"

Revoking a refresh token signs the app out completely; revoking an access token ends only that token. Disconnecting on the API keys page does the same as revoking the refresh token.

Account keys

Create a key on the API keys page and send it as Authorization: Bearer slurry_acct_live_.... Keys can be read only or read and write, can be locked to IP addresses and can expire. Use them for tools that only take a static header. See the management API and MCP server references.

Security notes

  • Every code and token is stored as a SHA-256 hash; Slurry cannot show one again.
  • Only public clients with PKCE are supported; Slurry never issues client secrets.
  • The consent form is bound to your session and the exact request, and Slurry only ever redirects to a URI the app registered.
  • Consents, token issue, refresh token reuse, device approvals and every disconnect are written to your audit log.
  • Endpoints are rate limited per address. Never approve a code or consent screen you did not start yourself.
Questions or a suspected leak: security@slurry.io.