ネイティブアプリ向け OIDC 連携
既存のネイティブアプリ(iOS / Android)に PocketSign Link v2 の OIDC ログインを組み込む場合の構成です。 ネイティブアプリは OAuth 2.0 の Public Client として動作し、PAR + PKCE を組み合わせて安全な認可フローを実現します。
自社のネイティブアプリに PocketSign Link v2 を ID 基盤としたログイン機能を追加したい場合や、アプリ内の WebView で v2 連携済みの Web サービス(RP)を利用したい場合に参照してください。
準拠する仕様
PocketSign Link v2 のネイティブアプリ向け OIDC 連携は、以下の標準仕様をベースにしています。
- RFC 8252 - OAuth 2.0 for Native Apps — ネイティブアプリにおける OAuth 2.0 のベストプラクティス
- RFC 7636 - Proof Key for Code Exchange (PKCE) — 認可コード横取り攻撃の防止
- RFC 9126 - Pushed Authorization Requests (PAR) — 認可パラメータの事前送信
ブラウザフローとの違い
| 観点 | ブラウザ(Confidential Client) | ネイティブアプリ(Public Client) |
|---|---|---|
| クライアント認証 | client_secret または private_key_jwt | なし(client_id のみ) |
| PKCE | 推奨 | 必須(S256) |
redirect_uri | https:// スキーム(サーバーサイド) | アプリに戻る URI(Universal Links / App Links / カスタムスキーム) |
| トークン交換 | サーバーサイド | アプリ内で直接実行 |
前提条件
- PocketSign Platform で OIDC クライアントを Public Client として登録する
redirect_uriにアプリへのコールバック URI を登録するclient_secretは発行されない
フロー図
PAR(Pushed Authorization Request)
ネイティブアプリでは、認可パラメータを事前にサーバーに送信する PAR の利用を推奨します。
curl -X POST "https://id.mock.klon.you/api/oidc/v1/par" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=<CLIENT_ID>" \
-d "redirect_uri=https://app.example.com/callback" \
-d "response_type=code" \
-d "scope=openid" \
-d "state=<STATE>" \
-d "nonce=<NONCE>" \
-d "code_challenge=<CODE_CHALLENGE>" \
-d "code_challenge_method=S256"
レスポンスで request_uri が返されます。
アプリ内の WebView で v2 連携済みの Web サービスを表示し、セッションバインドも使う場合は、native スコープも要求してください。
このスコープを含むアクセストークンを POST /api/native/v1/bind で使用します。
curl -X POST "https://id.mock.klon.you/api/oidc/v1/par" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=<CLIENT_ID>" \
-d "redirect_uri=https://app.example.com/callback" \
-d "response_type=code" \
--data-urlencode "scope=openid native" \
-d "state=<STATE>" \
-d "nonce=<NONCE>" \
-d "code_challenge=<CODE_CHALLENGE>" \
-d "code_challenge_method=S256"
認可リクエスト
PAR で取得した request_uri を使ってシステムブラウザで認可エンドポイントを開きます。
https://id.mock.klon.you/api/oidc/v1/authorize?client_id=<CLIENT_ID>&request_uri=<REQUEST_URI>
Public Client の場合、request_uri なしで直接パラメータを渡す方式も利用可能ですが、パラメータの露出を最小化するため PAR の利用を推奨します。
PKCE
Public Client では PKCE(Proof Key for Code Exchange)が必須です。
- ランダムな
code_verifier(43〜128 文字の英数字 +-._~)を生成する code_challenge = BASE64URL(SHA256(code_verifier))を計算する- PAR または認可リクエストに
code_challengeとcode_challenge_method=S256を含める - トークン交換時に
code_verifierを送信する
トークン交換
認可コードを受け取ったら、アプリ内から直接トークンエンドポイントを呼び出します。
curl -X POST "https://id.mock.klon.you/api/oidc/v1/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=<AUTHORIZATION_CODE>" \
-d "redirect_uri=https://app.example.com/callback" \
-d "client_id=<CLIENT_ID>" \
-d "code_verifier=<CODE_VERIFIER>"
Public Client ではクライアント認証が不要なため、client_id のみで呼び出します。
リフレッシュトークン
Public Client にもリフレッシュトークンが発行されます。
curl -X POST "https://id.mock.klon.you/api/oidc/v1/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=<REFRESH_TOKEN>" \
-d "client_id=<CLIENT_ID>"
実装上の要件とプラクティス
システムブラウザを使用する
認可リクエストは、アプリ内の WebView ではなく システムブラウザ(ASWebAuthenticationSession(iOS)や Chrome Custom Tabs(Android))を使って開いてください。
RFC 8252 では、ネイティブアプリが認可リクエストをシステムブラウザ経由で行うことを求めています。システムブラウザを利用すると、以下のメリットがあります。
- ユーザーが IdP の既存セッション(Cookie)を再利用でき、再ログインが不要になる
- パスワードマネージャーや生体認証との連携が機能する
- アプリが認証情報を傍受できないため、セキュリティが向上する
アプリ内の WebView(WKWebView、WebView 等)を認可リクエストに使用しないでください。WebView ではアプリがユーザーの入力やセッション Cookie を傍受できるため、RFC 8252 で非推奨とされています。
ただし、Web サービスの表示を目的とした WebView 内での認可フローはセッションバインドの仕組みで対応します。
redirect_uri の設計
redirect_uri にはプラットフォームの仕組みに応じて、以下のいずれかの形式を使用できます。
| 方式 | 形式の例 | 特徴 |
|---|---|---|
| App Links (Android) | https://app.example.com/callback | ドメイン所有権の検証があり、他のアプリによる横取りが困難。推奨 |
| Universal Links (iOS) | https://app.example.com/callback | ドメイン所有権の検証があり、セキュリティ上有利。ただし下記の注意を参照 |
| カスタムスキーム | com.example.myapp://callback | セットアップが容易だが、他のアプリが同じスキームを登録できるリスクがある |
App Links / Universal Links を使用する場合、redirect_uri は通常の https:// URL となるため、RP のサーバーサイドコールバックと同じ見た目になりますが、OS がアプリに直接ルーティングします。
カスタムスキームを使用する場合は、他のアプリとの衝突を避けるためリバースドメイン形式(com.example.myapp://)を推奨します。
:::caution iOS での Universal Links
ASWebAuthenticationSession を使用する場合、iOS のバージョンによっては Universal Links が期待どおりに動作しないことがあります。iOS では PKCE と併用したカスタムスキームが現実的な選択肢になる場合があります。対象の iOS バージョンに応じて動作を検証してください。
:::
PKCE による認可コード横取り防止
ネイティブアプリでは、コールバック URI を他のアプリが横取りするリスクがあります(特にカスタムスキーム使用時)。PKCE はこの攻撃を防ぐための最も重要な対策であり、Public Client では必須です。
code_verifier は暗号論的に安全な乱数から生成し、十分なエントロピー(256 ビット以上を推奨)を確保してください。
nonce による ID トークンのリプレイ防止
認可リクエストに nonce を含め、受け取った id_token の nonce クレームが一致することを検証してください。
state による CSRF 対策
認可リクエストごとにランダムな state 値を生成し、コールバック時に一致を検証してください。
トークンの安全な保管
- アクセストークン・リフレッシュトークンは、OS が提供するセキュアストレージ(iOS の Keychain、Android の EncryptedSharedPreferences 等)に保管してください
- トークンをログ出力やクラッシュレポートに含めないでください
2 回目以降のログイン
ユーザーが過去に同意済みで、要求する権限に変更がない場合、KLON は同意画面をスキップして自動的に認可コードを発行します。ただし、初回アクセス時は必ずアカウント確認画面が表示されます。
関連ページ
- OIDC 全体像は OIDC の概要
- 認可リクエストの詳細は 認可リクエスト
- トークンエンドポイントの詳細は トークン
- クライアント設定は クライアント設定
- WebView 内の Web サービス連携は ネイティブアプリ WebView 内の Web サービスログイン