dev.cocore.devicePair.start
Begin a device-pairing flow (OAuth 2.0 device-authorization style). Returns a `deviceId` plus a short human-typable `userCode` and the `verificationUri` where a signed-in user approves the pairing. The caller then polls `dev.cocore.devicePair.poll` until approval. The optional input lets an application (rather than a provider machine) say who it is: `appName` is shown on the approve screen, `keyName` names the minted API key so the user can recognise and revoke it, and `returnUrl` is where the approve screen sends the browser afterwards. `returnUrl` is honoured only for hosts the deployment allowlists; anything else is dropped silently, never rejected.
Details · procedure
| Kind | procedure |
|---|---|
| Authority | devicePair.cocore.dev |
| Indexed |
Showing version bafyreifujrh63pgqjy7ycyr3p3vifv2l6j4xgepxoayne2d73jktw3nc4i. Show the latest
Checks
Validunlimited-stringdefs.main.output.schema.properties.deviceIdNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.main.output.schema.properties.userCodeNo maxLength, maxGraphemes or format limits this string.
{
"$type": "com.atproto.lexicon.schema",
"defs": {
"main": {
"description": "Begin a device-pairing flow (OAuth 2.0 device-authorization style). Returns a `deviceId` plus a short human-typable `userCode` and the `verificationUri` where a signed-in user approves the pairing. The caller then polls `dev.cocore.devicePair.poll` until approval. The optional input lets an application (rather than a provider machine) say who it is: `appName` is shown on the approve screen, `keyName` names the minted API key so the user can recognise and revoke it, and `returnUrl` is where the approve screen sends the browser afterwards. `returnUrl` is honoured only for hosts the deployment allowlists; anything else is dropped silently, never rejected.",
"errors": [
{
"description": "Too many pairing attempts from this client; retry later.",
"name": "RateLimited"
},
{
"description": "`appDid` is not a DID, or has no `dev.cocore.app.registration` record (message begins `AppNotRegistered`).",
"name": "InvalidRequest"
}
],
"input": {
"encoding": "application/json",
"schema": {
"properties": {
"appDid": {
"description": "The requesting application's DID. When present the AppView reads the app's `dev.cocore.app.registration` record: the approve screen shows that record's `name` (the `appName` field is ignored) and `returnUrl` is honoured only if it matches one of the record's `returnUrls` AND the return host proves ownership via `/.well-known/cocore-app.json`. A DID with no registration record is rejected with InvalidRequest (AppNotRegistered).",
"format": "did",
"type": "string"
},
"appName": {
"description": "Human name of the requesting application, shown on the approve screen.",
"maxLength": 40,
"type": "string"
},
"keyName": {
"description": "Name for the API key minted on approval.",
"maxLength": 100,
"type": "string"
},
"returnUrl": {
"description": "Where to send the browser after approval. Must be https and on an allowlisted host.",
"format": "uri",
"maxLength": 2000,
"type": "string"
}
},
"type": "object"
}
},
"output": {
"encoding": "application/json",
"schema": {
"properties": {
"deviceId": {
"type": "string"
},
"expiresInSecs": {
"description": "Seconds until this pairing attempt expires.",
"type": "integer"
},
"pollIntervalSecs": {
"description": "Minimum seconds between poll calls.",
"type": "integer"
},
"userCode": {
"description": "Short code the user types at the verification URI.",
"type": "string"
},
"verificationUri": {
"format": "uri",
"type": "string"
}
},
"required": [
"deviceId",
"userCode",
"verificationUri",
"pollIntervalSecs",
"expiresInSecs"
],
"type": "object"
}
},
"type": "procedure"
}
},
"id": "dev.cocore.devicePair.start",
"lexicon": 1
}