📖
Entra ID×OIDCによるWebアプリ認証:ハンズオン
1. OIDC認証とは?
OIDC(OpenID Connect)は、OAuth 2.0ベースの「SSO(シングルサインオン)標準」です。
JSON形式のIDトークン(JWT)で「この人はEntra IDで認証済み!」をWebアプリ間でやりとりできます。
1.1 認証の仕組み
認証と認可とは
- 認証(Authentication): ユーザーが誰であるかの確認をする(例: ユーザー名とパスワードで本人確認)。
- 認可(Authorization): 認証されたユーザーがどのような権限を持つかを確認する(例: 管理者の権限であるとか一般ユーザの権限であるとか)。
1.2 OIDC認証の基本フロー(図解)
OIDC認証フロー図
┌────────────┐ ┌────────────┐ ┌──────────────┐
│ ユーザー │ │ Webアプリ │ │ IdP(Entra ID)│
└────────────┘ └────────────┘ └──────────────┘
(1) アクセス&ログイン要求
│────────────>│
(2) 認証要求リダイレクト
│────────────>│
│────────────>│
(3) 認証画面表示・ユーザー認証
│<────────────│
│<────────────│
(4) 認証コード受領(リダイレクト)
│<────────────│
(5) 認証コードを使いID/アクセストークン要求(バックエンド通信)
│────────────>│
│────────────>│
(6) ID/アクセストークン返却(JSONレスポンス)
│<────────────│
(7) Webアプリでトークン検証・セッション確立&サービス提供
この“IDトークン(JWT)”がOIDCのポイント。アプリ側はこれで「正しく本人」と判定されます
2. OIDC認証のハンズオン
2.1 Azure側のアプリ登録
-
Azureポータルにサインイン
「Entra ID」>「アプリの登録」>「新規登録」

-
アプリの登録内容
「アプリ名」
→OIDC Flask App
「リダイレクトURI」には
→ http://localhost:5000/oidc/callback を入力

-
各種IDの確認
登録完了後、「アプリケーション(クライアント)ID」と「ディレクトリ(テナント)ID」を控える

-
証明書の作成
「証明書とシークレット」>「新しいクライアントシークレット」を作成

-
証明書のシークレット値の確認
作成したシークレットの値を控える

2.2 アプリケーション(Flask OIDCクライアント)作成
■ 構成
OIDC/
├── app.py # Flaskアプリ本体
├── .env # 設定(クライアントID等)
■ ライブラリ
pip install flask requests python-dotenv authlib
■ .envの中身
OIDC_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OIDC_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
REDIRECT_URI=http://localhost:5000/oidc/callback
■ app.py(超シンプル実装例)
import os
from flask import Flask, redirect, request, session, url_for
from authlib.integrations.flask_client import OAuth
from dotenv import load_dotenv
load_dotenv()
app = Flask(__name__)
app.secret_key = os.urandom(24)
oauth = OAuth(app)
oauth.register(
name='azure',
client_id=os.environ['OIDC_CLIENT_ID'],
client_secret=os.environ['OIDC_CLIENT_SECRET'],
server_metadata_url=f'https://login.microsoftonline.com/{os.environ["OIDC_TENANT_ID"]}/v2.0/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile email'
}
)
@app.route('/')
def index():
user = session.get('user')
if user:
return f'ようこそ、{user["name"]} さん!<br><a href="/logout">ログアウト</a>'
return '<a href="/login">OIDCでログイン</a>'
@app.route('/login')
def login():
redirect_uri = url_for('auth_callback', _external=True)
return oauth.azure.authorize_redirect(redirect_uri)
@app.route('/oidc/callback')
def auth_callback():
token = oauth.azure.authorize_access_token()
userinfo = oauth.azure.parse_id_token(token)
session['user'] = userinfo
return redirect('/')
@app.route('/logout')
def logout():
session.clear()
return redirect('/')
if __name__ == '__main__':
app.run(debug=True)
2.3 動作確認
- アプリケーション起動
python app.py

-
ブラウザアクセス
ブラウザで http://localhost:5000/ へアクセスして、「OIDCでログイン」をクリック

-
Azure Entra IDのログイン画面へリダイレクト

4.ログイン確認
ようこそ、[名前] さん! と表示されなます

3. OIDCフローとコードの紐づけ
| フロー | コード/エンドポイント | ポイント(現場で何が起きているか) |
|---|---|---|
| (1) サービス要求 | / |
「OIDCでログイン」リンク表示 |
| (2) 認証要求リダイレクト | /login |
authorize_redirectでIdP(Entra ID)へリダイレクト、nonce生成 |
| (3) 認証画面(ユーザー認証) | Entra ID | Azureのログイン画面でID入力・パスワード認証 |
| (4) 認証コード受領(リダイレクト) | /oidc/callback |
Entra IDから「認証コード」をクエリパラメータで受け取る(GETアクセス) |
| (5) トークンリクエスト(バックエンド通信) | /oidc/callback |
サーバーが認証コードを使いEntra IDに「ID/アクセストークン」をリクエスト(POST通信) |
| (6) トークン検証・セッション格納 | /oidc/callback |
IDトークン(JWT)を検証し、ユーザー情報をsession['user']に格納 |
| (7) サービス提供 | / |
ログイン済みユーザー情報でページ表示 |
4. まとめ
OIDCはSAMLよりシンプル
Python/FlaskとAuthlibを使えば、10分でデモが作れる
Discussion