mcpField
A
auth0-maui

auth0-maui

github.com/auth0安全55223 次安装1 天前更新
代码仓库

关于 auth0-maui

auth0-maui 是为 .NET MAUI 应用接入 Auth0 OIDC 登录和退出的技能,涵盖 iOS、Android、macOS 和 Windows,并指导 PKCE 流程及刷新令牌会话恢复。

主要功能

  1. 01基于 PKCE 的 OIDC 登录与退出
  2. 02通过 WebAuthenticator 使用系统浏览器认证
  3. 03刷新令牌存储与会话恢复
  4. 04平台专属回调配置

适用场景

  1. 01为 .NET MAUI 应用添加 Auth0 认证
  2. 02在应用重启后恢复登录会话
  3. 03配置 Android 和 Windows 回调处理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/auth0/agent-skills --skill auth0-maui

安装后在 Claude Code 中输入/auth0-maui确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api.md
integration.md
setup.md

详细介绍

auth0-maui 集成

为面向 iOS、Android、macOS 和 Windows 的 .NET MAUI 应用添加 Auth0 身份验证。此技能集成 Auth0.OidcClient.MAUI NuGet 包,该包通过 MAUI 的 WebAuthenticator 使用系统浏览器,实现基于 OIDC 和 PKCE 的安全登录与注销流程。

**Agent 指令:**提供 SDK 设置说明前,请运行以下命令获取最新的 MAUI 发布版本:

gh api repos/auth0/auth0-oidc-client-net/releases --jq '[.[] | select(.tag_name | startswith("maui-")) | .tag_name | ltrimstr("maui-")] | .[0]'

在所有依赖项行中使用返回的版本,而不是下方的任何硬编码版本。

前提条件

  • .NET 8.0 SDK 或更高版本
  • Visual Studio 2022 (17.8+) 并安装 MAUI 工作负载,或支持 MAUI 的 JetBrains Rider
  • 对于 iOS:安装了 Xcode 15+ 的 macOS
  • 对于 Android:Android SDK API 33+ (net8.0) 或 API 34+ (net9.0)
  • 对于 Windows:Windows 10 (10.0.19041.0)+
  • 已配置 Native 应用程序的 Auth0 帐户
  • Node.js 20+(用于 Auth0 CLI 自动化设置)

不要用于以下场景

使用场景推荐技能
ASP.NET Core 服务端 Web 应用auth0-aspnetcore-authentication
ASP.NET Core Web API(JWT 验证)auth0-aspnetcore-api
React Native 移动应用auth0-react-native
仅适用于 iOS 的 Swift 应用auth0-swift
仅适用于 Android 的 Kotlin 应用auth0-android
Expo React Native 应用auth0-expo

快速入门工作流

**Agent 指令:**开始之前,检查用户的项目:

  1. 从 .csproj 文件(TargetFrameworks)中确定 .NET 版本
  2. 检查是否已有身份验证实现 — 搜索现有的登录/注销处理程序,如果找到则接入
  3. 记录项目的命名空间和目录约定
  4. 查找现有的 Auth0Client 或 Auth0ClientOptions 用法,避免重复配置
  1. 安装 SDK:dotnet add package Auth0.OidcClient.MAUI
  2. 配置 Auth0:有关自动或手动配置,请参阅设置指南。
  3. 集成身份验证:添加 Auth0Client 实例化,并将登录/注销操作连接到 UI 操作。
    • **重要:**始终设置 Scope = "openid profile email offline_access" — offline_access 作用域是获取刷新令牌以静默续订令牌所必需的。
  4. 使用 SecureStorage 持久化令牌:登录后,使用 await SecureStorage.Default.SetAsync("refresh_token", loginResult.RefreshToken) 存储刷新令牌。应用启动时,使用 RefreshTokenAsync 恢复会话。注销时,使用 SecureStorage.Default.Remove("refresh_token") 清除令牌。
  5. 注册 URL 方案:配置特定于平台的回调处理:
    • Android:创建带有自定义方案(例如 myapp)IntentFilter 的 WebAuthenticatorActivity
    • Windows(需要两个步骤):(1) 将 <uap:Extension Category="windows.protocol"><uap:Protocol Name="myapp"/></uap:Extension> 添加到 Platforms/Windows/Package.appxmanifest,并且 (2) 在 Platforms/Windows/App.xaml.cs 中调用 Activator.Default.CheckRedirectionActivation()
    • iOS/macOS:无需额外配置
  6. 构建并验证:dotnet build

