みなさんこんにちは!ワンキャリアで共通基盤チームの吉田(X:@yoshida_baystar)です。
ワンキャリアは、複数のサービスで使える共通会員ID「ワンキャリアID」を開発・運用しています。この記事では、その開発経験から学んだOAuth2.0とOpenID Connectについて、認証と認可の違いやセキュリティ対策を含めて解説します。
OAuth2.0とOpenID Connectとは
現在のWebサービスやアプリケーションにおいて、「Googleでログイン」や「Facebookと連携する」といった機能は当たり前になっています。この裏側では、OpenID Connectがログインを実現し、OAuth2.0がデータ連携の許可を管理しています。
つまり、OAuth2.0は「誰に、何を許可するか」を決める「認可(Authorization)」の仕組みであり、OpenID Connectはその上で「ユーザーが誰であるか」を証明する「認証(Authentication)」の仕組みです。
ここからは、認可と認証の違いについて詳しく説明していきます。
認可と認証の違い
OAuth2.0とOpenID Connectを理解する上で最も重要なのが、認可と認証の違いです。
認可とは、認証済みのユーザーに対して特定のリソースやアクションへのアクセス権限があるかどうかを確認する仕組みです。例えば、ユーザーAが他人の写真を編集する権限があるかどうか、といった判断を行います。
認証とは、ユーザーが本人であることを確認する仕組みです。一般的にはユーザー名とパスワードの組み合わせや、多要素認証などが用いられます。認証が成功すると、システムはそのユーザーが誰なのかを特定できます。
実際の業務ではこの2つが混同されることが多く、設計や実装に大きな影響を与えることもあります。よくある間違いとして、OAuth2.0を「認証の仕組み」として理解してしまうケースがあります。
しかし、OAuth2.0は本来「認可のためのフレームワーク」です。OAuth2.0だけでは「このユーザーは誰なのか」という認証情報を取得することはできません。 OAuth2.0だけでユーザー認証を行おうとすると、セキュリティ上の問題が発生する可能性があります。そこで登場するのがOpenID Connectです。
OAuth2.0の基本フロー
ここではOAuth2.0で最も一般的に使用されるAuthorization Code Flowについて、詳細な流れを見ていきましょう。

