OAuth 2.0とは
OAuth 2.0は、ユーザーのパスワードを外部アプリに渡さず、特定のデータや機能へのアクセスを許可するための標準規格です。
例えば、自作のWebアプリからGoogleカレンダーの予定を取得する場合を考えます。
OAuth 2.0を利用しない従来の方式では、自作アプリにGoogleアカウントのIDとパスワードを渡してアクセスする方法がありました。
この方式には、パスワードの漏洩リスクや、外部アプリに必要以上の権限を与えてしまう問題があります。
OAuth 2.0では、パスワードの代わりにアクセストークンを使用することで、許可された範囲のAPIにアクセスできるようにします。
具体的には、次の流れです。
- WebアプリがGoogleカレンダーへのアクセス許可を要求する
- ユーザーがGoogleの画面で許可する
- Googleがアクセストークンを発行する
- Webアプリがアクセストークンを使ってAPIにアクセスする
この仕組みは、RFC 6749で標準化されています。
OpenID Connect(OIDC)とは
OpenID Connect(OIDC)は、OAuth 2.0を拡張し、ユーザー認証の仕組みを追加した標準規格です。
GoogleやMicrosoftが独自に開発したサービスではなく、OpenID Foundationが策定した共通の規格です。
GoogleやMicrosoftなどのサービス提供者は、この規格に準拠した認証機能を提供しています。
OAuth 2.0はアクセス権限の付与を目的としており、アプリにログインしたユーザーが誰であるかを証明する仕組みではありません。
OIDCでは、OAuth 2.0の仕組みを利用しながら、認証結果を含むIDトークンを発行します。
例えば、「Googleでログイン」という機能では、OIDCを使ってGoogleが認証したユーザーを識別できます。
| 規格 | 主な目的 |
|---|---|
| OAuth 2.0 | アクセス権限の付与(認可) |
| OpenID Connect | ユーザーの本人確認(認証) |
OIDCはOAuth 2.0を置き換えるものではなく、その仕組みの上に構築されています。
認証と認可の違い
OAuth 2.0とOIDCを理解するには、認証と認可の違いが重要です。
認証(Authentication)
ユーザーが誰なのかを確認することです。
例えば、Googleアカウントでログインし、ユーザーが本人であることを確認する処理が該当します。
認可(Authorization)
ユーザーやアプリに対して、何を許可するかを決定することです。
例えば、外部アプリにGoogleカレンダーの予定の読み取りを許可する処理が該当します。
以下の図は、両者の役割を比較したものです。
OAuth 2.0は認可の規格、OIDCは認証の規格という違いがあります。
OAuth 2.0とOIDCで使用する3種類のトークン
OAuth 2.0とOIDCでは、主に3種類のトークンが登場します。
| トークン | 目的 | 利用先 |
|---|---|---|
| アクセストークン | APIへのアクセス | APIサーバー |
| IDトークン | 認証結果の確認 | アプリ |
| リフレッシュトークン | アクセストークンの再取得 | 認可サーバー |
アクセストークン
アクセストークンは、APIへアクセスするための情報です。
例えば、Google Calendar APIにアクセスする際、HTTPリクエストのAuthorizationヘッダーに指定します。
GET /calendar/v3/users/me/calendarList HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer ACCESS_TOKEN
APIサーバーはアクセストークンを確認し、許可された範囲の処理を実行します。
IDトークン
IDトークンは、OIDCで追加された認証情報を含むトークンです。
通常はJWT(JSON Web Token)形式で発行されます。
デコード後の内容は、例えば次のようになります。
{
"iss": "https://accounts.google.com",
"sub": "123456789",
"aud": "my-app-client-id",
"exp": 1793000000,
"iat": 1792996400
}
アプリは署名や各項目を検証することで、認証されたユーザーを識別します。
リフレッシュトークン
リフレッシュトークンは、アクセストークンを再取得するためのトークンです。
アクセストークンには有効期限が設定されることが一般的です。
期限切れになった場合でも、有効なリフレッシュトークンがあれば、ユーザーに再度アクセス許可を求めずにアクセストークンを取得できます。
ただし、リフレッシュトークンは必ず発行されるわけではありません。
認可コードフローの仕組み
認可コードフロー(Authorization Code Flow)は、OAuth 2.0およびOIDCで利用される代表的な方式です。
一時的な認可コードを取得し、そのコードをトークンと交換します。
Googleログインを例に、ブラウザ、Webアプリのサーバー、Google認可サーバーの関係を確認します。
認可リクエスト
WebアプリはブラウザをGoogleの認可エンドポイントへ移動させます。
https://accounts.google.com/o/oauth2/v2/auth
?response_type=code
&client_id=APP_CLIENT_ID
&redirect_uri=https://app.example.com/callback
&scope=openid%20email%20profile
&state=RANDOM_VALUE
&code_challenge=CHALLENGE_VALUE
&code_challenge_method=S256
主なパラメータは次のとおりです。
| パラメータ | 意味 |
|---|---|
response_type=code | 認可コードを要求 |
client_id | アプリの識別子 |
redirect_uri | 認可後の戻り先 |
scope | 要求する権限や認証範囲 |
state | リクエストとレスポンスの対応確認 |
code_challenge | PKCEで使用する検証値 |
PKCEは、認可コードが第三者に盗まれた場合の不正利用を防ぐ仕組みです。
認可コードの取得
ユーザーの認証後、Googleはブラウザを指定されたURLへリダイレクトします。
https://app.example.com/callback
?code=AUTHORIZATION_CODE
&state=RANDOM_VALUE
アプリはstateを照合してから、取得した認可コードを使用します。
トークンの取得
アプリのサーバーからGoogleのトークンエンドポイントにリクエストします。
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=https://app.example.com/callback
&client_id=APP_CLIENT_ID
&client_secret=APP_CLIENT_SECRET
&code_verifier=ORIGINAL_VERIFIER
この例は、クライアントシークレットを使用するサーバー側アプリを想定しています。
Googleからのレスポンス例です。
{
"access_token": "ACCESS_TOKEN",
"id_token": "ID_TOKEN",
"token_type": "Bearer",
"expires_in": 3600
}
アプリはIDトークンを検証し、ユーザーのログイン処理を行います。
scopeにopenidを指定すると何が変わるのか
scopeは、要求するアクセス権限や認証情報の範囲を指定するパラメータです。
例えば、Googleカレンダーの読み取り権限を要求する場合です。
scope=https://www.googleapis.com/auth/calendar.readonly
一方、OIDCを利用する場合はopenidを指定します。
scope=openid email profile
それぞれの意味は次のとおりです。
| scope | 意味 |
|---|---|
openid | OIDCによる認証を要求 |
email | メールアドレス情報を要求 |
profile | プロフィール情報を要求 |
openidが含まれることで、OIDCの認証リクエストとして扱われます。
認可コードフローでは、トークン取得時にIDトークンも発行されます。
IDトークンの中身と検証方法
IDトークンは通常JWT形式で、ヘッダー、ペイロード、署名の3部分で構成されます。
HEADER.PAYLOAD.SIGNATURE
ペイロードには、認証結果に関する情報が含まれます。
{
"iss": "https://accounts.google.com",
"sub": "123456789",
"aud": "my-app-client-id",
"exp": 1793000000,
"iat": 1792996400
}
主なクレーム
クレームとは、トークンに含まれる個々の情報です。
| クレーム | 意味 |
|---|---|
iss | トークンの発行者 |
sub | ユーザーを識別するID |
aud | トークンの発行対象 |
exp | 有効期限 |
iat | 発行日時 |
nonce | 認証リクエストとの対応を確認する値 |
アプリ側で必要な検証
IDトークンを受け取っただけでは、安全にログインできません。
少なくとも次の項目を適切に検証する必要があります。
- 電子署名が正しいこと
issが信頼する発行者であることaudに自分のClient IDが含まれることexpによる有効期限が切れていないことnonceを送信した場合、その値が一致すること
また、subはユーザー識別子として利用できますが、異なる発行者間で同じ値が使われる可能性があります。複数の認証プロバイダーに対応する場合は、issとsubの組み合わせで識別することが重要です。
GoogleとMicrosoftでOAuth 2.0・OIDCに違いはあるのか
GoogleとMicrosoftは、どちらもOAuth 2.0とOIDCをサポートしています。
基本的な認可コードフローやIDトークンの形式は共通ですが、APIのURLや利用できるscopeなどが異なります。
| 項目 | Microsoft | |
|---|---|---|
| 認可の規格 | OAuth 2.0 | OAuth 2.0 |
| 認証の規格 | OIDC | OIDC |
| 主なAPI | Google APIs | Microsoft Graph |
| 認可エンドポイント | /o/oauth2/v2/auth | /oauth2/v2.0/authorize |
Googleの認可エンドポイントは次のとおりです。
https://accounts.google.com/o/oauth2/v2/auth
Microsoftでは、例えば次のURLを使用します。
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
Microsoftでは、テナントの指定によって認証対象のアカウントを制御できます。
実装する際は、各サービスのエンドポイント、Client ID、scope、IDトークンの発行者などを設定する必要があります。
Gmail APIとMicrosoft Graph APIのnpmライブラリ
OpenID Connectという名前の由来
OIDCは、以前の認証規格であるOpenID 2.0の後継にあたる規格です。
| 規格 | 登場年 | 主な目的 |
|---|---|---|
| OpenID 2.0 | 2007年 | ユーザー認証 |
| OAuth 2.0 | 2012年 | アクセス権限の付与 |
| OpenID Connect | 2014年 | OAuth 2.0を利用した認証 |
OpenID Connectは、OpenID 2.0の単純なバージョンアップではありません。
OAuth 2.0を基盤として、ユーザー認証の仕組みを新たに標準化したものです。
OAuth 2.0だけでログイン機能を作るべきではない理由
OAuth 2.0はアクセス権限の付与を目的としているため、アクセストークンを取得しただけでは、ユーザーの認証結果を安全に確認できません。
例えば、次のアクセストークンを受け取ったとします。
{
"access_token": "ACCESS_TOKEN"
}
アクセストークンだけをログインの証明として扱うと、別のアプリ向けに発行されたトークンを誤って受け入れるなどの問題が発生する可能性があります。
OIDCではIDトークンを利用し、認証されたユーザーとトークンの発行対象を確認できます。
{
"iss": "https://accounts.google.com",
"sub": "123456789",
"aud": "my-app-client-id"
}
このIDトークンについて署名や各クレームを検証することで、標準化された方法でユーザー認証を行えます。
OAuth 2.0だけでも独自の認証処理を実装することは技術的に可能ですが、認証方式を独自に設計する必要があります。
Googleログインなどの機能を実装する場合は、OAuth 2.0を基盤としたOIDCを利用するのが適切です。