Open15

認証・認可(auth)

kzk4043kzk4043

OIDC

https://zenn.dev/powersei45/articles/e02e966983ce86

OpenID Connect(OIDC)は、OAuth 2.0 をベースにした認証用の拡張仕様です。OAuth 2.0 が「認可」にフォーカスしているのに対して、OIDC は「認証」を扱うための仕組みを追加しています。
OAuth 2.0 を拡張し、ID Token という新たなトークンを導入してユーザー情報をやり取りできます。

# 自社サービスの個別ログインでOIDC実装を検討する際のガイド

## OIDCに則ることが意味がない場合(ほとんどのケース)

- 単一サービスのみ運営
- 他社との連携予定なし
- シンプルなユーザー管理で十分
- 開発リソースが限られている

**→ 通常のセッション管理やJWT実装で十分**

## OIDCに則ることが意味がある場合

### 1. 将来的に複数サービス展開予定
- 最初からOIDC準拠にしておけば、後でSSO化が楽
- 例:メインサービス → 管理画面 → APIポータル

### 2. B2B/エンタープライズ向け
- 大企業は「OIDC/SAML対応」を要求することが多い
- 顧客の既存認証システムとの連携が必須

### 3. 他社サービスとの相互連携
- 自社もIdentity Providerになる予定
- パートナー企業との認証連携

### 4. 高度なセキュリティ要件
- 金融、医療、政府系
- 監査でプロトコル準拠が求められる
kzk4043kzk4043
  1. Issuer (OpenID Provider, OP)
    1. ID Token を発行する認証サーバー側のサービス。Google や GitHub、Auth0 など。
  2. Relying Party (RP)
    1. OP から認証結果を受け取り、ログイン処理を行うクライアント(サービス提供側)。
  3. ID Token
    1. JWT(JSON Web Token)形式で、ユーザーを認証したことを示すトークン。sub(ユーザーを一意に識別するクレーム)や発行者情報 (iss) などが含まれる。
  4. UserInfo エンドポイント
    1. ユーザーのプロフィール情報を取得するためのエンドポイント。ID Token に含まれない追加情報などを取得するために使用。
kzk4043kzk4043

https://www.tohoho-web.com/ex/openid-connect.html

これが一番わかり易いかも。単語大事

エンティティ

  • User / End-User / User-Agent:サービスを利用する側。Webブラウザなど。
  • RP(Relying Party) / Client:サービスを提供する側。食べログなど。
  • OP(OpenID Provider) / IdP(Identity Provider):ユーザーのID/パスワードを管理して認証する側。

トークン

  • IDトークン(id_token):ユーザーを認証したことを示すトークン。JWT形式。
  • アクセストークン(access_token):OP が持つリソース(ユーザ情報など)にアクセスするためのトークン。
  • リフレッシュトークン(refresh_token):アクセストークンの有効期限切れをリフレッシュして延長するためのトークン。
kzk4043kzk4043

https://zenn.dev/sora1010/articles/8467860cb2b042

しかし、このシナリオでも、クライアントとAPIで構成されるアプリケーションのセキュリティは危険にさらされるかもしれません。実際、IDトークンをクライアントとAPIのチャネルに結びつける仕組みはありません。もし攻撃者があなたのIDトークンを盗むことに成功したら、彼らはそれを使って正規のクライアントのようにAPIを呼び出すことができる。
一方、アクセストークンについては、送信者制約と総称される一連のテクニックがあり、アクセストークンを特定の送信者に結びつけることができます。これにより、たとえ攻撃者がアクセストークンを盗んだとしても、トークンは最初に要求したクライアントにバインドされているので、それを使ってAPIにアクセスできないことが保証される。

kzk4043kzk4043

AIまとめ

ID TokenとAccess Tokenの違い:なぜAPIアクセスにID Tokenを使ってはいけないのか

ID TokenとAccess Tokenの基本的な違い

ID Token(身分証明書)

  • 目的: ユーザーが誰なのかを証明する(認証)
  • 形式: JWT(JSON Web Token)で、中身が読める
  • 含まれる情報:
    • sub: ユーザーの一意のID
    • name: ユーザーの名前
    • email: メールアドレス
    • iss: 誰が発行したか(例:Google)
    • exp: 有効期限
  • 使い道: ログイン時に「このユーザーは本人である」ことを確認する

Access Token(入館証)

  • 目的: リソースへのアクセス権限を証明する(認可)
  • 形式: 多くの場合、中身が読めないランダムな文字列
  • 含まれる情報: 実装によるが、通常は最小限の権限情報のみ
  • 使い道: APIを呼び出すときの「鍵」として使う

具体例で理解する

Googleアカウントでログインする場合:

  1. ID Tokenを受け取る

    「この人は田中太郎さん(tanaka@gmail.com)です」
    という証明書
    
  2. Access Tokenを受け取る

    「このトークンを持っている人は、
    Googleドライブの読み取り権限があります」
    という許可証
    

ID Tokenの「その後」の使い道

基本的には使い捨て

実は、ID Tokenはログイン時に一度使ったら、その後はほとんど使いません