**Agent 指令:**编写 Auth0Client 配置时:

  • 务必在 Scope 字符串中包含 offline_access — 如果不包含,则不会返回刷新令牌,访问令牌过期时用户必须每次都重新进行身份验证。
  • 务必实现令牌持久化:登录后使用 SecureStorage.Default.SetAsync("refresh_token", ...),并在应用启动时使用 SecureStorage.Default.GetAsync("refresh_token") 静默恢复会话。
  • 注销时,使用 SecureStorage.Default.Remove("refresh_token") 清除存储的令牌。
  • 务必创建/更新 Platforms/Windows/Package.appxmanifest 以注册自定义 URL 方案协议。否则,Windows 在身份验证后不会拦截回调 URL。在 <Application> 节点的 <Extensions> 元素内添加 <uap:Extension Category="windows.protocol"><uap:Protocol Name="myapp"/></uap:Extension>。
  • 务必在 Platforms/Windows/App.xaml.cs 的构造函数中,将 CheckRedirectionActivation() 添加为第一行,放在 InitializeComponent() 之前。

编写配置和代码后,验证构建是否成功:

dotnet build

如果构建失败,请尝试修复问题。失败 5-6 次后,请向用户寻求帮助。

回调 URL 配置

MAUI SDK 使用自定义 URL 方案处理回调。默认模式为:

myapp://callback

与使用 https://{domain}/{platform}/{bundleId}/callback 或 {bundleId}.auth0://{domain}/ios/{bundleId}/callback 模式的其他 Auth0 原生 SDK 不同,MAUI 使用更简单的自定义方案 方式。你可以自定义方案(例如 com.mycompany.myapp://callback)。无论选择哪种方案,都必须:

  1. 在 Auth0 Dashboard 的 Allowed Callback URLs 和 Allowed Logout URLs 下注册
  2. 在特定于平台的回调处理程序中配置(Android IntentFilter、Windows Package.appxmanifest)
  3. 在 Auth0ClientOptions.RedirectUri 和 Auth0ClientOptions.PostLogoutRedirectUri 中设置

