Capacitor アプリで Okta にサインインするには、 OIDC ネイティブアプリケーション Okta Admin Consoleで、次のようなサインインリダイレクトURIを登録します: com.example.app://oauth/okta、システムブラウザでPKCEを使った認可 code フローを実行します。次に @capgo/capacitor-social-login issuerとclient IDでOktaを一度設定したら、あとは呼び出すだけです SocialLogin.login({ provider: 'oauth2', options: { providerId: 'okta' } }).
このガイドでは、Oktaアプリの統合、認可サーバーのポリシー、iOS・Android・Web向けの code プラグイン、トークンのリフレッシュ、ユーザープロファイル、ログアウト、よく発生するOktaのエラーについて解説します。2026年10月時点の Capacitor 8を対象としています。
必要なもの
- アプリ統合を作成する管理者権限を持つOkta org(Workforce IdentityまたはCustomer Identity)。
- Capacitor 8のアプリ。
- 使用する Capacitor
appId、これをリダイレクトスキームとして再利用します。 - オプションで、Oktaのアクセストークンを検証するバックエンドの API。
Capacitor アプリでのOktaログインの仕組み
アプリがパスワード入力フォームを表示することはありません。セキュアなブラウザでOktaのサインインページを開き、OktaがMFAとポリシーを処理したうえで、code を付けてアプリにリダイレクトします。アプリは code とPKCE verifierをトークンと交換します。
| プラットフォーム | ブラウザ | 設定内容 |
|---|---|---|
| iOSと | ASWebAuthenticationSession |
対象外 Info.plist |
| Androidでは | Chrome Custom Tabs と androidUseCustomTabs: true (デフォルトは WebView) |
リダイレクトスキーム用の Intent フィルター |
| Web | ポップアップまたはリダイレクト | CORS 用の信頼済みオリジン |
Android では Custom Tabs を推奨します。Okta Verify、FastPass、passkey は埋め込み WebView よりシステムブラウザで動作が安定し、SSO クッキーが Chrome と共有されます。
ステップ 1: Okta アプリ統合の作成
- Okta Admin Console で、 Applications > Applications > Create App Integration.
- 選択: OIDC - OpenID Connect と ネイティブアプリケーション.
- 名前を指定し、その下に グラントタイプ keep Code 認可 にチェックを入れます リフレッシュトークン ユーザーをサインインしたままにする場合。
- サインイン リダイレクト URI:
com.example.app://oauth/okta. 追加https://app.example.com/auth/callbackWebビルドを配信する場合。 - サインアウト リダイレクト URI:
com.example.app://oauth/logout(必要に応じてWeb URLも含む)。 - 割り当て: アプリを使用できるユーザーを選択します。割り当てられていないユーザーはサインイン時にエラーになります。
- 保存して、次をコピーします クライアントID. の下で クライアント資格情報の場合、クライアント認証は なし と PKCEを必須に 設定する必要があります。
Oktaでは、ネイティブリダイレクトURIにリバースドメイン形式のプライベートユーススキームを使用する必要があります。Bundle IDまたはApplication IDが適しています。
Authorization Serverを確認してください。
以下に移動します: セキュリティ > API > 認証サーバー. ほとんどのセットアップでは default カスタム認証サーバー、イシューア https://your-org.okta.com/oauth2/default.
| イシューア | 使用シーン |
|---|---|
https://your-org.okta.com/oauth2/default (カスタム) |
独自の API がアクセストークンを検証する場合、カスタムスコープやクレームが必要な場合 |
https://your-org.okta.com (組織) |
ID トークンのみが必要、または Okta API を呼び出す場合 |
サーバーの アクセスポリシー タブを開きます。アプリ(または All clients)に割り当てられたポリシーに、次を許可するルールが必要です: 認可 Code grant と リフレッシュトークン 使用する場合です。ルールが不足していると「Policy evaluation failed for this request」が発生します。
Web 用の Trusted Origins
同じ code を Web で実行する場合は、Web オリジンを以下に追加してください: セキュリティ > API > 信頼済みオリジン を使用して CORS チェックされている必要があります。これがないと、ブラウザがトークンリクエストをブロックします。
ステップ 2: プラグインのインストール
bun add @capgo/capacitor-social-login
bunx cap sync
Okta が唯一のプロバイダーなら、同梱のソーシャル SDK を以下でオフにしてください: capacitor.config.ts:
plugins: {
SocialLogin: {
providers: { google: false, facebook: false, apple: false, twitter: false },
},
},
ステップ 3: Android の redirect intent filter を追加する
では android/app/src/main/AndroidManifest.xml、内部の MainActivity アクティビティ:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.example.app" android:host="oauth" />
</intent-filter>
MainActivity を維持する必要があります android:launchMode="singleTask"、これは Capacitor のデフォルト設定です。これにより、リダイレクトが実行中のアクティビティに届きます。
ステップ 4: Okta を初期化する
import { Capacitor } from '@capacitor/core';
import { SocialLogin } from '@capgo/capacitor-social-login';
const OKTA_ISSUER = 'https://your-org.okta.com/oauth2/default';
const isWeb = Capacitor.getPlatform() === 'web';
export async function initAuth() {
await SocialLogin.initialize({
oauth2: {
okta: {
appId: 'YOUR_OKTA_CLIENT_ID',
authorizationBaseUrl: `${OKTA_ISSUER}/v1/authorize`,
accessTokenEndpoint: `${OKTA_ISSUER}/v1/token`,
resourceUrl: `${OKTA_ISSUER}/v1/userinfo`,
redirectUrl: isWeb
? 'https://app.example.com/auth/callback'
: 'com.example.app://oauth/okta',
scope: 'openid profile email offline_access',
pkceEnabled: true,
logoutUrl: `${OKTA_ISSUER}/v1/logout`,
postLogoutRedirectUrl: isWeb
? 'https://app.example.com/'
: 'com.example.app://oauth/logout',
androidUseCustomTabs: true,
},
},
});
}
より短い代替案: を設定し issuerUrl: OKTA_ISSUER し、エンドポイントURLを削除します。プラグインはを読み込みます /.well-known/openid-configuration を埋め込みます。Ionic Auth Connect から移行するチームは SocialLoginAuthConnect を使用して、 okta プリセット (issuer, clientId, redirectUrl) を使用できます。 移行ガイド.
ステップ 5: サインインしてプロフィールを取得する
import { SocialLogin } from '@capgo/capacitor-social-login';
export async function signInWithOkta() {
try {
const { result } = await SocialLogin.login({
provider: 'oauth2',
options: { providerId: 'okta' },
});
const profile = result.resourceData as {
sub: string;
email?: string;
name?: string;
preferred_username?: string;
} | null;
return {
accessToken: result.accessToken?.token,
idToken: result.idToken,
refreshToken: result.refreshToken,
scopes: result.scope,
profile,
};
} catch (error: any) {
if (error?.code === 'USER_CANCELLED') return null;
throw error;
}
}
resourceData が返すJSONを保持します。 /userinfo エンドポイントでカバーされており、追加のリクエストなしでプロファイルを取得できます。ID トークンのクレームを表示用に読み取るには、 SocialLogin.decodeIdToken({ idToken })この呼び出しでは署名の検証は行われません。
知っておきたいログインオプション:
loginHintユーザー名を自動入力します。prompt: 'login'Oktaのセッションが有効でも、再認証を強制します。additionalParameters: { idp: '0oa...' }Oktaで設定された特定のアイデンティティプロバイダーへ直接ルーティングします。
Webでは flow: 'redirect'、呼び出し SocialLogin.handleRedirectCallback() コールバックページで交換を完了します。
ステップ 6: API で Okta トークンを検証する
import { createRemoteJWKSet, jwtVerify } from 'jose';
const ISSUER = 'https://your-org.okta.com/oauth2/default';
const jwks = createRemoteJWKSet(new URL(`${ISSUER}/v1/keys`));
export async function verifyOktaAccessToken(token: string) {
const { payload } = await jwtVerify(token, jwks, {
issuer: ISSUER,
audience: 'api://default', // the Audience value of your authorization server
});
return payload; // payload.uid is the Okta user ID, payload.sub the login
}
認可サーバーの 設定 タブでオーディエンスを確認してください。API 内で、組織の認可サーバーからのアクセストークンを検証しないでください。Okta はこれをサポートしていません。
ステップ 7: トークンをリフレッシュする
import { SocialLogin } from '@capgo/capacitor-social-login';
export async function ensureFreshOktaToken() {
const { isLoggedIn } = await SocialLogin.isLoggedIn({ provider: 'oauth2', providerId: 'okta' });
if (!isLoggedIn) {
await SocialLogin.refresh({ provider: 'oauth2', options: { providerId: 'okta' } });
}
const { accessToken } = await SocialLogin.getAuthorizationCode({ provider: 'oauth2', providerId: 'okta' });
return accessToken;
}
リフレッシュトークンが期限切れまたは失効している場合、 refresh は拒否します。これをキャッチして、ユーザーを signInWithOkta().
チェック: リフレッシュトークン アプリ統合のセクション。 「使用のたびにトークンをローテーション」」を有効にすると、各リフレッシュで新しいリフレッシュトークンが返され、古いトークンは短い猶予期間後に使えなくなります。プラグインは保存しているコピーを自動で置き換えます。リフレッシュトークンを自分で保持する場合(たとえば Keychain 経由で @capgo/capacitor-native-biometric setData)、次を使用して SocialLogin.refreshToken({ provider: 'oauth2', providerId: 'okta', refreshToken }) 返された値を保存してください。
ステップ 8: サインアウトする
await SocialLogin.logout({ provider: 'oauth2', providerId: 'okta' });
プラグインは保存しているトークンをクリアし、次に /v1/logout を使用して id_token_hint と post_logout_redirect_uriを開きます。Okta はセッションを終了し、サインアウト URI にリダイレクトします。この URI はアプリ統合に登録されている必要があります。モバイルでは、ログアウトページがシステムブラウザで開かれます。
リフレッシュトークンのサーバー側での失効も行うには、Okta の /v1/revoke エンドポイントをログアウト前にバックエンドまたはアプリから呼び出します。 トークン失効ガイド でパターンを確認してください。
トラブルシューティング
| エラー | 原因 | 解決策 |
|---|---|---|
invalid_request: The 'redirect_uri' parameter must be a Login redirect URI in the client app settings |
リダイレクトが登録されていません | Sign-in redirect URIs に正確な URI を追加してください |
User is not assigned to the client application |
割り当てが不足しています | Assignments でユーザーまたはグループを割り当ててください |
Policy evaluation failed for this request |
このクライアントまたはグラントにはアクセスポリシールールがありません | 認可サーバーにポリシーとルールを追加します |
invalid_client トークンエンドポイントで |
アプリが Web または SPA タイプであるか、認証方法が None 以外であること | クライアント認証が None のネイティブアプリを使用します |
| リフレッシュトークンなし | Refresh Token grantが無効、 offline_access 存在しない、またはルールでブロックされている |
grantを有効化し、scopeを追加してルールで許可してください |
| API が不正なissuerのトークンを拒否します | トークンが組織のサーバーから発行されました | カスタム認可サーバーのissuerを使用してください |
Web: CORSエラーが発生 /v1/token |
Originが信頼されていません | CORSを有効にしたTrusted Originを追加してください |
| Androidでログイン後にブラウザのままになる | Intent filterの不一致 | スキームとホストを以下に一致させます redirectUrl |
オンにする logsEnabled: true デバッグ中はプロバイダー設定で、ネイティブログで認可URLとトークンレスポンスを確認できるようにします。
Okta の変更をロールアウトする
エンタープライズ顧客はリリース後にポリシーやクレームを変更することがよくあります。スコープ、クレーム処理、エラー画面などのクライアントサイドの変更は、 Capgo Live Updates による配信が可能で、ストアのフルレビューは不要です。ネイティブ部分(インテントフィルター、新しいスキーム)は引き続き新しいビルドが必要です。