关于 auth0-wpf
面向 .NET WPF 桌面应用的 Auth0 OIDC 登录与退出集成技能,指导编码 Agent 配置 WebView2、回调和令牌,并验证构建。
主要功能
- 01通过 WebView2 登录 Auth0
- 02OIDC 授权码流程与 PKCE
- 03集成登录和退出
- 04回调 URL 配置指导
- 05令牌刷新与个人资料指导
- 06构建与测试检查清单
适用场景
- 01为 WPF 应用添加 Auth0 身份验证
- 02配置登录和退出处理程序
- 03为 Auth0 原生应用设置回调 URL
- 04规划令牌刷新和个人资料访问
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ auth0/ agent-skills --skill auth0-wpf安装后在 Claude Code 中输入/auth0-wpf确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api.mdintegration.mdsetup.md详细介绍
Auth0 WPF 集成
为 WPF(Windows Presentation Foundation)桌面应用添加 Auth0 身份验证。此技能集成了 Auth0.OidcClient.WPF NuGet 包,该包使用 WebView2 在弹出窗口中显示 Auth0 登录页面,以通过 PKCE 实现安全的基于 OIDC 的登录和登出流程。
该 SDK 通过在 WPF Window 中托管的 WebView2 控件内打开 Auth0 Universal Login 页面来执行 WebAuth(使用 PKCE 的 OIDC 授权码流程)。与需要在 Info.plist 或 AndroidManifest.xml 中注册 URL scheme 的原生移动 SDK 不同,WPF SDK 完全通过 WebView2 导航事件处理回调,无需自定义 URL 类型或协议处理程序。
**Agent 指令:**在提供 SDK 设置说明之前,运行以下命令获取最新发布版本:
gh api repos/auth0/auth0-oidc-client-net/releases --jq '[.[] | select(.tag_name | startswith("wpf-")) | .tag_name | ltrimstr("wpf-")] | .[0]'在所有依赖项行中使用返回的版本,不要使用下方任何硬编码版本。
先决条件
- .NET 6.0 SDK 或更高版本(WPF 需要 Windows)
- 安装了 .NET 桌面开发工作负载的 Visual Studio 2022 或 JetBrains Rider
- Windows 10 或更高版本
- Microsoft Edge WebView2 Runtime(Windows 11 已内置,可在 Windows 10 上安装)
- 已配置 Native 应用程序的 Auth0 账户
- Node.js 20+(用于 Auth0 CLI 自动化设置)
不适用场景
| 使用场景 | 推荐技能 |
|---|---|
| .NET MAUI 跨平台应用 | auth0-maui |
| Windows Forms 桌面应用 | auth0-winforms |
| ASP.NET Core 服务端 Web 应用 | auth0-aspnetcore-authentication |
| ASP.NET Core Web API(JWT 验证) | auth0-aspnetcore-api |
| 仅限 iOS 的 Swift 应用 | auth0-swift |
| 仅限 Android 的 Kotlin 应用 | auth0-android |
快速入门工作流
**Agent 指令:**开始前,检查用户的项目:
- 从
.csproj文件(TargetFramework)中确定 .NET 版本- 检查代码库中是否已有身份验证提供程序——搜索现有的
Auth0Client或WebViewBrowser用法,如有则复用- 记录项目的命名空间和目录约定
- 安装 SDK:
dotnet add package Auth0.OidcClient.WPF - 配置 Auth0:请参阅设置指南了解自动或手动配置方法。
- 集成身份验证:添加
Auth0Client初始化,并将登录/登出连接到 XAML 按钮点击处理程序。 - 构建并验证:
dotnet build
**Agent 指令:**编写 Auth0Client 配置时:
- 使用此技能集成指南中的准确代码模式。
- SDK 使用 WebView2 在弹出窗口中显示登录页面——无需自定义浏览器设置。
- 默认回调 URL 为
https://{yourDomain}/mobile——必须将其添加到 Auth0 Dashboard 的 Allowed Callback URLs 和 Allowed Logout URLs 中。- 与使用
https://{domain}/ios/{bundleId}/callback或类似平台专用模式的原生移动 SDK 不同,WPF 使用更简单的https://{domain}/mobile回调格式。编写配置和代码后,验证构建是否成功:
dotnet build如果构建失败,请尝试修复问题。失败 5-6 次后,请向用户寻求帮助。
回调 URL 配置
WPF SDK 默认使用 https://{yourDomain}/mobile 作为回调 URL。这与移动端原生 SDK 不同:
- 移动端 SDK 使用平台专属的回调,例如
https://{domain}/ios/{bundleId}/callback或https://{domain}/android/{packageName}/callback - WPF/WinForms 使用通用回调
https://{yourDomain}/mobile
回调由 WebView2 控件的 NavigationStarting 事件拦截,无需注册系统级 URL 方案。无需配置 Info.plist、AndroidManifest.xml 或 Windows 协议处理程序。
在 Auth0 Dashboard 中配置:
- Allowed Callback URLs:
https://{yourDomain}/mobile - Allowed Logout URLs:
https://{yourDomain}/mobile
完成条件
- 已安装
Auth0.OidcClient.WPF包 - 已使用 Domain 和 ClientId 配置
Auth0Client - 登录/登出流程正常工作(WebView2 弹出窗口打开以进行身份验证)
- 登录后可访问用户个人资料声明
- 已在 Auth0 Dashboard 中注册回调 URL
https://{yourDomain}/mobile - 构建成功且没有错误
- 已在真实设备上测试(实体 Windows 计算机,而不只是远程桌面)
详细文档
- 设置指南 — Auth0 租户配置、SDK 安装、回调 URL 设置
- 集成模式 — 登录/登出流程、令牌刷新、用户个人资料、错误处理
- API 参考与测试 — 完整的
Auth0ClientOptions参考、声明、测试清单、故障排除
常见错误
| 错误 | 修复方法 |
|---|---|
| Auth0 Dashboard 中的应用类型未设为 Native | 在 Dashboard 设置中将应用类型改为 “Native” |
| Auth0 Dashboard 中缺少回调 URL | 将 https://{yourDomain}/mobile 添加到 Allowed Callback URLs 和 Allowed Logout URLs |
在 Domain 配置中使用 https:// 前缀 | Domain 只能填写主机名(例如 tenant.auth0.com,而不是 https://tenant.auth0.com) |
| 未安装 WebView2 Runtime | 在 Windows 10 上安装 Microsoft Edge WebView2 Runtime(Windows 11 已内置) |
刷新令牌时未请求 offline_access 范围 | 将 offline_access 添加到 Auth0ClientOptions 中的 Scope |
| 在代码中存储 ClientSecret | 原生应用不使用 Client Secret,请将其移除 |
| 尝试在注册表/清单中注册 URL 方案 | WPF 在进程内使用 WebView2,无需注册 URL 方案(不同于需要 AppxManifest 的 MAUI) |
测试说明
Agent 指令: 提醒用户在实体设备上测试。与实体 Windows 计算机相比,某些 WebView2 行为(弹出窗口、证书处理)在远程桌面或虚拟机环境中可能有所不同。发布前,请在真实硬件上测试完整的登录 → WebView2 → 回调 → 令牌流程。
测试清单:
- 登录流程:点击登录 → 打开 WebView2 弹出窗口 → 完成身份验证 → 弹出窗口关闭 → 显示用户信息
- 登出流程:点击登出 → 打开 WebView2 弹出窗口 → 清除会话 → 弹出窗口关闭
- 令牌刷新:使用已存储的刷新令牌调用
RefreshTokenAsync,确认正常工作 - 取消:用户关闭 WebView2 窗口 → 应用正常处理
UserCancel - 实体设备:在真实 Windows 计算机上测试(而不只是虚拟环境)
- 多次登录:验证登出后可以再次登录(没有残留状态)
相关技能
- auth0-winforms — Windows Forms 桌面应用
- auth0-maui — .NET MAUI 跨平台应用
- auth0-aspnetcore-authentication — ASP.NET Core 服务端 Web 应用
- auth0-aspnetcore-api — 使用 JWT 验证的 ASP.NET Core Web API
快速参考
using Auth0.OidcClient;
using System.Diagnostics;
// Initialize client
var client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email offline_access"
});
// Login — opens WebView2 popup window (WebAuth flow with PKCE)
var loginResult = await client.LoginAsync();
if (!loginResult.IsError)
{
var user = loginResult.User;
var name = user.FindFirst(c => c.Type == "name")?.Value;
var email = user.FindFirst(c => c.Type == "email")?.Value;
var picture = user.FindFirst(c => c.Type == "picture")?.Value;
Debug.WriteLine($"name: {name}");
Debug.WriteLine($"email: {email}");
foreach (var claim in loginResult.User.Claims)
{
Debug.WriteLine($"{claim.Type} = {claim.Value}");
}
}
// Store the refresh token from login for later use
var refreshToken = loginResult.RefreshToken;
// Logout
await client.LogoutAsync();
// Refresh token (requires offline_access scope)
var refreshResult = await client.RefreshTokenAsync(refreshToken);
if (refreshResult.IsError == false)
{
var newAccessToken = refreshResult.AccessToken;
}
MainWindow.xaml(WPF UI)
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Auth0 WPF App" Height="450" Width="800">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="LoginButton" Content="Login" Width="200" Height="40"
Margin="10" Click="LoginButton_Click" FontSize="16"/>
<Button x:Name="LogoutButton" Content="Logout" Width="200" Height="40"
Margin="10" Click="LogoutButton_Click" FontSize="16"/>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs(WPF 代码隐藏)
using Auth0.OidcClient;
using System.Diagnostics;
namespace MyApp;
public partial class MainWindow : Window
{
private Auth0Client _client;
public MainWindow()
{
InitializeComponent();
_client = new Auth0Client(new Auth0ClientOptions
{
Domain = "{yourDomain}",
ClientId = "{yourClientId}",
Scope = "openid profile email offline_access"
});
}
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
var loginResult = await _client.LoginAsync();
if (loginResult.IsError)
{
Debug.WriteLine($"An error occurred during login: {loginResult.Error}");
return;
}
var user = loginResult.User;
var name = user.FindFirst(c => c.Type == "name")?.Value;
var email = user.FindFirst(c => c.Type == "email")?.Value;
var picture = user.FindFirst(c => c.Type == "picture")?.Value;
Debug.WriteLine($"name: {name}");
Debug.WriteLine($"email: {email}");
foreach (var claim in loginResult.User.Claims)
{
Debug.WriteLine($"{claim.Type} = {claim.Value}");
}
}
private async void LogoutButton_Click(object sender, RoutedEventArgs e)
{
await _client.LogoutAsync();
}
}