わかったつもりになる「APIの認証プロセス」〜JWT, Basic, Token Based, OAuth, Cookie/Session Based, SSO, OIDC...〜
JWT
概要
トークンベースの認証。
Open Standard(RFC7519)とやらに基づいている。
JSON Web Token (JWT) is a compact, URL-safe means of representing
claims to be transferred between two parties. The claims in a JWT
are encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON Web
Encryption (JWE) structure, enabling the claims to be digitally
signed or integrity protected with a Message Authentication Code
(MAC) and/or encrypted.
ちょっと表現が硬すぎて理解しづらい…ので必死に要約する。
JWTは、
- デジタル署名されたトークンの形式で、2つのパーティ(例えば、クライアントとサーバ)間でクレーム(主張や情報の断片)を安全に転送するために使われる
- 情報をコンパクトかつURLに適した形式で表現する方法である
JWT内のクレームは、JSONオブジェクトとしてエンコードされ、様々な種類のデータ(ユーザーID、権限レベル、有効期限などなど)を効率的に格納できる
JWTは下記2つによってセキュアである。
- デジタル署名: JWTはJSON Web Signature(JWS)構造を使ってデジタル署名されることが多く、これによりトークンが改ざんされていないことを保証する。
- 暗号化: JWTはJSON Web Encryption(JWE)構造を使って暗号化することもでき、これによりトークンの内容が第三者に読まれることを防ぐ。
JWTの用途)例えば、ユーザーがログインした際に認証情報を提供するためや、APIへのアクセス権を確認するためなどに使われる。また、データの整合性と信頼性を保証するために、署名や暗号化がしばしば施される。
JWT(JSON Web Tokens)は、デジタル署名されたトークンを使用して、クライアントとサーバ間で情報を安全に交換するための方法です。JWTは、通常、認証や情報の交換に使用されます。
具体に踏み込む
JWTの構成
3部構成。
- ヘッダー(Header): トークンのタイプ(通常はJWT)と使用される署名アルゴリズム(例:HMAC SHA256、RSAなど)を指定する。
- ペイロード(Payload): 実際に伝達したいデータ(クレーム)。ユーザーID、トークンの有効期限などの情報を含む。
- 署名(Signature): ヘッダーとペイロードを結合し、秘密鍵を使用して生成された署名のこと。
サーバサイドでの処理
JWTを生成してクライアントに送信する。下記はPythonのHTTPサーバのコード例。
import jwt
from flask import Flask, jsonify, request
from datetime import datetime, timedelta
app = Flask(__name__)
SECRET_KEY = "your_secret_key"(秘密鍵)
@app.route('/login', methods=['POST'])
def login():
username = request.json.get("username")
password = request.json.get("password")
# ユーザー認証(省略)
# JWT生成
payload = {
'exp': datetime.utcnow() + timedelta(days=1), # 有効期限
'iat': datetime.utcnow(), # 発行時間
'sub': username # ユーザー識別子
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
return jsonify({'token': token})
if __name__ == '__main__':
app.run()
クライアントサイドでの処理
サーバから受け取ったJWTを保存し、以後のリクエストにトークンを添付する。
function login() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
})
.then(response => response.json())
.then(data => {
// JWTをローカルストレージに保存
localStorage.setItem('token', data.token);
})
.catch((error) => { ... });
}
function getData() {
const token = localStorage.getItem('token');
fetch('/some-protected-route', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + token,
},
})
// 以後の処理(省略)
}
セキュリティに関する考慮事項
- HTTPSを使用する: JWTはデータを暗号化しないので、トークンがインターセプトされると、内容が読まれる可能性がある。
- トークンの有効期限: 短い有効期限を設定し、トークンの乗っ取りリスクを軽減するのが良い。
- 秘密鍵の管理: 秘密鍵は絶対に漏らさない(当たり前)。
JWTのエンコード(生成)とデコード(確認)
サーバサイドとクライアントサイドのどちらでも行える。
サーバサイド
- エンコード(生成): サーバサイドでのみ実施。セキュアな環境で秘密鍵または署名アルゴリズムを使うため。
- デコード(確認): クライアントから送られてきたJWTをデコードして検証し、リクエストが正当なユーザーから送信されたものかを確認する。
クライアントサイド
- デコード(確認): JWTのペイロードをデコードして中身を確認することが可能。これは情報を閲覧するだけで、署名を検証するのではない。
- エンコード(生成): クライアントサイドでJWTを生成することは推奨できない。セキュアな状態で署名するのは困難(ほぼ不可能)で、セキュリティリスクそのものだから。
重要な点
- 署名の検証: JWTのセキュリティは署名に依存する。署名の検証はサーバサイドでのみ行うべき。
- 秘密鍵の管理: 秘密鍵はサーバサイドで安全に管理する。クライアントサイドに秘密鍵を持つのは御法度。
JWTの生成と署名の検証はセキュリティ上の理由からサーバサイドで行うのがベストプラクティス。クライアントサイドでは、JWTの中身を閲覧するためにデコードすることはある、検証ではないことに注意。
JWT(JSON Web Token)のペイロード部分について
原則として任意の値を含めれる。
トークンの発行者やトークンの対象者などに関する情報、さらにはユーザー固有のデータやアプリケーション固有の情報など、さまざまなタイプのクレーム(主張)を格納する場所である。
ペイロードに含めれる情報の種類
下記に全部まとまっている。
-
Registered Claims: JWT標準に予め定義されている一連の情報。例えば、トークンの有効期限(
exp
)、発行者(iss
)、対象者(sub
)など。 - Public Claims: より広範なJWTコミュニティによって使用されることを目的としたクレーム。これらは一意であり、名前の衝突を避けるためにURI形式で名前空間が定義されることが推奨されている。
- Private Claims: JWTの発行者と受信者間の合意に基づいて定義されるクレーム。アプリケーション固有のデータはここに含める。
注意点
- セキュリティ: ペイロードに機密情報(パスワードや個人情報など)を含める場合はトークンのセキュリティに注意する。JWTは基本的に署名されているだけでペイロードは暗号化されていないため、機密情報を含める場合はJWTを暗号化するか他の何かしらの手段を実施すること。
- サイズの制約: JWTはHTTPヘッダーなどで使用されるため、そのサイズには実用的な制約がある。大量のデータを含めると通信効率が悪化するので、必要な情報のみを含めるのが良い。
参考資料
この二つ読めば理解した気分になれた。
他にもいろんな参考資料
Basic認証
HTTP仕様の一部で、RFC 7617に詳細が記載されている。
ウェブサーバーとブラウザ間での簡易的な認証方法の一つで、ユーザー名とパスワードをBase64でエンコードしてHTTPリクエストのAuthorization
ヘッダーに含めることによってユーザー認証を行う方法である。
特徴:
- 実装が簡単で多くのウェブサーバーやブラウザでサポートされている。
- ユーザー名とパスワードはBase64でエンコードされて送信されるが、暗号化ではないため、第三者によって容易にデコードされる可能性がある。(セキュリティが重要視される環境には向いてない。)
- HTTPSと組み合わせて送信データのセキュリティを高めることができる。
- ステートレスである→クライアントはHTTPリクエストごとに認証ヘッダーを送信する必要があり、サーバー上にセッションやログイン状態が保持されない。
認証の流れ:
- ブラウザが保護されたリソースにアクセスを試みる。
- サーバーは認証が必要であることを示すレスポンス(HTTPステータスコード 401 Unauthorized)とともに、「WWW-Authenticate」というヘッダーを送信する。
- ブラウザはユーザーにユーザー名とパスワードの入力を促し、入力された情報を「Authorization」というヘッダーにエンコードしてサーバーに送信する。
- サーバーは送信された認証情報を検証し、正しい場合はリソースへのアクセスを許可する。
認証の動作原理
-
最初のリクエスト: ブラウザからサーバーへの最初のリクエストには、
Authorization
ヘッダーが含まれない。サーバーは401 UnauthorizedレスポンスとWWW-Authenticate: Basic
ヘッダーを返す。 -
認証ポップアップ: ブラウザは
WWW-Authenticate
ヘッダーを検出し、ユーザーに認証情報の入力を求めるポップアップを表示する。 -
資格情報の送信: ユーザーが資格情報を入力すると、ブラウザはこれをBase64でエンコードし、改めて
Authorization
ヘッダーを含むリクエストを送信する。 - サーバーでの検証: サーバーは受け取った資格情報をデコードして検証し、資格情報が有効であれば、要求されたリソースをクライアントに返却する。
関連資料
実装例(Node.js, Express)
server.ts
import express, { Request, Response, NextFunction } from 'express'
import { authMiddleware } from './auth'
const app = express()
const port = 3000
app.use(authMiddleware)
app.get('/', (req: Request, res: Response) => {
res.send('Hello World!')
});
app.listen(port, () => { ... })
auth.ts
import { Request, Response, NextFunction } from 'express'
const decodeCredentials = (authHeader: string): [string, string] => {
const token = authHeader.split(' ')[1]
const decoded = Buffer.from(token, 'base64').toString()
const [username, password] = decoded.split(':')
return [username, password]
}
export const authMiddleware = (req: Request, res: Response, next: NextFunction) => {
const authHeader = req.headers.authorization || ''
if (!authHeader.startsWith('Basic ')) {
return res.status(401).send('Authentication required.')
}
const [username, password] = decodeCredentials(authHeader);
... // ユーザ名とパスワードを検証
res.set('WWW-Authenticate', 'Basic realm="user_pages"')
res.status(401).send('Authentication required.')
}
トークン認証
ユーザーが自分の身元を確認し、一意なアクセストークンを受け取るプロトコルのことを指す。
トークンが有効な間、ユーザーは同じウェブページやアプリにアクセスする際に、都度認証情報を再入力する必要がない。
この方式は従来のパスワードベースやサーバーベースの認証技術と異なり、セキュリティの第二層を提供し、管理者には各アクションとトランザクションに対して詳細な制御が可能である。ただし、トークンの使用にはある程度のコーディング知識が必要になる。
IdPを使う場合も使わない場合もある。アプリの要件、規模、セキュリティの必要性、ユーザ管理方法への要求によって異なる。
専門用語解説
- トークン認証 (Token authentication): ユーザーが自身の身元を確認し、対応するサービスやアプリにアクセスするための一時的な証明書(トークン)を受け取る認証方法。
- アクセストークン (Access token): サービスやリソースへのアクセス権を証明するために使用されるデジタルキー。
- JSON Web Token (JWT): 二者間で安全に情報を交換するために使用される、デジタル署名付きのURL安全なトークン形式。ヘッダー、ペイロード、署名の3部分から構成される。
Reference
JWT以外のトークンの種類
- OAuth 2.0
- SAML
- OpenID Connect
- Refresh
- API Key
基本的な認証フローについては、これらのトークンがどのように使用されるかに関わらず、大まかには以下のステップになる:
- 認証リクエスト: ユーザーまたはクライアントアプリケーションが認証サーバーに対して認証をリクエスト
- 認証とトークンの発行: 認証サーバーはユーザーの身元を確認し、成功した場合にトークン(アクセストークン、IDトークン、リフレッシュトークンなど)を発行
- トークンの使用: クライアントアプリケーションは発行されたトークンを使用して、保護されたリソースにアクセス
- トークンの検証: リソースサーバー(またはAPI)は、アクセスを要求するトークンを検証し、適切な権限がある場合にのみリソースへのアクセスを許可
Node.js×Expressでトークン認証を実装する例。トークンにはJWTを使用。
const express = require('express');
const jwt = require('jwt-simple');
const app = express();
const PORT = 3000;
// トークンを署名・検証するために使う秘密鍵
const secretKey = 'SecretKey';
// ユーザー認証用のダミーデータ
const users = [
{ id: 1, username: 'user1', password: 'pass1' },
{ id: 2, username: 'user2', password: 'pass2' }
];
// JSON形式で送信されたリクエストボディを簡単に扱うための必須の設定(Expressではテンプレみたいなもん)
app.use(express.json());
// ログインエンドポイント
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.find(u => u.username === username && u.password === password);
if (user) {
// JWTトークンの生成
const payload = { id: user.id, username: user.username };
const token = jwt.encode(payload, secretKey);
res.json({ token });
} else {
res.status(401).json({ error: '認証に失敗しました。' });
}
});
// トークン検証ミドルウェア
const verifyToken = (req, res, next) => {
const token = req.headers['authorization'];
if (!token) return res.status(403).json({ error: 'トークンが必要です。' });
try {
const decoded = jwt.decode(token, secretKey);
req.user = decoded;
next();
} catch (err) {
return res.status(401).json({ error: 'トークンの検証に失敗しました。' });
}
};
// 認証が必要なルート
app.get('/protected', verifyToken, (req, res) => {
res.json({ message: '保護されたルートへようこそ', user: req.user });
});
app.listen(PORT, () => {
console.log(`サーバーがポート${PORT}で起動しました。`);
});
OAuth認証
OAuthはOpen Authorizationの略で、認可のプロトコルである。
第三者アプリケーションがユーザーの代わりに特定のリソースにアクセスする許可をユーザーから安全に得るために使われる。
ユーザーの認証情報ではなく、アクセストークンを使ってデバイス、API、サーバー、アプリケーションを認可する仕組みで、「安全な委任アクセス」として知られている。
OAuth認証を使うと、ユーザーは自分の認証情報を直接共有することなく、異なるインターネットサービス間で安全にデータを共有できる。
OAuthは主にREST/APIに利用され、ユーザーデータの限られた範囲しか提供しない。
最も単純な形では、OAuthはFacebook、Amazon、Twitterのようなサービスに認証を委譲し、サードパーティのアプリケーションがログイン名とパスワードを入力することなくユーザーアカウントにアクセスできるようにする。
具体的には、あるサービス(クライアントアプリケーション)が、ユーザーの許可を得た上で、別のサービス(リソースサーバー)にアクセスする際に使われる。
ユーザーは自分のユーザー名やパスワードをクライアントアプリケーションに直接提供することなく、リソースサーバー(例えば、ソーシャルメディアサイト)上のデータにクライアントアプリケーションがアクセスすることを許可できる。
通常、以下のステップとなる:
- ユーザー認証: ユーザーがリソースサーバーにログインし、クライアントアプリケーションが特定の情報にアクセスすることを承認する。
- アクセストークンの発行: 承認後、リソースサーバーはクライアントアプリケーションにアクセストークンを発行する。
- リソースアクセス: クライアントアプリケーションはこのアクセストークンを使用して、ユーザーの代わりにリソースサーバーから情報を取得またはリソースにアクセスする。
Reference
Digital Oceanの記事をGPT4に要約させたもの
OAuth 2.0は、HTTPサービス上のユーザーアカウントへの限定的なアクセスをアプリケーションに提供する認可フレームワークです。ユーザー認証をユーザーアカウントをホストするサービスに委任し、第三者アプリケーションがそのユーザーアカウントにアクセスすることを許可します。OAuth 2.0は、Webおよびデスクトップアプリケーション、モバイルデバイス用の認可フローを提供します。
OAuthの役割
OAuthは以下の4つの役割を定義しています:
- リソースオーナー:ユーザーがアプリケーションに自分のアカウントへのアクセスを許可する役割です。
- クライアント:ユーザーアカウントにアクセスを求めるアプリケーションの役割です。
- リソースサーバー:保護されたユーザーアカウントをホストするサーバーの役割です。
- 認証サーバー:ユーザーの身元を検証し、アプリケーションにアクセストークンを発行するサーバーの役割です。
抽象的なプロトコルフロー
- アプリケーションがユーザーからサービスリソースへのアクセス許可をリクエストします。
- ユーザーがリクエストを承認すると、アプリケーションは認可グラントを受け取ります。
- アプリケーションが認証サーバー(API)からアクセストークンをリクエストします。
- アプリケーションがリソースサーバー(API)からリソースをリクエストし、アクセストークンを提示します。
- アクセストークンが有効であれば、リソースサーバー(API)はアプリケーションにリソースを提供します。
アプリケーション登録
OAuthを使用する前に、アプリケーションをサービスに登録する必要があります。このプロセスでは、アプリケーション名、ウェブサイト、リダイレクトURIなどを提供します。登録後、サービスはクライアントIDとクライアントシークレットを発行します。
認可グラント
OAuth 2.0は、認可コード、クライアントクレデンシャル、デバイスコードなど、さまざまな認可グラントタイプを定義しています。各グラントタイプは異なるシナリオで使用され、特定の認可フローに最適化されています。
まとめ
OAuth 2.0により、アプリケーションはユーザーのアカウントに対する限定的なアクセスを安全に取得できます。アプリケーションは、特定の認可フローを通じてアクセストークンを取得し、そのトークンを使用してAPIを通じてユーザーアカウントのリソースにアクセスします。認証と認可は異なる概念であり、OAuth 2.0は認可を中心に設計されています。
Node.jsの実装例
Express、Passport、passport-google-oauth20(Google OAuth 2.0認証を簡単に実装できるライブラリ)を使用
const express = require('express');
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const app = express();
passport.use(new GoogleStrategy({
clientID: 'YOUR_CLIENT_ID_HERE',
clientSecret: 'YOUR_CLIENT_SECRET_HERE',
callbackURL: "http://localhost:3000/auth/google/callback"
},
function(accessToken, refreshToken, profile, cb) {
// ここでユーザープロファイルを使用する。例えば、データベースに保存するなど。
return cb(null, profile);
}
));
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
// 認証が成功したら、リダイレクトするか、成功したことを示すページを表示する。
res.redirect('/');
});
app.get('/', (req, res) => res.send('Hello World!'));
app.listen(3000, () => console.log('Server started on port 3000'));
APIアクセスの流れ
- ユーザーが/auth/googleにアクセスすると、GoogleのOAuth 2.0認証フローが開始
- ユーザーがGoogleでの認証を完了すると、Googleはユーザーを/auth/google/callbackにリダイレクトし、アプリケーションがトークンを受け取る
- 認証が成功すれば、ユーザーはアプリケーションのホームページ(/)にリダイレクトされる
上で述べたのは誤りがあるかも👀
OAuth 2.0 は、OAuth 1.0 との後方互換性がない。
OAuth 2.0は認証プロトコルではなく、アプリケーション間で認証決定を伝達するための委任プロトコルである。誤解が多い中、OAuthは認証プロトコル内で使われるが、OAuth自体がユーザー認証を直接行うわけではない。
認証とは、アプリケーションがユーザーの存在を確認することであり、OAuthではこれを実現してない。しかし、OAuthを基盤として、OpenID Connectのような認証およびアイデンティティプロトコルを構築できる。
OpenID ConnectはOAuth 2.0上に構築され、IDトークン、UserInfoエンドポイント、動的サーバー検出、クライアント登録などを追加することで、認証情報を安全に管理し、アプリケーションに提供する。OpenID ConnectはOAuth 2.0を拡張して、認可だけでなく認証にも対応し、ユーザーが誰であるかを確認するための情報(IDトークンなど)を提供する。
これにより、アプリケーションはユーザーの認証と認可の両方を効率的に管理できるようになる。
Cookie Based認証
ユーザーがログイン情報(例えば、ユーザー名とパスワード)を使用して認証を行うと、サーバー側は認証成功の証としてセッションIDを含むクッキーをユーザーのブラウザに送信する。
ユーザーがその後サーバーにリクエストを送る際、ブラウザはこのクッキーを自動的にリクエストに添付してサーバーに送る。
サーバーはクッキーに含まれるセッションIDを確認し、それに基づいてユーザーの認証状態を判定する。
特徴
セッション管理がサーバー側で行われること。
セッションIDをクッキーで管理することで、サーバーは各ユーザーの認証状態やセッション情報を追跡できる。
これにより、ユーザーは一度ログインすれば、セッションが有効な限り、再度認証情報を入力することなくサービスを利用できる。
セキュリティ上の懸念
クッキーが盗まれるとセッションハイジャックが可能になるため、HTTPSを使用して通信を暗号化する、HttpOnlyやSecure属性をクッキーに設定するなどの対策が重要。
また、クロスサイトスクリプティング(XSS)やクロスサイトリクエストフォージェリ(CSRF)などの攻撃に対する防御も必要となる。
そもそもの認証・認可
認証(Authentication)と認可(Authorization)は異なる概念
- 認証(Authentication)
- ユーザーが誰であるかを確認するプロセス
- 例えば、ユーザー名とパスワードを入力してログインすることで、システムはそのユーザーが宣言している人物であることを確認する。また、二要素認証など、さらにセキュリティを強化する方法もある。
- 認可(Authorization)
- 認証されたユーザーが特定のリソースにアクセスしたり、ある操作を実行したりする権限があるかどうかを決定するプロセス
- 例えば、あるウェブサイト上で、特定のユーザーが特定のページを見ることができるか、あるいは管理者権限で特定の操作ができるかどうかを制御する。
OpenID Connect
OpenID Connect(OIDC)は、ユーザーが様々なウェブサイトやアプリケーション間で一貫して自分の身元を認証できるようにするプロトコルである。
この仕組みは、OAuth 2.0の認可フレームワークに基づき、ユーザーが認証サービスによって誰であるかを確認し、その結果をアプリケーションと安全に共有することを可能にする。
つまり、OIDCはユーザーが一つのアカウントで多くのサービスにログインできるようにし、開発者がユーザーのログインプロセスを簡単に管理できるようにすることを目指している。
対照的に、OAuthは主にアプリケーションがユーザーの許可を得て特定のリソースにアクセスする権限を得るための認可を提供する。
このプロセスはユーザーの認証情報を第三者アプリケーションに明かすことなく、安全なリソースアクセスを可能にする。
OIDCとOAuthの主な違いは、OIDCがユーザー認証に焦点を当てているのに対し、OAuthはアプリケーションへの認可を中心に設計されている点だ。OIDCは、ユーザーがログインする際に「現在のユーザーは誰か」という問いに対して安全かつ検証可能な答えを提供する。このため、OIDCはシングルサインオン(SSO)やアイデンティティフェデレーションのニーズに適している。
OAuthとOpenIDは、認証と認可のニーズに対処するための2つの重要なプロトコルで、それぞれ異なる目的を持つ。
OAuth(オープン認可)
- 目的: 第三者アプリケーションがユーザーの許可を得てリソースにアクセスするための認可を提供する。
- 利用シーン: ソーシャルメディア接続やAPI保護に最適で、ユーザーのログイン情報を明かさずに、サードパーティアプリがユーザーデータへアクセスすることを可能にする。
- メリット: 広範な採用とサポート、細かいアクセス制御。
- デメリット: 実装の複雑さ、ユーザー情報に関する制限。
OpenID(オープンID)
- 目的: ユーザーが複数のウェブサイトやアプリケーションで一貫した認証情報を使用してログインできるようにする。
- 利用シーン: シングルサインオン(SSO)や複数のドメインまたは組織間でのフェデレーションアイデンティティに適する。
- メリット: ユーザー認証の簡素化、デジタルアイデンティティの管理。
- デメリット: サポートの限界、OAuthほど細かい認可機能を持たない。
OAuth vs OpenID:どちらを選ぶべきか?
- OAuthは、特に外部アプリがユーザーデータにアクセスする必要がある場合や、APIのセキュリティ強化が必要な場合に適している。
- OpenIDは、ユーザーが一貫したログイン情報で複数のサービスにアクセスすることを希望する場合、特にシングルサインオン(SSO)やアイデンティティのフェデレーションが求められる場合に最適である。
選択する際には、アプリケーションがユーザー認証に重点を置いているのか、それとも外部サービスへの安全なアクセス権限を管理する必要があるのかを考慮する必要がある。多くの場合、OIDCとOAuthは相互に補完し合うものとして組み合わせて使用され、アプリケーションにおける認証と認可の両方のニーズに対応する。
Reference
OAuth 2.0の認可フレームワークに基づいたプロセスにおいて、ユーザーが認証サービス(IdP: Identity Provider、身元情報提供者)によってどのように認証され、その結果がアプリケーションと安全に共有されるかという部分は、主にIdPが担っている。
そのため一般的な開発者は、このプロセスの内部実装を直接触る必要がない。
開発者が行うべきこと
OAuth 2.0やOpenID Connect(OIDC)をサポートするIdPから提供されるAPIやサービスを利用して、アプリケーションに認証機能を統合すること。
- アプリケーションの登録: 開発者は、使用するIdPにアプリケーションを登録し、クライアントIDとクライアントシークレットなどの認証情報を取得する。
- 認証リクエストの送信: アプリケーションはユーザーがサインインを試みた際に、IdPの認証エンドポイントにリダイレクトするリクエストを送信する。
- ユーザー認証: ユーザーはIdPのウェブページで認証(ログイン)を行い、アプリケーションへのアクセスを承認する。
- 認証情報の受け取り: 認証が成功すると、アプリケーションはIdPからIDトークン(OIDCの場合)やアクセストークン(OAuth 2.0の場合)を受け取る。
- ユーザー情報の取得: 必要に応じて、アプリケーションは受け取ったトークンを使ってIdPからユーザー情報を取得する。
SAML
セキュリティアサーションマークアップ言語(SAML)は、認証や認可データをパーティー間、特にアイデンティティプロバイダー(IdP)とサービスプロバイダー(SP)間で交換するための、XMLベースの標準である。
SAMLベースのシステムでは、ユーザーが保護されたリソースへのアクセスをリクエストする。
サービスプロバイダーは、アイデンティティプロバイダーにユーザーの認証を依頼し、リソースへのアクセス権を持っているかを確認する。
SAMLの利点
SAMLを使用することのいくつかの利点には、次のようなものがある:
- シングルサインオン(SSO):ユーザーはIdPで一度ログインすると、再認証することなく複数のサービスプロバイダーにアクセスできる。
- セキュリティの向上:サービスプロバイダーがパスワードやユーザー認証情報を管理する必要がなくなり、攻撃の可能性が減少する。
- 効率の向上:ユーザーが複数の認証情報を管理する必要がなくなるため、ユーザーとシステム管理者の双方にとってアクセス管理が容易になる。
- 相互運用性:SAMLは、異なる技術やプラットフォームにかかわらず、幅広いアプリケーションが連携して動作することを可能にする。
SAMLの構成要素
SAMLアーキテクチャには3つの主要な構成要素がある:
- アイデンティティプロバイダー(IdP):ユーザーの身元を管理し、セキュリティトークン(アサーションとも呼ばれる)を提供して認証するエンティティ。
- サービスプロバイダー(SP):サービス(例えばウェブアプリケーションやAPIなど)を提供し、アイデンティティプロバイダーによるユーザー認証とリソースへのアクセス許可/拒否に依存するエンティティ。
- ユーザー/プリンシパル:サービスプロバイダーが提供するサービスへのアクセスを求めるエンドユーザー。
SAMLワークフロー
SAML認証プロセスは、以下のステップで構成される:
- ユーザーがサービスプロバイダーから保護されたリソースへのアクセスをリクエストする。
- ユーザーがまだ認証されていない場合、サービスプロバイダーはアイデンティティプロバイダーにSAML認証リクエストを生成して送信する。
- アイデンティティプロバイダーはユーザーを認証する(例えば、ユーザー名とパスワード、多要素認証などを使用)。
- アイデンティティプロバイダーはSAMLレスポンスを構築し、リクエストされたリソースへのアクセスが認可されているかどうかを含め、ユーザーに関する詳細を返す。
- SAMLレスポンスは、通常、ユーザーのウェブブラウザーやAPIクライアントを介してサービスプロバイダーに戻される。
- サービスプロバイダーはSAMLレスポンスを処理し、必要な情報を抽出し、アイデンティティプロバイダーのアサーションに基づいてユーザーへのアクセスを許可または拒否する。
SAMLを使用することで、さまざまなアプリケーションやシステム間でのユーザー認証と認可を効率的に行い、より良いユーザー体験と全体的なバックエンドセキュリティを提供できる。
##Reference