各ステップの詳細
1.ユーザーがアプリケーションにアクセス ユーザーがクライアントにログインを試みます。
2.認可サーバーへのリダイレクト クライアントはユーザーを認可サーバーにリダイレクトします。この際、主に以下のパラメータが含まれます。
-
response_type:【必須】 認可コードを要求することを示す。値は”code”でなければならない
-
client_id:【必須】 アプリケーションの識別子。認可サーバーがどのアプリからのリクエストかを識別する
-
state:【推奨】 CSRF攻撃対策用のランダムな文字列
3.ユーザー認証と認可 ユーザーが認可サーバーでログインし、クライアントアプリケーションに対する権限付与に同意します。
4.認可コードの発行 認可サーバーがワンタイムの認可コードを生成します。
5.認可コードの返却 認可サーバーがユーザーを指定されたredirect_uriにリダイレクトし、認可コードをパラメータとして渡します。
6.アクセストークンの要求 クライアントが認可コードを使って、認可サーバーに対してアクセストークンを要求します。この通信はバックエンド間で行われクライアント認証が必要です。
7.アクセストークンの発行 認可サーバーが認可コードを検証し、有効な場合はアクセストークン(とリフレッシュトークン)を発行します。
8.リソースへのアクセス クライアントがアクセストークンを使って、リソースサーバー(APIエンドポイント)からユーザーの情報やデータを取得します。
OAuth2.0の重要なポイント
上記のフローを理解した上で、OAuth2.0のより詳細な部分をいくつか深ぼっていきましょう。
① クライアントアプリケーションにID・パスワードを教える必要がない
OAuth2.0の最も重要なセキュリティ上のメリットは、サードパーティにリソースサーバーのID・パスワードを渡す必要がないという点です。
これによってID・パスワード入力によって発生する以下のようなリスクを防ぐことができます。
-
サードパーティ経由でのID・パスワードの漏洩
-
悪意あるサードパーティによるID・パスワードの悪用
-
パスワードを変更した際に、すべての連携アプリで再設定が必要になる
OAuth2.0では、ステップ3でユーザーが入力するID・パスワードは認可サーバーに対して行われます。サードパーティアプリケーションにはID・パスワードを入力する必要がありません。これにより、上記のようなセキュリティリスクを大幅に軽減できます。
② アクセストークンが権限委譲の証となる
OAuth2.0の仕組みの中心にあるのがアクセストークンです。ステップ4で権限委譲の同意が得られると、その証として認可サーバーはアクセストークンを発行し、ステップ7でクライアントアプリケーションに渡されます。
アクセストークンには以下のような情報が紐付けられています。
-
誰のリソースか(リソースオーナーの識別子)
-
どのアプリケーションに対して発行されたか(クライアントID)
-
どのような権限を持つか(scope)
-
有効期限(数分〜数時間)
リソースサーバーは、ステップ8で受け取ったアクセストークンを検証し、以下を確認します。
-
アクセストークンが有効か
-
要求されたリソースへのアクセス権限があるか
-
要求された操作が許可された範囲内か
これらの確認を通過してはじめて、リソースオーナーのリソースへのアクセスが許可されます。このように、権限委譲においてアクセストークンが中心的な役割を果たします。
③ OAuth2.0は「認可」であって「認証」ではない
ここまでの説明で、OAuth2.0が「認可のプロトコル」あるいは「権限委譲のプロトコル」と言われる意味がお分かりいただけたでしょうか。
重要なポイントは、OAuth2.0のフローには、クライアントアプリケーションへのログインの話や、クライアントアプリケーションが「ユーザーが誰であるかを認証する」といった話は含まれていないということです。
認可コードは必要なのか?
私がOAuth2.0を学習している上で最初に疑問を感じたのが「認可コードを挟まずアクセストークンを直接返す仕組みではダメなのか?」ということでした。実際Implicit Flowというフローでは、直接アクセストークンを返す仕組みが使われていました。しかし、2018年頃から非推奨となったようです。
mplicit Flowでは以下のようにアクセストークンを直接URLに含めてリダイレクトします。
https://client.example.com/callback
この方式はシンプルで扱いやすいように見えますが、直接アクセストークンが返されることにより以下のリスクが存在します。
これらの問題は、Authorization Code Flowの認可コードの仕組みによってリスク軽減ができます
-
クライアント認証を挟むことで、悪意のあるクライアントがアクセストークンを取得しにくい
-
認可コードは使い捨てかつ有効期限が短く設定されている
このように認可コードを経由する仕組みはやや複雑ですが、アクセストークンを保護するための役割を果たしているのです。そのためAuthorization Code Flowが一般的に使用されているようです。
OpenID Connectによる認証の拡張
OAuth2.0の上に認証レイヤーを追加したものがOpenID Connect(以下、OIDC)です。
OIDCを使うことで、ユーザーはIDプロバイダが提供するアカウントでサードパーティにログインすることができます。 例えば「Googleでログイン」機能を提供しているサービスは、OIDCを使用しています。
この仕組みでは、GoogleがIDプロバイダとしてユーザーの認証情報を提供し、サードパーティはGoogleから発行されるIDトークンを通じてユーザー情報を取得します。これにより、ユーザーは新しいアカウントを作成することなく既存のGoogleアカウントで様々なサービスにログインできるようになります。
フロー図で表現すると以下のような流れで認証を行います。

