A minimal AT Protocol Personal Data Server written in JavaScript.
atproto pds
46
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v0.5.0 146 lines 6.5 kB view raw view rendered
1# Scope Validation Comparison: pds.js vs atproto PDS 2 3Comparison of OAuth scope validation between this implementation and the official AT Protocol PDS. 4 5--- 6 7## Scope Types Supported 8 9| Scope Type | Format | pds.js | atproto PDS | 10|------------|--------|--------|-------------| 11| `atproto` | Static | Full access | Required for all OAuth | 12| `transition:generic` | Static | Full access | Full repo/blob bypass | 13| `transition:email` | Static | N/A | Read account email | 14| `transition:chat.bsky` | Static | N/A | Chat RPC access | 15| `repo:<collection>?action=<action>` | Granular | Full parsing + enforcement | Full parsing + enforcement | 16| `blob:<mime>` | Granular | Full parsing + enforcement | Full parsing + enforcement | 17| `rpc:<aud>:<lxm>` | Granular | Not implemented | Full parsing + enforcement | 18 19--- 20 21## Scope Enforcement by Endpoint 22 23### com.atproto.repo.createRecord 24 25| Aspect | pds.js | atproto PDS | 26|--------|--------|-------------| 27| Scope check | `ScopePermissions.allowsRepo(collection, 'create')` | `permissions.assertRepo({ action: 'create', collection })` | 28| Required scope | `repo:<collection>?action=create` or `transition:generic` or `atproto` | `repo:<collection>?action=create` or `transition:generic` or `atproto` | 29| OAuth-only check | Yes (legacy tokens without scope bypass) | Yes (legacy Bearer bypasses) | 30| Error response | 403 "Missing required scope \"repo:...?action=...\"" | 403 "Missing required scope \"repo:...?action=...\"" | 31 32### com.atproto.repo.putRecord 33 34| Aspect | pds.js | atproto PDS | 35|--------|--------|-------------| 36| Scope check | `allowsRepo(collection, 'create')` AND `allowsRepo(collection, 'update')` | `assertRepo({ action: 'create' })` AND `assertRepo({ action: 'update' })` | 37| Required scope | `repo:<collection>?action=create&action=update` | `repo:<collection>?action=create&action=update` | 38| Notes | Requires both since putRecord can create or update | Requires both since putRecord can create or update | 39 40### com.atproto.repo.deleteRecord 41 42| Aspect | pds.js | atproto PDS | 43|--------|--------|-------------| 44| Scope check | `ScopePermissions.allowsRepo(collection, 'delete')` | `permissions.assertRepo({ action: 'delete', collection })` | 45| Required scope | `repo:<collection>?action=delete` | `repo:<collection>?action=delete` | 46 47### com.atproto.repo.applyWrites 48 49| Aspect | pds.js | atproto PDS | 50|--------|--------|-------------| 51| Scope check | Iterates all writes, checks each unique action/collection pair | Iterates all writes, asserts each unique action/collection pair | 52| Required scope | All `repo:<collection>?action=<action>` for each write | All `repo:<collection>?action=<action>` for each write | 53| Per-write validation | Yes | Yes | 54 55### com.atproto.repo.uploadBlob 56 57| Aspect | pds.js | atproto PDS | 58|--------|--------|-------------| 59| Scope check | `ScopePermissions.allowsBlob(contentType)` | `permissions.assertBlob({ mime: encoding })` | 60| Required scope | `blob:<mime-type>` (e.g., `blob:image/*`) | `blob:<mime-type>` (e.g., `blob:image/*`) | 61| MIME type awareness | Yes (validates against Content-Type) | Yes (validates against Content-Type) | 62 63### app.bsky.actor.getPreferences 64 65| Aspect | pds.js | atproto PDS | 66|--------|--------|-------------| 67| Scope check | Requires auth only | `permissions.assertRpc({ aud, lxm })` | 68| Required scope | Any valid auth | `rpc:app.bsky.actor.getPreferences` | 69 70### app.bsky.actor.putPreferences 71 72| Aspect | pds.js | atproto PDS | 73|--------|--------|-------------| 74| Scope check | Requires auth only | `permissions.assertRpc({ aud, lxm })` | 75| Required scope | Any valid auth | `rpc:app.bsky.actor.putPreferences` | 76 77--- 78 79## Scope Parsing 80 81| Feature | pds.js | atproto PDS | 82|---------|--------|-------------| 83| Scope string splitting | `scope.split(' ')` | `ScopesSet` class | 84| Repo scope parsing | `parseRepoScope()` | `RepoPermission.fromString()` | 85| Repo scope format | `repo:collection?action=create&action=update` | `repo:collection?action=create&action=update` | 86| Blob scope parsing | `parseBlobScope()` | `BlobPermission.fromString()` | 87| RPC scope parsing | None | `RpcPermission.fromString()` | 88| Scope validation | Returns null for invalid | Validates syntax, ignores invalid | 89| Action deduplication | Yes (via Set) | Yes | 90| Default actions | All (create, update, delete) when no `?action=` | All (create, update, delete) when no `?action=` | 91 92--- 93 94## Permission Checking 95 96| Feature | pds.js | atproto PDS | 97|---------|--------|-------------| 98| Permission class | `ScopePermissions` | `ScopePermissions` / `ScopePermissionsTransition` | 99| `allowsRepo(collection, action)` | Yes | Yes | 100| `allowsBlob(mime)` | Yes (with MIME wildcard matching) | Yes (with MIME wildcard matching) | 101| `allowsRpc(aud, lxm)` | N/A | Yes | 102| Transition scope handling | `transition:generic` bypasses repo/blob checks | `transition:generic` bypasses repo/blob checks | 103| Error messages | Specific missing scope in error | Specific missing scope in error | 104 105--- 106 107## OAuth Flow 108 109| Feature | pds.js | atproto PDS | 110|---------|--------|-------------| 111| `scopes_supported` in metadata | `['atproto']` | `['atproto']` (but accepts granular) | 112| Scope validation at PAR | None | Validates syntax | 113| Scope stored in token | Yes | Yes | 114| Scope returned in token response | Yes | Yes | 115| `atproto` scope required | Checked at endpoints | Required at token verification | 116 117--- 118 119## Transition Scope Behavior 120 121| Scope | pds.js | atproto PDS | 122|-------|--------|-------------| 123| `transition:generic` | Bypasses all repo/blob permission checks | Bypasses ALL repo/blob permission checks | 124| `transition:chat.bsky` | Not implemented | Allows `chat.bsky.*` RPC methods | 125| `transition:email` | Not implemented | Allows `account:email:read` | 126 127--- 128 129## Summary 130 131| Category | pds.js | atproto PDS | 132|----------|--------|-------------| 133| Scope parsing | Full parser for repo/blob | Full parser per scope type | 134| Enforcement granularity | Per-collection, per-action | Per-collection, per-action | 135| Transition scope support | `transition:generic` only | Full | 136| MIME-aware blob scopes | Yes | Yes | 137| RPC scopes | No | Yes | 138| Error specificity | Names missing scope | Names missing scope | 139 140--- 141 142## Remaining Gaps 143 1441. **RPC scopes**`rpc:<aud>:<lxm>` parsing and enforcement not implemented 1452. **Additional transition scopes**`transition:chat.bsky` and `transition:email` not implemented 1463. **Scope validation at PAR** — Could validate scope syntax during authorization request