{
  "$type": "com.whtwnd.blog.entry",
  "theme": "github-light",
  "title": "atproto OAuthスコープの現状 (2025/08版)",
  "content": "**公式発表でこの記事の内容はほぼカバーされた。以下を参照のこと。**\n\nhttps://github.com/bluesky-social/atproto/discussions/2656\n\n\n### 前書き\n\nBlueskyのaptoroリポジトリで開発されているOAuthスコープの[基礎部分](https://github.com/bluesky-social/atproto/pull/3806)が先日マージされた。\\\n現在の荒いOAuthも影響を受けており、認証画面の表示が変わったことに気付いている人もいるだろう。\n\nあくまで基礎なのでまだ道半ばだが、開発者や利用者にも注目されているようなので、現時点の実装からざっくり情報をまとめてみた。\\\n大体の仕様は[proposal 0011](https://github.com/bluesky-social/proposals/tree/main/0011-auth-scopes)で既に告知されている内容であり、新規情報としてはこれまで詳細説明を避けてきた個別のリソースの振る舞いが主となる。\n\n「2025/08時点の」「実装から読み取った内容を」「個人の推測込みで」記載しているので、くれぐれも間に受けないように。\n\n### 共通仕様\n\nproposalの復習。\n\natprotoのOAuthスコープは`リソース名:先頭引数値?他引数名=他引数値`の形で表す。先頭引数も名前付きで定義することは可能。\\\nproposalでは明記されていないが、名前付きは[`&`で繋げて複数指定できる](https://github.com/bluesky-social/atproto/blob/649e5ad7726ec369fced3700b82c96931090fe3c/packages/oauth/oauth-scopes/src/syntax.test.ts#L53-L57)。なお、同じ引数を複数回指定することも可能で、配列として結合して解釈される。\n\n個別のリソースはatproto仕様で定義される。詳細は後述。\n\nスコープに対応するlexicon型として`permission`と`permission-set`が新たに定義される。\\\nこれは主にスコープを圧縮するための要素だが、[実装着手](https://github.com/bluesky-social/atproto/pull/4108)したばかりなので割愛。\\\nlexicon管理者がAPI/collectionを圧縮する用途でのみ使われ、クライアントが勝手に定義したりはできない点に注意。`app.bsky.feed.*`と`app.bsky.graph.*`の両方を含むpermission-setを定義するには、NSIDが`app.bsky.xxx`でなければならない。[^set]\n\n[^set]: permission-setの内容更新は再認証無しで追随するため、自由な定義を許すと利用者が確認した権限が狭くても後から好き勝手できてしまう。再認証必須にすればAPIが増減する度にお伺いを立てないといけない。逆に言えばlexicon所有者は他人のappviewに悪さできる可能性があるため、XRPC APIを実装する際は採用するlexiconが信頼できるかを考慮するべき。\n\nなお、`atproto`スコープは必ず含めなければならない。これは他のリソースの仕組みとは別で、atproto用であると示すフラグのようなもの。\n\n### リソース一覧\n\n[現時点でマージ済](https://github.com/bluesky-social/atproto/tree/1899b1fc16bc5cd7bb930ec697898766c3a05add/packages/oauth/oauth-scopes/src/resources)のもののみ示す。\n\n子アイテムはリソースが持つパラメータ。定義と同じ順序なので、先頭のものが名前を省略できる。\n\n* repo: record操作\n    * collection: 対象collectionのNSID\n    * action: create, update, delete\n* rpc: PDS外XRPC実行(プロキシ&トークン)\n    * lxm: 対象APIのNSID\n    * aud: 対象サービスのID([atproto-proxy](https://atproto.com/ja/specs/xrpc#service-proxying)と同じ形式)\n* blob: blobアップロード\n    * accept: MIMEタイプ\n* identity: ID情報更新(PLCサーバーへの操作)\n    * attr: handle, *(did:plc操作全般)\n* account: アカウント情報全般(PDSへの操作)\n    * attr: email(アドレス取得・設定), repo(import), status(activate)\n    * action: read, manage\n\n`identity`と`account`はまだ不安定そう。特に`status`は未実装。\n\npermission setに関してはproposalでは`include:〜`という形のスコープ構文が使われていたが、結局NSID単体になりそう?\n\n具体的にPDSのどこで使われているかは[`permissions`でコード検索](https://github.com/search?q=repo%3Abluesky-social%2Fatproto+permissions+NOT+path%3A%2F%5Epackages%5C%2Foauth%5C%2F%2F&type=code)すれば大体分かる。\n\n現在使われている`transition:generic`等も`transition`リソースと解釈することができる。内部では実際そんな感じで処理され、対応するリソース群にマップされる。\n\n### ユースケース別要求例\n\n#### Blueskyクライアント\n\n実用上は[#4108](https://github.com/bluesky-social/atproto/pull/4108)(Permission set)を待つべき。\n\nごく簡単なBlueskyクライアントなら、例えば以下のようになる。文法を示すため、意図的に不揃いな書き方をした。\\\nちゃんとやるなら`repo`は全然足りないし、`rpc`も`uploadVideo`やDM周りはケアできていない。\n\n```\natproto\nrepo:app.bsky.feed.post?action=create\nrepo:app.bsky.feed.post?action=delete\nrepo:app.bsky.feed.like?action=create&action=delete\nrepo?collection=app.bsky.actor.profile\nrpc:*?aud=did:web:api.bsky.app%23bsky_appview\nrpc:app.bsky.feed.getFeedSkeleton?lxm=com.atproto.moderation.createReport&aud=*\nblob?accept=*/*\nidentity:handle\n```\n\n#### PDS引越し(転入)\n\n```\natproto\naccount:repo?action=manage\naccount:status?action=manage\nidentity:*\nblob:*/*\nrpc:app.bsky.actor.putPreferences?aud=did:web:api.bsky.app%23bsky_appview\n```\n\n`putPreferences`(および`getPreferences`)はBluesky実装ではPDSが行うが、api.bsky.app宛の`rpc`が必要になる。\\\nこれは、内部処理的には[`PDS_BSKY_APP_VIEW_DID`](https://github.com/bluesky-social/atproto/blob/649e5ad7726ec369fced3700b82c96931090fe3c/packages/pds/src/config/env.ts#L104)宛のリクエストを横取りしている扱い[^pref]のため。\n\n[^pref]: 明確にそういう扱いになったのは[OAuth実装が入ってから](https://github.com/bluesky-social/atproto/blame/649e5ad7726ec369fced3700b82c96931090fe3c/packages/pds/src/api/app/bsky/actor/putPreferences.ts#L29-L32)。これまでは宛先は気にせずPDSで処理していたのだが、一貫性のためにこうなったと思われる。副作用として、昔は`putPreferences`に対する`atproto-proxy`は無効だったが、最近は使えるらしい。",
  "createdAt": "2025-08-19T01:59:51.536Z",
  "visibility": "url"
}