Scopes
The complete list of Connect permissions and what each one grants.
A scope is a single named permission on a token. Request only what your app actually uses — users see the list on the consent screen.
The list#
| Scope | Grants |
|---|---|
profile.read | GET /connect/userinfo — user id and username |
profile.email | GET /connect/userinfo — the user's email address |
models.run | OpenAI-compatible API calls billed to the user with your app markup |
kv.read | Read per-user key/value data (scoped to your app) |
kv.write | Write per-user key/value data |
files.read | Read the user's folder for your app |
files.write | Write and delete files in that folder |
Scopes are space-separated in the scope parameter:
text
scope=models.run%20kv.read%20kv.writeRules#
- An app can only request scopes that are enabled for it in the console. See Enable Connect.
- Calling an endpoint without the scope for it returns
403. - Read and write are separate.
kv.readdoes not implykv.write. - The granted scopes come back on the token response in
scope, and are also reported by/connect/userinfo. Check them rather than assuming.
Choosing scopes#
| If your app | Request |
|---|---|
| Only runs models, keeps nothing | models.run |
| Remembers settings between sessions | models.run kv.read kv.write |
| Personalizes with the user's name | add profile.read |
| Signs the user into your own account system | add profile.read profile.email |
| Produces documents the user keeps | add files.read files.write |
Asking for storage scopes an app never uses is a common reason users decline at the consent screen, and a common reason a listing draws complaints.
Checking what you got#
bash
curl https://api.portmodels.com/connect/userinfo \
-H "Authorization: Bearer pmc_..."json
{ "user_id": "...", "username": "...", "scopes": ["models.run", "kv.read"], "app_id": "acme/chatbot" }Degrade gracefully when a scope is missing: an app that hard-fails because the
user declined files.write is worse than one that keeps working without saved
output.