// ログイン時
function handleLogin(idToken) {
  // 1. ID Tokenを検証
  const userInfo = verifyIdToken(idToken);
  
  // 2. 自分のアプリのセッションを作成
  session.create({
    userId: userInfo.sub,
    email: userInfo.email,
    name: userInfo.name
  });
  
  // 3. ID Tokenはもう不要!
  // Access Tokenは保存しておく(API呼び出し用)
  saveAccessToken(accessToken);
}

ID TokenをAPIアクセスに使ってはいけない理由

1. 設計思想の違い

項目 ID Token Access Token
目的 「誰であるか」を証明する一度きりの証明書 「何ができるか」を証明する継続的な許可証
受け取り側 あなたのアプリケーション(Relying Party) リソースサーバー(API)
検証者 あなたのアプリケーション自身 APIサーバー

2. セキュリティリスク

個人情報の露出

// ID Tokenの中身(誰でも読める)
{
  "sub": "1234567890",
  "name": "田中太郎",
  "email": "tanaka@example.com",
  "picture": "https://example.com/photo.jpg",
  "birthdate": "1990-01-01"
}

ID Tokenを何度もネットワーク上でやり取りすると:

  • 個人情報が漏洩するリスクが高まる
  • 中間者攻撃で情報を盗まれる可能性

3. 有効期限の問題

ID Token: 5分〜1時間(短い)
Access Token: 1時間〜24時間(長い)

→ ID Tokenはすぐ期限切れになってAPIが使えなくなる

4. 権限管理ができない

ID Tokenには「スコープ(権限)」の概念がありません:

// Access Tokenなら
{
  "scope": "read:posts write:posts delete:own_posts",
  "resource": "/api/posts"
}

// ID Tokenには権限情報がない
{
  "name": "田中太郎"  // 誰かは分かるが、何ができるかは不明
}

5. 実装上の問題

APIサーバー側の負担

// もしID TokenをAPIで使うと...
async function handleAPIRequest(idToken) {
  // 毎回これらの検証が必要
  // 1. JWT署名の検証(重い処理)
  // 2. 発行者(iss)の確認
  // 3. 対象(aud)の確認
  // 4. 有効期限の確認
  // 5. その上で権限チェックも別途必要
}

// Access Tokenなら
async function handleAPIRequest(accessToken) {
  // トークンストアで高速検証
  const permissions = await tokenStore.verify(accessToken);
  // 権限があればOK
}

6. 具体例で理解

❌ 悪い例:ID Tokenを使い回す

// Googleでログイン後
const idToken = "eyJhbGc..."; // 個人情報満載

// これを何度も送信...危険!
fetch('/api/posts', { headers: { 'Authorization': idToken }});
fetch('/api/comments', { headers: { 'Authorization': idToken }});
fetch('/api/profile', { headers: { 'Authorization': idToken }});

✅ 良い例:役割分担

// 1. ログイン時のみID Token使用
const userInfo = verifyIdToken(idToken); // 一度だけ!

// 2. API呼び出しはAccess Token
fetch('/api/posts', { 
  headers: { 'Authorization': `Bearer ${accessToken}` }
});

まとめ

ID TokenをAPIアクセスに使わない理由

  1. プライバシー:個人情報が含まれている
  2. セキュリティ:何度も送信するとリスク増大
  3. 有効期限:すぐ切れる
  4. 権限管理:スコープがない
  5. パフォーマンス:検証が重い
  6. 設計原則:そもそも用途が違う

覚え方

  • ID Token = パスポート(入国審査で一度見せるだけ)
  • Access Token = 入館証(施設内で何度も使う)

パスポートを毎回見せて歩き回るのは危険で非効率です!

重要な違い(まとめ表)

項目 ID Token Access Token
何を証明? 「誰であるか」 「何ができるか」
いつ使う? ログイン時 API呼び出し時
中身は見える? 見える(JWT) 通常見えない
有効期限 短い(数分〜1時間) やや長い(1時間〜)
個人情報 含まれる 含まれない
権限情報 なし あり(scope)
使用回数 一度だけ 何度でも
kzk4043kzk4043

SSO

Single Sign-On(SSO)は、一度のログインで複数のアプリケーションやサービスにアクセスできる認証システムです。

OIDC(OpenID Connect)は、OAuth 2.0の上に構築された認証レイヤーで、SSOを実現するための主要な技術の一つです。

kzk4043kzk4043

単語整理

  • 認証認可、ログイン
    • 個別ログイン
    • SSO
      • SAML
      • OAuth2.0(認可)
        • OIDC(認証を追加)

OIDC

  • トークン
    • id token
      • JWT
    • access token
      • JWTでも良い
    • refresh token

JWT

  • ヘッダ
  • ペイロード
  • 署名
    • 署名を検証することで改ざんを検知
    • 検証は公開鍵でできるからブラウザでもできる?
kzk4043kzk4043

memo

  • PKCE Code Verifier/Code Challenge/Stateパラメータ勉強
    • PKCE Code Verifier→FE生成
    • Code Challenge→verifierハッシュ化→これをaccess Tokenにくっつけて
    • 盗まれたときの検証
    • トークン交換とはなにか
    • PKCE情報・State削除していいのか
  • トークンの保存先はlocalStorage/sessionStorageどちらがいいのか
  • localStorage/sessionStorageの違い
  • refreshする条件