跳转至正文

如何使用 Capacitor 通过 Okta 登录

将 Okta 接入 Capacitor 8 应用,使用 OIDC 和 PKCE:创建 Native 应用集成、设置重定向 URI、refresh token、登出,并解决 Okta 报错。

通过 PKCE 从 Capacitor 移动应用打开的 Okta 登录页

要在 Capacitor app 中使用 Okta 登录,请创建一个 OIDC 原生应用 在 Okta 管理控制台中,注册一个登录重定向 URI,例如 com.example.app://oauth/okta,并在系统浏览器中运行带有 PKCE 的授权 code 流程。使用 @capgo/capacitor-social-login ,你只需配置一次 Okta 的 issuer 和 client ID,然后调用 SocialLogin.login({ provider: 'oauth2', options: { providerId: 'okta' } }).

本指南涵盖 Okta 应用集成、授权服务器策略、用于 iOS、Android 和 Web 的插件 code、token 刷新、用户资料、登出,以及最常见的 Okta 错误。目标为 2026 年 10 月版本的 Capacitor 8。

准备工作

  • 一个具有管理员权限的 Okta 组织(Workforce Identity 或 Customer Identity),用于创建应用集成。
  • 一个 Capacitor 8 应用。
  • 您的 Capacitor appId,稍后将其用作重定向 scheme。
  • 可选:一个用于验证 Okta access token 的后端 API。

Okta 登录在 Capacitor 应用中的工作原理

您的应用不会显示密码表单。它会在安全浏览器中打开 Okta 登录页面,由 Okta 处理 MFA 和策略,然后携带 code 重定向回您的应用。应用随后使用 code 加上 PKCE verifier 换取 token。

平台 浏览器 您需要配置的内容
iOS ASWebAuthenticationSession 在 Info.plist
Android 使用 Chrome Custom Tabs 和 androidUseCustomTabs: true (默认使用 WebView) 重定向方案的 Intent 过滤器
Web 端 弹窗或重定向 CORS 可信源

在 Android 上优先使用 Custom Tabs。Okta Verify、FastPass 和 passkeys 在系统浏览器中的表现优于嵌入式 WebView,且 SSO Cookie 可与 Chrome 共享。

步骤 1:创建 Okta 应用集成

  1. 在 Okta 管理控制台中,前往 应用程序 > 应用程序 > 创建应用集成.
  2. 选择 OIDC - OpenID Connect 以及 原生应用.
  3. 命名后,在下方 授权类型 保留 Code 授权 并勾选 刷新令牌 如果希望用户保持登录状态。
  4. 登录重定向 URI: com.example.app://oauth/okta。添加 https://app.example.com/auth/callback 如果你发布 Web 构建。
  5. 登出重定向 URI: com.example.app://oauth/logout (如有需要,还包括 Web URL)。
  6. 分配:选择谁可以使用该应用。未被分配的用户在登录时会收到错误提示。
  7. 保存,然后复制 客户端 ID。在 客户端凭证中,客户端身份验证应设为 无 以及 需要 PKCE 应处于开启状态。

Okta 要求使用反向域名格式的私有用途 scheme 作为原生重定向 URI。您的 bundle ID 或应用 ID 即可满足此要求。

检查授权服务器

前往 安全 > API > 授权服务器。大多数配置使用 default 自定义授权服务器、签发者 https://your-org.okta.com/oauth2/default.

签发者 适用场景
https://your-org.okta.com/oauth2/default (自定义) 当您自己的 API 验证访问令牌,且需要自定义 scope 或 claims 时
https://your-org.okta.com (组织) 仅需 ID token 或调用 Okta API

打开服务器的 访问策略 选项卡。必须为您的应用(或所有客户端)分配一条策略,其中的规则允许 Code 授权 授权,并且 刷新令牌 (如果您使用了它)。缺少规则会导致“Policy evaluation failed for this request”错误。

Web 可信来源

