Claude App Attestとは — iOS/macOSアプリがキーなしでAPIを呼ぶ仕組み
Claude App Attestは、Appleのapp attest(アプリ証明)でiOS/macOSアプリの正当性を確かめ、APIキーなしでClaude APIを呼ばせる仕組みです。1時間だけ有効なトークンを発行します。
Claude App Attestとは何か — APIキーを配らずにアプリを認証する仕組み
App Attest(アプリ証明)は、AppleがDeviceCheckで提供するAPIです。アプリが改ざんされていない正規ビルドであることを、端末のハードウェア鍵で証明します。Claude App Attestはこの証明を認証に使い、iOS/macOSアプリが端末から直接Claude APIを呼べるようにします。そのうえでAnthropicが端末に短命のアクセストークンを発行し、利用料はデベロッパーのワークスペースに課金されます。
一番の違いは「アプリに秘密を持たせない」点です。sk-ant-...形式のAPIキーをアプリに入れて配ると、配布物から取り出されて不正利用される恐れがあります。App Attestはキーそのものを配らず、プロキシサーバーも要りません。使えるのはClaude APIを直接呼ぶ場合だけで、Amazon Bedrock・Google Cloud・Microsoft Foundry経由では使えません。
導入はSwift Package Managerで行います。Package.swiftには次の1行を加えます。
.package(url: "https://github.com/anthropics/ClaudeForFoundationModels.git", from: "0.1.0")XcodeからならFile > Add Package Dependenciesでも追加できます。開発中はClaude Consoleで発行したAPIキーを使い、出荷前にApp Attestかプロキシに切り替える流れです。
自分のアプリはどの認証方式で作るか — 3つの選択肢
Claude for Foundation Modelsは、認証方式をauth:パラメーターで切り替えます。選べるのは.apiKey / .proxied / .appAttestの3つです。
3つの認証モードの違い
.apiKey(開発用)
実装は最も簡単です。ただしアプリに入れたキーは出荷バイナリから取り出せ、取り出した人の利用分があなたのアカウントに課金されます。開発中の反復に使い、リリース前に切り替えます。
.proxied(自前の中継)
自前のバックエンドが標準のMessages APIリクエストを受け取り、
x-api-keyヘッダーを付けてhttps://api.anthropic.comへ転送します。アプリ側はbaseURLに自前の中継先を渡します。端末にキーは残りませんが、サーバーの構築と運用は自分で持ちます。アプリが渡すヘッダーは毎回のリクエストに付くので、プロキシ側が呼び出し元を認可する材料にできます。ヘッダーが要らない中継先なら、空の辞書
[:]を渡します。.appAttest(バックエンド不要)
キーもプロキシも持たずに出荷できます。呼び出し先はClaude APIの直接呼び出しに限られ、動作には物理デバイスが必要です。
App Attestの設定は、クライアントIDを渡す1行です。
ClaudeLanguageModel(
name: .sonnet5,
auth: .appAttest(clientID: "clid_...")
)モデルIDの指定・タイムアウト・努力レベルなど、パッケージ側の設定はApple Foundation Modelsの実装ガイドにまとまっています。
Simulatorで開発するあいだは.apiKey、実機で動かすときは.appAttestと使い分けます。App Attestを選ぶとプロキシがなくなるので、プロキシで呼び出し元を認可する手は使えなくなります。ここが分かれ目で、後述の切り分けで詳しく扱います。
App Attestは内部でどう動くか — チャレンジからトークン発行まで
アプリが端末で初めてClaudeを呼ぶとき、内部では次の順で処理が進みます。
トークンが発行されるまで
- 1
チャレンジを要求する
アプリがAnthropicに、チャレンジを求めます。
- 2
端末を証明する
Appleの
DCAppAttestServiceで、その端末のアプリを証明します。 - 3
トークンと交換する
証明結果をAnthropicに送ると、検証済みの短命アクセストークンが返ります。
この流れはClaude for Foundation Modelsパッケージが自動で実行し、期限が切れると新しいトークンも取りに行きます。チャレンジ応答のコードを自分で書く必要はありません。
発行されるトークンの制約
有効期間
1時間
発行から1時間で失効
認可範囲
Messages APIのみ
ワークスペースにスコープが固定される
登録できるバンドルID
最大32個
1つのintegrationあたり
見落としやすいのは、トークンがエンドユーザーの身元を運ばない点です。証明されるのは「登録したアプリの正規インストールである」ことだけで、「誰が使っているか」は含まれません。無料枠の回数制限や課金上限のような利用者単位の判定は、トークンには載せられず、アプリ側で別にユーザー識別を持つ必要があります。
パッケージはAppleのプロトコルで表せない機能を公開していません。プロンプトキャッシュの制御・停止シーケンス・Batch処理・Files API・トークンカウント・ベータヘッダーが該当します。プロンプトキャッシュはパッケージが自動で適用します。
Appleの側では何が行われているか — 開発者に残る条件
Claude App Attestの内部で使われるDCAppAttestServiceは、Appleが一般のアプリ開発者向けに公開しているDeviceCheckフレームワークのクラスです。AppleのドキュメントはApp Attestを、アプリのロジックでは自分自身の安全性を確かめられない、という前提から説明しています。改ざんされたアプリは検査結果を偽れるため、ハードウェアに結び付いた暗号鍵で「正規のインスタンスだ」と第三者に示す設計です。
Claude App Attestでは、分担がはっきりしています。鍵の生成と証明は、Claude for Foundation Modelsパッケージが行います。attestation(Appleによる鍵の出自の証明)はAnthropicに送られ、アクセストークンと交換されます。開発者が書くattestationのコードも、attestationを検証するサーバーもありません。
Appleの説明では、アプリ側の処理は鍵の生成(generateKey)・鍵の証明(attestKey)・リクエストへの署名(generateAssertion)の3段階です。鍵の秘密鍵部分は端末のSecure Enclaveに保存され、どのプロセスからも直接は読み出せず、変更もできません。attestationにはサーバーが出した一度きりのチャレンジのハッシュが使われ、再送攻撃を防ぎます。
以降は、この仕組みを使うアプリの開発者に効くApple側の条件です。
対応する端末とOS
AppleのAPIリファレンスが挙げる提供開始のOSは次のとおりです。iOS・iPadOS・Mac Catalystが14.0、macOSが11.0、tvOSが15.0、visionOSが1.0、watchOSが9.0。Claude App Attestを使うパッケージ側の動作環境(OS 27)とは別の層の条件で、Apple側のAPIはそれよりずっと前から提供されています。
端末が対応しているかはisSupportedで判定します。Appleは、Macで動くアプリではisSupportedの値がfalseになると説明しています。Mac Catalystアプリと、Apple silicon上で動くiOS・iPadOSアプリも含まれます。一方、Anthropicのページの題名は「iOSとmacOSアプリ向けのApp Attest」で、対象にmacOSを挙げています。Appleのリファレンス同士でも、提供開始OSの一覧にmacOS 11.0があり、isSupportedの説明ではMacはfalseという形で、読み方が分かれます。macOSでの動作は、実機での検証を前提にしておくのが安全です。
非対応の端末では処理を飛ばします。Appleは、その場合はアプリだけでなくサーバー側の挙動も変え、assertionを必須にしないよう求めています。App Attestを使うアプリには、Apple Developerのサイトに登録したApp IDも必要です。App Clipで作った鍵は、対応するフルアプリでも使えるよう共有コンテナに識別子を置きます。
アプリ拡張機能は大半が対象外です。generateKeyは、isSupportedの値にかかわらず拡張機能から呼ぶと失敗します。対象となる拡張機能の範囲は、Appleのページで書き方が違います。Appleの説明記事は「Action・extensible SSO・watchOSの拡張機能」を挙げます。isSupportedのリファレンスは「watchOS 9以降のwatchOS拡張機能だけ」です。
鍵の寿命と数
鍵は通常のアプリ更新では有効なままですが、アプリの再インストール・端末の移行・バックアップからの復元では失われます。その場合は最初からやり直して新しい鍵を作ります。Claude App Attestでは、この再証明もパッケージが処理します。
Appleは、同じ端末でも別のユーザーが鍵を使い回すと不正の検知が難しくなるとして、ユーザーアカウントごと・端末ごとに別の鍵を作るよう説明しています。鍵の数が少ないほど不正の兆候を見つけやすいため、新しい鍵の生成は上のような場面とユーザー追加に絞るのが望ましいとされています。attestKeyがserverUnavailableエラーを返したときは、時間をおいて同じ鍵でやり直せます。
自前のサーバーで使う場合
attestationを自前のサーバーで検証する場合の手順は、Appleが別のドキュメントで説明しています。attestationオブジェクトはCBOR形式で、証明書チェーン・認証データ・レシートを含み、サーバーはこれらを検証して公開鍵をユーザーと端末に結び付けます。その後はassertionの署名とカウンターを検証し、集計値のリスクメトリックで端末改造による不正の兆候も調べられます。Claude App Attestではこれらを開発者が実装する場面はありません。
他の認証方式とどう切り分けるか
Claude APIの認証方式は3つあり、比較表では想定用途が分かれています。
| 認証方式 | クレデンシャル | 想定用途 |
|---|---|---|
| APIキー | クレデンシャルsk-ant-api...形式の静的シークレット | 想定用途ローカル開発・プロトタイピング・スクリプト、シークレットを自分で管理できるサーバー |
| Workload Identity Federation | クレデンシャルIdPのIDトークンから交換する短命トークン | 想定用途AWS・Google Cloud・Azure上の本番ワークロード、CI/CD、Kubernetesなど静的シークレットを排したい構成 |
| App Attest | クレデンシャル登録アプリの正規インストールに発行される短命トークン | 想定用途エンドユーザーに配布するiOS/macOSアプリで、バックエンドもプロキシも持たずに直接呼ぶ場合 |
APIキーとWorkload Identity Federationは、Claude APIのエンドポイントに対して同じアクセス権を持ちます。両者の違いはシークレットの管理を誰が担うかです。
自分の状況に当てはめるなら、次の見立てになります。
- サーバー側のワークロードがすでにクラウドのIDを持っている: そちらはWorkload Identity Federationが受け皿になる
- 同じチームがモバイルアプリも配る: モバイル側だけApp Attestにして、サーバー側とは方式を分ける
- 自分だけが使うツールで、キーの保管を自分で担保できる: APIキーのままで足りる
- アプリ内でユーザーごとの回数制限を厳密に効かせたい: トークンはユーザーを運ばないので、アプリ側の識別か自前プロキシが要る
各方式の全体像はClaude APIの認証方式まとめにあります。
導入に必要な条件と設定手順
App Attestには物理デバイスが必須です。Simulatorと、Secure Enclaveを持たないハードウェアでは証明が実行できません。 設定には、Apple Developer Team IDと、組織のadmin・owner・primary ownerのいずれかのロールが要ります。
設定の4ステップ
- 1
Xcodeでケーパビリティを追加する
アプリのターゲットの「Signing & Capabilities」で、App Attestケーパビリティを追加します。
- 2
App integrationsを開く
Claude Consoleで、対象ワークスペースの設定から「App integrations」を開きます。
- 3
integrationを作る
「Create app integration」を押し、名前・Apple Developer Team ID・バンドルIDを入力します。バンドルIDは複数登録できます。
- 4
クライアントIDを渡す
integrationの「Overview」タブからクライアントID(
clid_...)をコピーし、アプリのClaude設定に渡します。
利用料は標準のAPI料金で課金されるため、組織に利用可能なクレジット残高か有効な支払い方法が必要です。Appleはリクエストの経路に入らず、プロンプトも応答も見ません。リクエストはアプリからClaude APIへ直接届きます。
実装で押さえるエラー処理
パッケージはClaude APIのエラーをAppleのLanguageModelErrorに対応づけます。コンテキストウィンドウの超過は.contextSizeExceeded、HTTP 429は.rateLimited、タイムアウトは.timeoutです。対応するものがないエラーはClaudeErrorとして出ます。
do {
let response = try await session.respond(to: prompt)
print(response.content)
} catch ClaudeError.missingCredential {
// 認証情報が未設定
} catch let error as LanguageModelError {
// レート制限・コンテキスト超過など
} catch {
// 通信エラー
}.rateLimitedを拾ったときの対処は、その回だけSystemLanguageModelに切り替える、リクエストをキューに積む、再試行を促す表示を出す、のいずれかが一般的です。
オンデバイスモデルは高速でプライベート、オフラインでも使えますが、軽量なタスク向けの大きさです。大きなコンテキストや高度な推論、Web検索やコード実行のようなサーバー側ツールが要る場面でClaudeに任せる、という分担になります。どちらも同じLanguageModelSessionのAPIなので、切り替えはmodel:引数の差し替えで済みます。
侵害・退役したアプリはどう止めるか
登録したアプリが侵害された、あるいは役目を終えたときは、integrationごと失効させます。Claude Consoleのワークスペース設定で「App integrations」を開き、対象を選んで「Revoke」を押し、確定する手順です。
失効させると、そのintegrationが発行済みのトークンはすべて無効になり、登録済みの端末も新しいトークンを要求できなくなります。元に戻せません。同じアプリのアクセスを戻すには、新しいintegrationを作ります。その「Overview」タブのクライアントID(clid_...)を、アプリに渡し直します。
App Attestで作れないもの — 対応面の限界
対象のアプリはiOSとmacOSです。パッケージ自体はvisionOSとwatchOSの27も動作環境に挙げますが、App Attestの説明が対象とするのはiOSとmacOSのアプリです。ただしAppleは、Macで動くアプリではisSupportedがfalseになると説明しているため、macOSでの動作は実機で確かめる前提になります。
Bedrockなどを使う既存アプリをApp Attestへ移すには、呼び出し先をClaude APIの直接呼び出しに変えます。
サーバー側の処理は、端末の証明という前提がそもそも成り立たないため、静的シークレットを避けたければWorkload Identity Federationの領分になります。
まとめ
Simulatorでの開発は.apiKey、実機の検証から.appAttestに切り替えます。切り替え後はプロキシで利用者を認可する手段が消えるので、回数制限などはアプリ側で持つ前提になります。
失効はintegration単位で、元に戻せません。1つのintegrationには最大32個のバンドルIDを登録できるため、アプリをまとめて載せるほど、1本の侵害が及ぶ範囲も広がります。