図を見比べても分かる通りいくつか違いがありますが、一番重要な違いはIDトークンの発行有無です。OIDCでは、OAuth2.0のフローにopenidスコープの追加と、IDトークンの発行という認証レイヤーの要素が加わります。IDトークンに含まれるユーザー識別子を取得し、厳密な検証をすることでログイン処理を行うことができます。
IDトークン
IDトークンはIDプロバイダからJSON Web Token(JWT)形式で発行されます。ユーザー認証のために使用され主に以下の情報が含まれます。
-
iss:トークンを発行した認可サーバー
-
sub: ユーザーの一意識別子
-
aud:トークンの受信者(クライアントID)
-
exp:トークンの有効期限
-
iat:トークンの発行時刻
このIDトークンにより、クライアントは「発行元に確認せず、このユーザーが誰なのか」を特定できるようになります。
セキュリティリスクを最小化する実装のポイント
OAuth2.0とOIDCを安全に実装するためには、いくつかの重要なセキュリティ対策を講じる必要があります。
① リフレッシュトークンローテーション
リフレッシュトークンはアクセストークンと異なり長期間有効なトークンです。そのためトークン漏洩時のセキュリティリスクがアクセストークンと比べて高く、攻撃者が継続的に新しいアクセストークンを取得し続ける恐れがあります。
このリスクを軽減するための手法がリフレッシュトークンローテーションです。リフレッシュトークンを使用してアクセストークンを更新する際に、新しいリフレッシュトークンも同時に発行します。
【フロー例】
-
クライアントが古いリフレッシュトークンでアクセストークン更新を要求
-
認可サーバーが新しいアクセストークンと新しいリフレッシュトークンを発行
-
古いリフレッシュトークンを無効化
-
次回更新時は新しいリフレッシュトークンを使用
このローテーション方式により、リフレッシュトークンが漏洩した場合でも、次回の正規利用時に不正利用を検出できます。
② PKCE(Proof Key for Code Exchange)
OAuthの脆弱性として悪意のあるアプリが認可コードを取得できてしまった場合、認可コードを使って不正にアクセストークンを取得できる恐れがあります。
PKCEはこういった「認可コード横取り攻撃」を防ぐための拡張仕様で、特にクライアントシークレットを安全に保管できないPublic Client(SPAやモバイルアプリケーション)でOAuthを使用する場合に必須の対策になります。
PKCEの仕組みは以下の通りです。
-
クライアントがランダムな文字列(code_verifier)を生成
-
code_verifierをSHA256でハッシュ化してBase64URLエンコード(code_challenge)
-
認可リクエスト時にcode_challengeを送信
-
トークン交換時にcode_verifierを送信して検証
これにより攻撃者が認可コードとcode_challengeを傍受しても、元のcode_verifierを逆算することは不可能です。そのため、攻撃者はトークンを取得できず本物のクライアントのみトークンを取得できます。
③ Redirect URIの厳密な検証
認可サーバーでのRedirect URIの検証は非常に重要です。
-
完全一致での検証: 部分一致や正規表現での検証は避ける
-
HTTPSの強制: 本番環境ではHTTPSのURIのみを許可
-
ワイルドカードの禁止: サブドメインでのワイルドカード使用は推奨されない
これらの対策を怠ると攻撃者が認可コードを窃取し、不正にアク セストークンを取得する可能性があります
まとめ
OCID開発を通じて学んだ認証と認可の違い、OAuth2.0とOpenID Connectについて解説しました。
今回解説したもの以外にもOAuth2.0周辺には、セキュリティ性を担保するための複雑な仕様やベストプラクティスが存在しています。これらは今後も新たな攻撃手法の発見によって増えていく可能性があるので、RFC 6749やOpenID Connect Core 1.0を読んでみると面白いかもしれません。
また、実際に認証・認可の仕組みを実装する場合ライブラリやフレームワークを利用するのが一般的です。しかし、これらの背後にある仕組みを理解することでアプリケーション特性にあった設計やトラブル対応に繋げることができると思います。
この記事がOAuth2.0とOpenID Connectの理解に貢献し、設計やトラブル対応の助けになれば幸いです!
「人の数だけ、キャリアをつくる。」
ワンキャリアではミッション実現のために、事業・プロダクト開発を推進させる仲間を募集しています。弊社のエンジニア組織にご興味を持っていただけた方は、採用情報もチェックいただけると嬉しいです!
▼ワンキャリアのエンジニア組織のことを知りたい方はまずこちら
▼カジュアル面談を希望の方はこちら
▼エンジニア求人票
元の記事を確認する