**注意:**对于生产应用,请使用反向域名方案(例如 com.yourcompany.yourapp://callback),以降低 URL 方案劫持的风险。

完成标准

  • 已安装 Auth0.OidcClient.MAUI 包
  • 已配置 Auth0Client,包含 Domain、ClientId,以及包含 offline_access 的 Scope
  • 已在 Android(WebAuthenticatorCallbackActivity)和 Windows(Package.appxmanifest)上注册 URL scheme
  • 已将回调 URL(myapp://callback)添加到 Auth0 Dashboard 的 Allowed Callback URLs 和 Allowed Logout URLs
  • 登录/登出流程正常运行
  • 登录后通过 SecureStorage.Default.SetAsync 持久化刷新令牌
  • 已在应用启动时通过 SecureStorage.Default.GetAsync + RefreshTokenAsync 实现会话恢复
  • 构建成功且无错误
  • 已在实体设备或模拟器/仿真器上测试

详细文档

  • 设置指南 — Auth0 租户配置、SDK 安装、特定平台的回调设置
  • 集成模式 — 登录/登出流程、令牌刷新、用户资料、错误处理、MVVM 模式
  • API 参考与测试 — 完整的 Auth0ClientOptions 参考、声明、测试清单、故障排查

常见错误

错误修复方法
未在 Auth0 Dashboard 中将应用类型设为 Native在 Dashboard 设置中将应用类型更改为“Native”
Auth0 Dashboard 中缺少回调 URL将 myapp://callback(或你的 scheme)添加到 Allowed Callback URLs 和 Allowed Logout URLs
Android:缺少 WebAuthenticatorCallbackActivity创建带有 [IntentFilter] 且与回调 scheme 匹配的 activity 类
Windows:未调用 CheckRedirectionActivation()在 Windows App.xaml.cs 的开头、InitializeComponent() 之前添加 Activator.Default.CheckRedirectionActivation()
Domain 使用了 https:// 前缀Domain 应仅为主机名(例如 tenant.auth0.com,而不是 https://tenant.auth0.com)
未请求用于刷新令牌的 offline_access scope在 Auth0ClientOptions 的 Scope 中添加 offline_access 以获取刷新令牌
RedirectUri/PostLogoutRedirectUri 与 Dashboard 不匹配确保 URI(scheme + 路径)与 Auth0 Dashboard 中配置的内容完全一致
未在 Android/Windows 上注册 URL scheme在特定平台的配置中注册自定义 URL scheme(参见平台设置步骤)
以纯文本形式存储令牌使用 MAUI Essentials 中的 SecureStorage 持久化刷新令牌

测试说明

Agent 指令: 提醒用户除模拟器/仿真器外,还要在实体设备上测试。部分 WebAuthenticator 行为(系统浏览器集成、URL scheme 拦截)在实体设备和模拟器上可能有所不同。发布前,请在真实硬件上测试完整的登录 → 回调 → 令牌流程。

测试清单:

  • 登录流程:打开系统浏览器 → 完成身份验证 → 返回应用
  • 登出流程:打开浏览器 → 清除会话 → 返回应用
  • 令牌刷新:使用存储的刷新令牌调用 RefreshTokenAsync,确保正常运行
  • 取消:用户取消登录 → 应用妥善处理 UserCancel
  • 实体设备:在真实 iOS/Android 设备上测试(不只是模拟器)
  • 离线:验证应用重启后令牌刷新正常运行
  • 多平台:至少在一个移动平台(iOS 或 Android)和 Windows 上测试

相关技能

  • auth0-aspnetcore-authentication — ASP.NET Core 服务端 Web 应用
  • auth0-aspnetcore-api — 使用 JWT 验证的 ASP.NET Core Web API
  • auth0-android — Android 原生 Kotlin 应用
  • auth0-swift — iOS/macOS Swift 应用
  • auth0-react-native — React Native 移动应用
  • auth0-net-android-ios — .NET Android/iOS(非 MAUI)

快速参考

using Auth0.OidcClient;

// Initialize client
var client = new Auth0Client(new Auth0ClientOptions
{
    Domain = "YOUR_AUTH0_DOMAIN",
    ClientId = "YOUR_AUTH0_CLIENT_ID",
    RedirectUri = "myapp://callback",
    PostLogoutRedirectUri = "myapp://callback",
    Scope = "openid profile email offline_access"
});

// Login — opens system browser
var loginResult = await client.LoginAsync();
if (!loginResult.IsError)
{
    var user = loginResult.User;
    var accessToken = loginResult.AccessToken;
    var idToken = loginResult.IdentityToken;
    var refreshToken = loginResult.RefreshToken;

    // Access user claims
    var name = user.FindFirst("name")?.Value;
    var email = user.FindFirst("email")?.Value;

    // Persist refresh token securely for session restoration
    if (!string.IsNullOrEmpty(refreshToken))
        await SecureStorage.Default.SetAsync("refresh_token", refreshToken);
}

// Logout — clears Auth0 session and stored tokens
await client.LogoutAsync();
SecureStorage.Default.Remove("refresh_token");

// Restore session on app startup (no user interaction needed)
var savedToken = await SecureStorage.Default.GetAsync("refresh_token");
if (!string.IsNullOrEmpty(savedToken))
{
    var refreshResult = await client.RefreshTokenAsync(savedToken);
    if (!refreshResult.IsError)
    {
        var newAccessToken = refreshResult.AccessToken;
        // Update stored token if rotated
        if (!string.IsNullOrEmpty(refreshResult.RefreshToken))
            await SecureStorage.Default.SetAsync("refresh_token", refreshResult.RefreshToken);
    }
    else
    {
        // Refresh failed — clear and require re-login
        SecureStorage.Default.Remove("refresh_token");
    }
}

// Get user info from /userinfo endpoint
var userInfo = await client.GetUserInfoAsync(accessToken);

// Login with extra parameters (organization, audience, connection)
var orgLogin = await client.LoginAsync(new { organization = "org_abc123" });
var apiLogin = await client.LoginAsync(new { audience = "https://my-api.example.com" });
Android 回调 Activity(必需)
[Activity(NoHistory = true, LaunchMode = LaunchMode.SingleTop, Exported = true)]
[IntentFilter(new[] { Intent.ActionView },
    Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
    DataScheme = CALLBACK_SCHEME)]
public class WebAuthenticatorActivity : Microsoft.Maui.Authentication.WebAuthenticatorCallbackActivity
{
    const string CALLBACK_SCHEME = "myapp";
}
Windows 平台设置(必需 — 两个步骤)

步骤 1:在 Platforms/Windows/Package.appxmanifest 中注册协议:

<Extensions>
  <uap:Extension Category="windows.protocol">
    <uap:Protocol Name="myapp"/>
  </uap:Extension>
</Extensions>

步骤 2:在 Platforms/Windows/App.xaml.cs 中处理重定向:

// In Platforms/Windows/App.xaml.cs
public App()
{
    if (Auth0.OidcClient.Platforms.Windows.Activator.Default.CheckRedirectionActivation())
        return;
    this.InitializeComponent();
}

References

评论

支持 Markdown