Shelfieにはログイン機能を実装しました。
認証にはGoogle、GitHubを用いた認証を実装したかったのでOAuth2について一から学習し、整理してみました。
本記事では
- OAuth2とは何か
- OAuth2を利用した認証フローの概要
- Clerkを利用した実装例
をまとめます。
OAuth2とは
OAuth2(Open Authorization 2.0の略とされる)はユーザーのパスワードを第三者アプリへ渡さずに、限定された権限を委譲するための仕組みです。
例えば、『Googleでログイン』はユーザーが外部アプリにGoogleのパスワードを渡しているのではなく
このアプリに〇〇までの権限を与えて良いか
をGoogleが確認し、許可された範囲だけのアクセスを認めるということをしています。
OAuth2に登場する主要な登場人物
- リソース所有者 (ユーザー本人)
- クライアント(権限を利用したいアプリケーション(Shelfieなど))
- 認可サーバー(Google)
- リソースサーバー(Google Drive APIなど)
OAuth2での重要な考え方
OAuth2の中心となっているのはパスワードではなく、トークンです。
例:
Access Token : abc123xyz...
アプリは毎回パスワードを送るのではなく、
GET /userinfo
Authorization: Bearer abc123xyz...
のように送信します。
このトークンには有効期限や許可された権限、発行元などの情報が含まれています。
また、OAuth2は今までの説明からも分かる通り認証そのものではありません。
OAuth2はユーザーがクライアントに対し、リソースサーバーへのアクセスを許可するための認可の仕組みです。
「この人は誰か?」を保証する認証を実現するにはその上にある仕組みを使う必要があります。
OAuth2を用いた認証処理の流れ
sequenceDiagram
participant U as ユーザー
participant C as 個人開発アプリ
participant A as Google認可サーバ
participant R as Google API
U->>C: Googleでログイン押下
C->>A: 認可要求
A->>U: ログイン画面表示
U->>A: ログイン・許可
A->>C: Authorization Code
C->>A: Authorization Code送信
A->>C: Access Token発行
C->>R: APIリクエスト
R->>C: ユーザー情報返却
1 ユーザーがログインを開始
ユーザーはアプリのログイン画面で
Googleでログイン
ボタンを押します。この時点ではまだ認証は行われていません。
アプリはGoogleに対して認可要求を行う準備をします。
2 認可サーバーへリダイレクト
アプリはGoogle認可サーバーへリダイレクトします。
リクエストには以下の情報が含まれます。 例:
client_id=xxxxx
redirect_uri=https://example.com/callback
scope=openid profile email
response_type=code
3 Google側で認証・認可確認
Googleはユーザーへログイン画面を表示します。
ユーザーはメールアドレス、パスワード、アクセス許可を入力します。
4 認可コードを取得
認証と認可が成功するとGoogleはアプリへ認可コードを返します。
例:
https://example.com/callback?code=abc123
認可コードは「引換券」のような役割をしており、以下のような特徴をもっています。
- 一時的
- 数分程度で期限切れになる
- API利用には使えない
5 認可コードとトークンを交換
アプリは取得した認可コードをGoogleへ送信します。
例:
POST /token
code=abc123
client_id=xxxxx
client_secret=xxxxx
Googleはコードを検証し、次のトークンを返します。
例:
{
"access_token":"eyxxxxx",
"id_token":"eyJhbGciOi...",
"expires_in":3600, "token_type":"Bearer"
}
- access_token : Google API利用用
- id_token : ログインしたユーザーの情報
6 ID Tokenでユーザーを識別
アプリはID Tokenを利用してログインユーザーを識別しセッションを作成します。
これで認証処理の完了です。
なぜ2種類のトークンがあるのか
OAuth2は前述の通り認可の仕組みです。access_tokenはまさに何ができるかの認可を扱っています。
id_tokenは認証を行うために「OIDC(OpenID Connect)」というOAuth2を拡張した仕組みを用いて追加しているのです。
Clerkを用いた実装例
今回の個人開発では認証基盤としてClerkを利用しました。
ただ、認証後のセッション管理はアプリ独自の仕組みを実装して組み合わせました。
以下は、実際の認証処理フローになります。
sequenceDiagram
participant U as ユーザー
participant App as フロントエンド
participant Clerk
participant B as バックエンド
participant G as Google
U->>App: Googleログイン押下
App->>Clerk: ログイン要求
Clerk->>G: OAuth/OIDC認証
G->>Clerk: 認証成功
Clerk->>App: ユーザー情報
App->>B: 認証済み情報送信
B->>B: 独自JWT生成
B->>App: Access Token
B->>App: Refresh Token
実装内容
認証画面はClerk標準UIをそのまま利用せず、アプリに合わせてカスタムUIを実装しました。
また、ログイン状態を維持するために、バックエンド側で独自に以下のトークンを発行するように実装しました。
- Access Token : APIアクセス時の認証用
- Refresh Token : 期限切れAccess Tokenの再発行用
Access Tokenは有効期限を短く設定しているため、期限切れになった場合はRefresh Tokenを利用して新しいAccess Tokenを取得します。
Tokenの独自実装
なぜ、せっかくClerkという認証基盤を利用しているにも関わらずTokenをバックエンドで独自発行したのかというと
ログイン状態の維持のためのセッション管理をバックエンドの責務にしたかったから
Clerkはセキュリティ向上のため、短命なセッショントークンを採用しています。
デフォルトではセッショントークン(JWT)は約60秒程度の有効期限となっており、期限が切れるたびに内部で自動更新される仕組みになっています。
この設計によって漏洩時のリスクは低減できますが、今回の個人開発では以下の方針を取りました。
- アプリケーションのログイン状態管理はバックエンドの責務にしたい
- API認可をバックエンド主体で管理したい
- トークン更新処理をアプリ独自で制御したい
そのため、Clerkで認証完了後にバックエンドへトークンを送信し、バックエンド側で独自のAccess Token / Refresh Tokenを発行する構成にしました。
最後に
今回の個人開発では本格的な認証基盤を実装してみました。(といってもSaaSに頼ってますが。。。)
その中でもOAuthについてちゃんと学習できたので概要、内部ロジックを理解することができました。
これを機にOAuthを用いた認証処理に繋がるOIDCについてもいつか学習してみたいと思います。
最後までご愛読ありがとうございました。

