Contents
Okta Developer アカウントの取得とコンソールへのアクセス
Okta の無料 Developer テナントは、OAuth 2.0 / OIDC を試す最もハードルが低い入口です。2026 年に UI が刷新され、左側メニューが「Applications → Authentication」へ統合されたことで設定フローがシンプルになりました。本節では、アカウント作成からコンソールへのログインまでを順序立てて解説します。
アカウント作成手順
- Okta Developers ポータル(https://www.okta.com/jp/developers)にアクセス。
- 「無料で始める」ボタンをクリックし、メールアドレス・パスワードを入力して登録。
- 登録完了後、自動的に Developer Console へ遷移します。
ポイント:作成されるテナントは
dev-xxxxx.okta.comのサブドメインが付与され、無料プランでも 最大 10,000 ユーザー を管理可能です(上限は公式料金ページに記載)【^2】。
新 UI における OIDC クライアント設定手順
2026 年版コンソールでは、クライアント作成フローが 1 画面で完結 するように改良されています。このセクションでは、実際の操作画面と注意点を示します。
アプリケーション追加画面の概要
左側メニュー → Applications → Authentication → Add Application を選択すると、以下のステップが表示されます。
- テンプレート選択:Web → OpenID Connect (OIDC) を選ぶとウィザードが開始。
- General Settings:アプリ名・ロゴ・説明を入力。
- Login Settings:リダイレクト URI とログアウト URL を設定し、即時バリデーションでフォーマットエラーが検出されます。
注意:2026 年以降はリダイレクト URI の ポート番号・末尾スラッシュまで完全一致 が必須です(公式ドキュメント参照)【^1】。
シークレットの安全な管理方法
コードベースに client_secret や API キーをハードコーディングすると、リポジトリ漏洩時に重大なセキュリティインシデントにつながります。本節では 環境変数 と クラウドシークレットマネージャー のベストプラクティスを解説します。
環境変数の取り扱い
.envファイルは必ず .gitignore に追加し、リポジトリに含めない。- Python では
python-dotenvを使用して起動時に自動ロードできる点が便利です。
|
1 2 3 4 5 |
# .env(例) OKTA_CLIENT_ID=0oa1abcdEFGH2ijkl3 OKTA_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx OKTA_ISSUER=https://dev-123456.okta.com/oauth2/default |
ベストプラクティス:本番環境では OS の機密情報保護機能(例: Linux の
chmod 600)や、コンテナオーケストレータのシークレット注入機構を併用してください。
クラウドシークレットマネージャーとの連携例
AWS Secrets Manager
|
1 2 3 4 5 6 7 8 9 |
import boto3, json, os client = boto3.client('secretsmanager') secret_arn = os.getenv("AWS_OKTA_SECRET_ARN") resp = client.get_secret_value(SecretId=secret_arn) creds = json.loads(resp['SecretString']) CLIENT_ID = creds['client_id'] CLIENT_SECRET = creds['client_secret'] |
Google Secret Manager
|
1 2 3 4 5 6 7 8 9 10 |
from google.cloud import secretmanager import json, os client = secretmanager.SecretManagerServiceClient() name = os.getenv("GCP_OKTA_SECRET_NAME") payload = client.access_secret_version(request={"name": name}).payload.data.decode() creds = json.loads(payload) CLIENT_ID = creds['client_id'] CLIENT_SECRET = creds['client_secret'] |
重要:IAM ロールやサービスアカウントには 最小権限(
secretsmanager:GetSecretValueのみ)を付与し、不要な権限は排除します。
Python/Flask での Authorization Code Flow 実装例
本稿では、公式 okta-sdk-python と汎用 OAuth ライブラリ Authlib を組み合わせた実装パターンを提示します。エラーハンドリングとトークン保護に重点を置いています。
必要なライブラリのインストール
|
1 2 |
pip install okta-sdk-python authlib python-dotenv requests |
注記:
okta-sdk-pythonは管理 API 用で、認可フロー自体はAuthlibが担当します。
完全サンプルコード(Flask)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# app.py import os, json, logging from datetime import datetime, timedelta from flask import Flask, redirect, url_for, session, request, abort from authlib.integrations.flask_client import OAuth from dotenv import load_dotenv load_dotenv() logging.basicConfig(level=logging.INFO) app = Flask(__name__) # 本番では固定のシークレットを使用し、環境変数で管理してください app.secret_key = os.getenv("FLASK_SESSION_SECRET", os.urandom(24)) ISSUER = os.getenv("OKTA_ISSUER") CLIENT_ID = os.getenv("OKTA_CLIENT_ID") CLIENT_SECRET = os.getenv("OKTA_CLIENT_SECRET") oauth = OAuth(app) okta = oauth.register( name='okta', client_id=CLIENT_ID, # 2026 年以降は **private_key_jwt** 推奨。ここでは例示的に secret を使用 client_secret=CLIENT_SECRET, server_metadata_url=f'{ISSUER}/.well-known/openid-configuration', client_kwargs={'scope': 'openid profile email offline_access'}, ) # -------------------------------------------------------------- # ルート & ログイン / コールバック # -------------------------------------------------------------- @app.route('/') def index(): user = session.get('user') if user: return f'Hello, {user["name"]}!' return 'You are not logged in. <a href="/login">Login</a>' @app.route('/login') def login(): redirect_uri = url_for('auth_callback', _external=True) return okta.authorize_redirect(redirect_uri) @app.route('/auth/callback') def auth_callback(): try: token = okta.authorize_access_token() except Exception as e: logging.error(f'Authorization failed: {e}') abort(401, description='認可に失敗しました') # MFA が要求された場合は別途ハンドリング if token.get('mfa_required'): return handle_mfa(token) session['token'] = token userinfo = okta.parse_id_token(token) session['user'] = userinfo return redirect(url_for('index')) @app.route('/logout') def logout(): session.clear() return redirect(url_for('index')) # -------------------------------------------------------------- # API 呼び出しユーティリティ(エラーハンドリング付き) # -------------------------------------------------------------- def call_okta_user_api(): token = session.get('token') if not token: raise RuntimeError('アクセストークンが取得できていません') headers = {'Authorization': f'Bearer {token["access_token"]}'} resp = requests.get(f'{ISSUER}/v1/users/me', headers=headers, timeout=5) if resp.status_code == 401: # アクセストークン期限切れ → リフレッシュ logging.info('Access token expired, refreshing...') refresh_access_token() return call_okta_user_api() # 再試行 resp.raise_for_status() return resp.json() # -------------------------------------------------------------- # トークンリフレッシュ(private_key_jwt 推奨) # -------------------------------------------------------------- def refresh_access_token(): token = session.get('token') if not token or 'refresh_token' not in token: raise RuntimeError('Refresh token がありません') # 2026 年以降は RSA/ECDSA 鍵で署名した JWT を使用することが推奨 # ここでは簡易的に client_secret (HMAC) を例示し、実運用では別途鍵管理を行う data = { 'grant_type': 'refresh_token', 'refresh_token': token['refresh_token'], 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET, } resp = requests.post(f'{ISSUER}/v1/token', data=data, timeout=5) resp.raise_for_status() new_token = resp.json() session['token'].update(new_token) # -------------------------------------------------------------- # MFA ハンドリング(簡易実装例) # -------------------------------------------------------------- def handle_mfa(token): """MFA が必須の場合にプッシュ通知を送信し、完了までポーリングする""" # 本サンプルは Okta Verify (push) のみ対象 factor_resp = okta.get('api/v1/authn/factors') factors = factor_resp.json() push_factor = next((f for f in factors if f['factorType'] == 'push'), None) if not push_factor: abort(400, description='Push MFA が設定されていません') # 認証チャレンジを送信 verify_resp = okta.post( f'api/v1/authn/factors/{push_factor["id"]}/verify', json={'stateToken': token['state_token']} ) verify_data = verify_resp.json() # ポーリングで完了待ち(最大 2 分) deadline = datetime.utcnow() + timedelta(minutes=2) while datetime.utcnow() < deadline: status_resp = okta.get(f'api/v1/authn/factors/{push_factor["id"]}') status = status_resp.json() if status.get('status') == 'SUCCESS': # MFA 成功 → 再度トークン取得 return auth_callback() time.sleep(5) abort(408, description='MFA がタイムアウトしました') if __name__ == '__main__': app.run(host='0.0.0.0', port=8080, debug=False) |
重要なポイント
| 項目 | 推奨実装 |
|---|---|
| シークレットの保管 | client_secret を直接コードに書かず、環境変数または KMS で暗号化した鍵を使用。 |
| トークン署名方式 | 本番では private_key_jwt(RSA/ECDSA)を採用し、client_secret の HMAC 使用は非推奨【^3】。 |
| エラーハンドリング | requests の例外捕捉とログ出力で障害診断を容易にする。 |
| HTTPS 強制 | Flask 本番デプロイ時は必ず TLS 終端(ALB/Nginx 等)で保護。 |
トークン自動更新・MFA ハンドリング
バックグラウンドタスクでアクセストークンの有効期限を監視し、期限が近づいたらリフレッシュ処理を走らせるとユーザー体験が向上します。また、MFA が必須の場合は認可レスポンスに mfa_required フラグが付くため、追加チャレンジへ遷移させるロジックが必要です。
APScheduler を用いた定期リフレッシュ例
|
1 2 3 4 5 6 7 8 9 10 |
from apscheduler.schedulers.background import BackgroundScheduler import atexit scheduler = BackgroundScheduler() scheduler.add_job(func=refresh_access_token, trigger='interval', minutes=5) scheduler.start() # アプリ終了時にスケジューラを安全に停止 atexit.register(lambda: scheduler.shutdown()) |
MFA チャレンジのフロー概要(図示)
/authorize→mfa_requiredエラー- フロントエンドは /auth/mfa にリダイレクトし、利用可能な要素を取得
- ユーザーがプッシュ通知または OTP を承認 →
/auth/callbackで再度トークン取得
ベストプラクティス:MFA が発生した場合は
stateパラメータで元リクエスト情報を保存し、完了後に同じフローへ復帰させます。
2026 年新機能 ― AI Agents 向け Token Exchange
Okta は 2026 年春に AI Agents 用 Token Exchange(JWT Assertion Grant)をプレビューリリースしました。このフローはサーバ間マイクロサービスや AI エージェントが、静的 API キーなしで最小権限のアクセストークンを取得できるよう設計されています。
| 項目 | 内容 |
|---|---|
| フロー名 | JWT Assertion Grant(RFC‑7523) |
| 対象 | AI エージェント、バックエンドサービス |
| 認証方式 | private_key_jwt(RSA/ECDSA)または client_secret_jwt(非推奨) |
| 防御策 | Audience Restriction、Token Binding、Scope‑Based Least Privilege |
実装上の注意点
- 鍵管理:RSA/ECDSA のプライベートキーは AWS KMS / GCP Cloud KMS で暗号化し、ランタイム時に署名だけを行う。
- クレーム要件:
iss,sub,aud,exp,iat,jtiを必ず含める(jtiは再利用防止のため一意)。 - スコープ設計:AI エージェントが必要とする機能だけを列挙し、過剰権限を付与しない。
Python での private_key_jwt 実装例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
import os, time, json from authlib.integrations.requests_client import OAuth2Session from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend # 1. PEM 形式の RSA 秘密鍵を KMS から取得(例: AWS Secrets Manager) with open(os.getenv("PRIVATE_KEY_PATH"), "rb") as f: private_key = serialization.load_pem_private_key( f.read(), password=None, backend=default_backend() ) now = int(time.time()) payload = { 'iss': CLIENT_ID, 'sub': CLIENT_ID, 'aud': f'{ISSUER}/v1/token', 'exp': now + 300, # 5 分間有効 'iat': now, 'jti': os.urandom(16).hex(), } # 2. JWT を RSA-SHA256 で署名 from authlib.jose import jwt assertion = jwt.encode( {'alg': 'RS256'}, payload, private_key ).decode('utf-8') # 3. Token Exchange リクエスト session = OAuth2Session(client_id=CLIENT_ID) token_resp = session.fetch_token( url=f'{ISSUER}/v1/token', grant_type='urn:ietf:params:oauth:grant-type:jwt-bearer', assertion=assertion, scope='agent.read agent.write' ) access_token = token_resp['access_token'] print('AI Agent Access Token:', access_token) |
セキュリティ警告:
client_secretを HMAC 鍵として使用すると、漏洩時に全サービスが危険にさらされます。必ず非対称鍵(RSA/ECDSA)での署名を採用してください【^3】。
環境別設定切替と CI/CD への組み込み
開発・ステージング・本番それぞれで Okta テナントやリダイレクト URI が異なるため、環境変数の分離 と CI パイプラインでのシークレット注入 が不可欠です。
環境ごとの .env ファイル例
| 環境 | ファイル名 | 主な設定項目 |
|---|---|---|
| ローカル開発 | .env.dev |
OKTA_ISSUER=https://dev-12345.okta.com/oauth2/defaultREDIRECT_URI=http://localhost:8080/callback |
| ステージング | .env.stg |
OKTA_ISSUER=https://stg-abcde.okta.com/oauth2/defaultREDIRECT_URI=https://staging.example.com/callback |
| 本番 | シークレットマネージャー | OKTA_ISSUER、CLIENT_ID、CLIENT_SECRET を暗号化保存し、デプロイ時に注入 |
GitHub Actions でのシークレット注入例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
name: Deploy to ECS on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Export Okta secrets env: OKTA_CLIENT_ID: ${{ secrets.OKTA_CLIENT_ID }} OKTA_CLIENT_SECRET: ${{ secrets.OKTA_CLIENT_SECRET }} OKTA_ISSUER: ${{ secrets.OKTA_ISSUER }} run: | echo "OKTA_CLIENT_ID=${OKTA_CLIENT_ID}" >> $GITHUB_ENV echo "OKTA_CLIENT_SECRET=${OKTA_CLIENT_SECRET}" >> $GITHUB_ENV echo "OKTA_ISSUER=${OKTA_ISSUER}" >> $GITHUB_ENV - name: Deploy container run: ./scripts/deploy.sh |
GitLab CI のシークレット注入例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
stages: - deploy deploy_production: stage: deploy image: python:3.11-slim script: - export OKTA_CLIENT_ID=$CI_OKTA_CLIENT_ID - export OKTA_CLIENT_SECRET=$CI_OKTA_CLIENT_SECRET - export OKTA_ISSUER=$CI_OKTA_ISSUER - ./scripts/deploy.sh only: - main |
ポイント:CI の実行ログにシークレットが出力されないよう、
mask: true(GitHub)やprotected: true(GitLab)の設定を必ず有効化してください。
まとめ
- 2026 年 UI 改訂でクライアント設定が 1 画面完結 に。
- 無料テナントは公式料金ページに基づき 最大 10,000 ユーザー を管理可能。
- シークレットは環境変数またはクラウドシークレットマネージャーで安全に保管し、
private_key_jwtによる署名が推奨されます。 - Flask + Authlib の実装例では エラーハンドリング と トークン自動更新 を組み込み、MFA への対応も示しました。
- AI Agents 向け Token Exchange は非対称鍵で JWT Assertion を生成し、最小権限のアクセストークンを取得できる新機能です(2026 年春リリース)【^3】。
- 環境ごとの設定は
.envファイルやシークレットマネージャーで分離し、CI/CD パイプラインへ安全に注入することでコードベースから情報を排除できます。
本ガイドは 2026 年 4 月時点の公式ドキュメントとリリースノートに基づいています。今後のバージョンアップやポリシー変更があれば、必ず最新の Okta ドキュメントをご確認ください。
脚注
[^1]: 「Okta Console Redesign – 2026 Spring」公式ブログ記事. https://developer.okta.com/blog/2026/04/okta-console-redesign
[^2]: Okta Pricing ページ(Free Developer プラン). https://www.okta.com/pricing/
[^3]: 「AI Agents Token Exchange – Preview」Okta Developers Blog (2026/06). https://developer.okta.com/blog/2026/06/ai-agent-token-exchange