Access Token—クライアントアプリケーションが保護されたAPIリソースにアクセスするためにサーバーに提示する認証情報です。ユーザー認証後、認可サーバーがaccess tokenを発行し、クライアントは各リクエストとともにHTTPヘッダーAuthorizationで送信します。OAuth.net、2025によると、access tokenはopaque string(意味を持たない任意の文字列)またはJWT(内部にデータを持つ自己完結型トークン)のいずれかであり、フォーマットの選択はシステムのアーキテクチャとパフォーマンス要件に依存します。
重要ポイント
Access Token—クライアント(モバイルアプリ、SPA、サーバー)が保護されたAPIエンドポイントへのHTTPリクエストを認証するために使用する文字列です。トークンは、ユーザーが自身の身元を確認し、アプリケーションに適切な権限(スコープ)を付与した後に、認可サーバーによって発行されます。
Access tokenはOAuth 2.0プロトコルと、その上に構築されたすべてのシステム(OpenID Connect、Firebase Authentication、Auth0、Keycloak)の中心的な要素です。Access tokenがなければ、保護されたAPIへのリクエストは処理されません。サーバーはHTTP 401 Unauthorizedを返します。トークンはユーザーを直接識別するのではなく、クライアントがユーザーに代わって特定のアクションを実行する権利を持っていること(認可)を確認します。ユーザーが誰であるか(認証)ではありません。
Okta、2025によると、公開APIの80%以上がAuthorizationヘッダーにaccess tokenを伴うBearerスキームを使用しており、時代遅れの認証方式(Basic AuthやAPI Key)に取って代わっています。Access tokenは委任認可の基盤でもあります。これは、ユーザーがアプリケーションに別のサービス上のデータへの限定アクセスを許可するモデルです。例えば、写真編集モバイルアプリがOAuth 2.0を介してGoogle Driveへのアクセスを要求すると、ユーザーは特定のスコープをリストした同意画面を表示し、確認後、それらの権限を持つaccess tokenを受け取ります。
仕組み access tokenはBearerスキームに基づいています。クライアントは各HTTPリクエストにAuthorization: Bearer <token>ヘッダーを追加します。リソースサーバー(API)はトークンを受け取り、検証し、アクセス可能なリソースを決定します。検証は2つの方法で行われます。ローカル(JWTの場合)またはイントロスペクションエンドポイント経由(opaqueトークンの場合)です。
Bearer tokenとは、トークンを提示する人(bearer)が誰でも対応するアクセス権を取得できることを意味します。これにより、転送中および保存中のトークン保護に高い要件が課せられます。Bearerスキームでは、クライアントがトークンの所有権を暗号学的に証明する必要はなく、単に送信するだけで十分です。したがって、HTTPSは必須です。トラフィック暗号化なしでは、攻撃者がトークンを傍受して即座に使用できます。
Cloudflare、2025によると、安全でないHTTP接続を介したBearer tokenの傍受は、リクエスト送信後平均12秒以内に発生します。HTTPSと短いaccess token TTL(15~30分)を使用することで、リスクはほぼゼロになります。アプリケーションレベルの追加保護として、OAuth 2.0 Token Binding(RFC 8471)によるリクエスト送信元の検証があります。クライアントはトークンにバインドされたTLSキーの所有権を証明し、傍受によるトークン盗難を無意味にします。
Access TokenにはopaqueとJWT(自己完結型)の2つの形式があります。これらの選択は、認証システムを設計する際の主要なアーキテクチャ上の判断の1つです。
| パラメータ | Opaque Token | JWT |
|---|---|---|
| 形式 | ランダム文字列(32~64バイト) | 署名付きBase64エンコードJSON |
| 検証 | イントロスペクションエンドポイント経由(HTTPリクエスト) | ローカル(暗号署名) |
| データを含む | いいえ—識別子のみ | はい—トークン内のクレーム |
| 失効 | 即時—サーバー側の検証 | ブラックリストまたは短いTTL経由 |
| パフォーマンス | 各リクエスト→イントロスペクション(RTT) | ローカル検証(RTTなし) |
| サイズ | ~100バイト | ~500~2000バイト |
Opaque tokenは、即時のアクセス失効と集中権限検証が必要なシステムに適しています。JWTは、パフォーマンスとネットワークコールの最小化が重要なマイクロサービスアーキテクチャ向けです。多くのプロバイダー(Auth0、Keycloak)は両方の形式をサポートし、クライアントごとにトークンタイプを設定できます。OpaqueとJWTの選択は、制御とパフォーマンスのトレードオフです。opaqueはサーバーに完全な制御を与え、JWTは最小限のレイテンシを提供します。
ライフサイクル access tokenは4つのフェーズで構成されます。発行、転送、使用、有効期限です。各フェーズには独自のセキュリティ要件とプロトコル制約があります。
Access Tokenの有効期間は限られており、通常15~60分です。expires_in値は、トークン発行時に認可サーバーの応答で示されます。この時間が経過すると、トークンは無効になり、クライアントはrefresh tokenメカニズムを通じて新しいトークンを取得する必要があります。クライアントは2つの方法で有効期限を確認できます。JWTのexpフィールド(ローカル)またはHTTP 401応答(opaqueトークンの場合)です。
Auth0 Best Practices、2025によると、モバイルアプリケーションに最適なaccess token TTLは15~30分です。TTLが短すぎる(5分未満)と、更新のたびにトークンエンドポイントに過剰な負荷がかかります。10,000ユーザーでTTLが5分の場合、ピーク時にはサーバーは毎分最大2,000の更新リクエストを受信します。TTLが長すぎる(2時間以上)と、トークン漏洩時の攻撃ウィンドウが拡大し、攻撃者はアクセスが自動的にブロックされるまで数時間にわたって侵害されたトークンを使用できます。
セキュリティ access tokenのセキュリティは、デバイス上の保存時、ネットワーク上の転送時、サーバー上の処理時のすべての段階で確保されなければなりません。基本的な推奨事項は、他のアプリケーションやプロセスからアクセス可能な場所にaccess tokenを決して保存しないことです。
モバイルデバイスでは、access tokenは次のように保存されます。iOSでは、kSecAttrAccessibleAfterFirstUnlock属性を持つKeychain(バックグラウンド更新のために、デバイスがロックされていても、最初のロック解除後にトークンにアクセス可能)。Androidでは、EncryptedSharedPreferences。Access tokenは、NSUserDefaults、SharedPreferences、外部ストレージのファイル、アプリケーションログに決して保存してはいけません。転送時は、TLS 1.3または1.2を使用したHTTPSのみです。各APIリクエストでは、access tokenはAuthorization: Bearerヘッダーで送信されるべきであり、URLパラメータ(クエリ文字列)では送信すべきではありません。URLはサーバーやブラウザのログに残ります。
OWASP Mobile Top 10、2025によると、デバイス上の不適切なトークン保存(M1: Improper Platform Usage)と安全でないデータ転送(M3: Insecure Communication)は、アカウント侵害につながる最も一般的なモバイル脆弱性のトップ3に入っています。追加の対策として、access tokenを使用するすべてのリクエストに証明書ピンニングを使用します。クライアントは、標準のCAチェーンだけでなく、事前に保存された証明書フィンガープリント(SHA-256 fingerprint)を通じてサーバーの証明書を検証します。これにより、CAが侵害された場合でもman-in-the-middle攻撃を防ぎます。
以下は、Android向けKotlinの例で、Authorizationヘッダーにaccess tokenを含むリクエストの送信と、refresh tokenによる自動更新を伴う401ハンドリングを示しています。カスタムInterceptorを備えたOkHttpを使用しています。
data class TokenStore {
fun getAccessToken(): String? {
// Reading from EncryptedSharedPreferences
return encryptPrefs.getString("access_token", null)
}
fun isTokenExpired(): Boolean {
val expiresAt = encryptPrefs.getLong("expires_at", 0)
return System.currentTimeMillis() > expiresAt
}
}
class ApiClient(private val tokenStore: TokenStore) {
private val client = OkHttpClient.Builder()
.addInterceptor(AuthInterceptor(tokenStore))
.build()
fun fetchUserProfile(): UserProfile? {
val request = Request.Builder()
.url("https://api.example.com/user/profile")
.get()
.build()
val response = client.newCall(request).execute()
return if (response.isSuccessful) {
parseProfile(response.body?.string() ?: return null)
} else null
}
}
fun sendAuthenticatedRequest(token: String): Unit {
val conn = URL("https://api.example.com/data").openConnection() as HttpURLConnection
conn.setRequestProperty("Authorization", "Bearer $token")
conn.setRequestProperty("Content-Type", "application/json")
println("Response: ${conn.responseCode}")
}
この例では、2つのアプローチを示しています。自動トークン管理のためのOkHttp Interceptorの使用と、HttpURLConnectionを介した直接送信です。OkHttp Interceptorが推奨されます。これはトークンの追加と更新のロジックを集中化し、各リクエストでのコード重複を排除します。すべてのリクエストは単一のインターセプターを通過し、応答ステータスをチェックし、必要に応じて開発者の介入なしにトークンを更新します。
よくある質問
API keyは特定のユーザーに紐付かない静的なアプリケーション識別子です。Access tokenは動的で一時的であり、ユーザーとセッションに紐付きます。API keyはスコープ(権限制限)をサポートしませんが、access tokenは操作ごとに異なるアクセスレベルを持つことができます。
2つの方法があります。アクティブな方法—JWTのexpフィールドを確認(クライアントがトークンの期限切れを自ら計算)。パッシブな方法—リクエストを送信してHTTP 401 Unauthorizedを受け取る。両方を組み合わせることをお勧めします。データ損失を防ぐための事前のexpチェックと、フォールバックとしての401ハンドリングです。
いいえ。Access tokenをURLのクエリ文字列で渡してはいけません。URLパラメータはブラウザの履歴、サーバーログ、リファラー、プロキシサーバーのキャッシュに保存されます。唯一安全な方法はAuthorization: Bearerヘッダーです。これはOAuth 2.0 Security Best Practices(RFC 9700)の要件です。
15~30分をお勧めします。自動更新のためにローテーション付きのrefresh tokenが使用されます。このTTLはセキュリティとUXのバランスを取ります。ユーザーは更新に気づかず、漏洩したトークンに対する攻撃ウィンドウは最小限です。特に機密性の高い操作(送金など)の場合は1~5分です。
Bearer tokenは、トークンを提示する人(bearer)が誰でもアクセスを取得できるaccess tokenの一種です。所有権の暗号学的証明は不要で、トークンを送信するだけで十分です。Bearerスキームはシンプルで効果的ですが、転送中のトークン傍受から保護するためにHTTPSが必要です。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。