如果您在 Web 上运行相同的 code,请在以下位置添加您的 Web 来源: 安全 > API > 可信来源 配合 CORS 已检查。如果没有它,浏览器会阻止 token 请求。

第 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 重定向 intent filter

在 android/app/src/main/AndroidManifest.xml,位于 MainActivity activity 中:

<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 的默认值,以便重定向到达正在运行的 activity。

步骤 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 并移除 endpoint 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 保存由 /userinfo 端点返回的 JSON,因此无需再次请求即可获取用户资料。若要读取 ID token 的 claims 用于展示,请使用 SocialLogin.decodeIdToken({ idToken })。该调用不会验证签名。

值得了解的登录选项:

  • loginHint 自动填充用户名。
  • prompt: 'login' 即使 Okta 会话仍有效,也会强制重新认证。
  • additionalParameters: { idp: '0oa...' } 直接跳转到 Okta 中配置的指定身份提供商。

在 Web 端使用 flow: 'redirect',调用 SocialLogin.handleRedirectCallback() 在回调页完成交换。

第 6 步:在您的 API 上验证 Okta token

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
}

在授权服务器的 设置 选项卡中找到 audience。请勿在您的 API 中验证来自组织授权服务器的 access token。Okta 不支持此操作。

步骤 7:刷新 token

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 token 已过期或被吊销, refresh 会拒绝请求。捕获该错误并将用户重定向回 signInWithOkta().

查看 刷新令牌 应用集成部分。使用 每次使用后轮换令牌,每次刷新都会返回一个新的刷新令牌,旧令牌在短暂的宽限期后失效。插件会自动替换其存储的副本。如果您自行持有刷新令牌(例如通过 Keychain 存储) @capgo/capacitor-native-biometric setData), 使用 SocialLogin.refreshToken({ provider: 'oauth2', providerId: 'okta', refreshToken }) 并保存返回的值。

第 8 步:退出登录

await SocialLogin.logout({ provider: 'oauth2', providerId: 'okta' });

该插件会清除已存储的 token,然后打开 /v1/logout 配合 id_token_hint 以及 post_logout_redirect_uri。Okta 会结束会话并重定向到你的注销 URI,该 URI 必须列在应用集成中。在移动端,注销页面会在系统浏览器中打开。

若要在服务端同时撤销 refresh token,请调用 Okta 的 /v1/revoke 端点(由你的后端或应用在退出登录前调用)。请参阅我们的 token 撤销指南 了解具体做法。

故障排除

错误 原因 修复
invalid_request: The 'redirect_uri' parameter must be a Login redirect URI in the client app settings 重定向未注册 请将完整 URI 添加到 Sign-in redirect URIs
User is not assigned to the client application 缺少分配 请在 Assignments 中分配用户或组
Policy evaluation failed for this request 该客户端或授权类型没有访问策略规则 请在授权服务器上添加策略和规则
invalid_client 在 token endpoint 处 应用类型为 Web 或 SPA,或认证方式不为 None 请使用 client authentication 为 None 的 Native app
缺少 Refresh Token Refresh Token 授权已关闭, offline_access 缺失或被规则拦截 启用授权,添加 scope,并在规则中允许
API 因 issuer 错误拒绝 Token Token 来自组织服务器 使用自定义 Authorization Server 的 issuer
Web:出现 CORS 错误 /v1/token Origin 不受信任 添加支持 CORS 的 Trusted Origin
Android 登录后仍停留在浏览器 Intent filter 不匹配 将 scheme 和 host 匹配为 redirectUrl

开启 logsEnabled: true 调试时在 provider 配置中开启,以便在 native logs 中查看 authorize URL 和 token 响应。

发布 Okta 变更

企业客户在上线后经常会更改策略或 claims。像 scopes、claim 处理或错误页面这类客户端变更,可以通过 Capgo 实时更新 发布,而无需经过完整的应用商店审核。但 native 部分(intent filter、新 scheme)仍需重新构建。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。