auth0-wpf
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAuth0 WPF Integration
Auth0 WPF 集成
Add Auth0 authentication to WPF (Windows Presentation Foundation) desktop applications. This skill integrates the NuGet package which uses WebView2 to display the Auth0 login page in a popup window for secure OIDC-based login and logout flows with PKCE.
Auth0.OidcClient.WPFThe SDK performs WebAuth (OIDC authorization code flow with PKCE) by opening the Auth0 Universal Login page inside a WebView2 control hosted in a WPF Window. Unlike native mobile SDKs that require URL scheme registration in Info.plist or AndroidManifest.xml, the WPF SDK handles the callback entirely within the WebView2 navigation events — no custom URL Types or protocol handlers are needed.
Agent instruction: Before providing SDK setup instructions, fetch the latest release version by running:bashgh api repos/auth0/auth0-oidc-client-net/releases --jq '[.[] | select(.tag_name | startswith("wpf-")) | .tag_name | ltrimstr("wpf-")] | .[0]'Use the returned version in all dependency lines instead of any hardcoded version below.
为WPF(Windows Presentation Foundation)桌面应用添加Auth0身份验证。此技能集成了 NuGet包,该包使用WebView2在弹出窗口中显示Auth0登录页面,实现基于OIDC的安全登录和登出流程,并采用PKCE机制。
Auth0.OidcClient.WPFSDK通过在WPF窗口中托管的WebView2控件打开Auth0通用登录页面,执行WebAuth(带PKCE的OIDC授权码流程)。与需要在Info.plist或AndroidManifest.xml中注册URL scheme的原生移动SDK不同,WPF SDK完全通过WebView2导航事件处理回调——无需自定义URL类型或协议处理程序。
Agent 指令: 在提供SDK设置说明前,运行以下命令获取最新版本:bashgh api repos/auth0/auth0-oidc-client-net/releases --jq '[.[] | select(.tag_name | startswith("wpf-")) | .tag_name | ltrimstr("wpf-")] | .[0]'将返回的版本用于所有依赖项代码行,而非下方的硬编码版本。
Prerequisites
前提条件
- .NET 6.0 SDK or later (WPF requires Windows)
- Visual Studio 2022 or JetBrains Rider with .NET desktop development workload
- Windows 10 or later
- Microsoft Edge WebView2 Runtime (included with Windows 11, installable on Windows 10)
- Auth0 account with a Native application configured
- Node.js 20+ (for Auth0 CLI automated setup)
- .NET 6.0 SDK或更高版本(WPF仅支持Windows)
- Visual Studio 2022或JetBrains Rider,并安装.NET桌面开发工作负载
- Windows 10或更高版本
- Microsoft Edge WebView2 Runtime(Windows 11已预装,Windows 10可手动安装)
- 已配置Native应用的Auth0账户
- Node.js 20+(用于Auth0 CLI自动化设置)
When NOT to Use
不适用于以下场景
| Use Case | Recommended Skill |
|---|---|
| .NET MAUI cross-platform app | |
| Windows Forms desktop app | |
| ASP.NET Core server-side web app | |
| ASP.NET Core Web API (JWT validation) | |
| iOS-only Swift app | |
| Android-only Kotlin app | |
| 使用场景 | 推荐技能 |
|---|---|
| .NET MAUI跨平台应用 | |
| Windows Forms桌面应用 | |
| ASP.NET Core服务器端Web应用 | |
| ASP.NET Core Web API(JWT验证) | |
| iOS专属Swift应用 | |
| Android专属Kotlin应用 | |
Quick Start Workflow
快速开始流程
Agent instruction: Before starting, examine the user's project:
- Identify the .NET version from the
file (.csproj)TargetFramework- Check if there is already an existing authentication provider in the codebase — search for existing
orAuth0Clientusage and reuse if foundWebViewBrowser- Note the project's namespace and directory conventions
- Install SDK:
dotnet add package Auth0.OidcClient.WPF - Configure Auth0: See Setup Guide for automatic or manual configuration.
- Integrate authentication: Add initialization and wire login/logout to XAML button click handlers.
Auth0Client - Build and verify:
dotnet build
Agent instruction: When writing the Auth0Client configuration:
- Use the exact code patterns from this skill's integration guide.
- The SDK uses WebView2 to show the login page in a popup window — no custom browser setup needed.
- The default callback URL is
— this must be added to Auth0 Dashboard Allowed Callback URLs and Allowed Logout URLs.https://{yourDomain}/mobile- Unlike native mobile SDKs that use
or similar platform-specific patterns, WPF uses the simplerhttps://{domain}/ios/{bundleId}/callbackcallback format.https://{domain}/mobileAfter writing configuration and code, verify the build succeeds:bashdotnet buildIf the build fails, attempt to fix the issue. After 5-6 failed attempts, ask the user for help.
Agent 指令: 开始前,请检查用户的项目:
- 从
文件的.csproj字段识别.NET版本TargetFramework- 检查代码库中是否已有身份验证提供程序——搜索已有的
或Auth0Client用法,若存在则复用WebViewBrowser- 记录项目的命名空间和目录规范
- 安装SDK:
dotnet add package Auth0.OidcClient.WPF - 配置Auth0:查看设置指南进行自动或手动配置。
- 集成身份验证:初始化并将登录/登出功能绑定到XAML按钮的点击事件处理程序。
Auth0Client - 构建并验证:
dotnet build
Agent 指令: 编写Auth0Client配置时:
- 使用本技能集成指南中的精确代码模式。
- SDK使用WebView2在弹出窗口中显示登录页面——无需自定义浏览器设置。
- 默认回调URL为
——必须添加到Auth0控制台的“允许回调URL”和“允许登出URL”中。https://{yourDomain}/mobile- 与使用
等平台特定模式的原生移动SDK不同,WPF使用更简洁的https://{domain}/ios/{bundleId}/callback回调格式。https://{domain}/mobile编写完配置和代码后,验证构建是否成功:bashdotnet build若构建失败,尝试修复问题。经过5-6次失败尝试后,向用户求助。
Callback URL Configuration
回调URL配置
The WPF SDK uses as its default callback URL. This differs from mobile native SDKs:
https://{yourDomain}/mobile- Mobile SDKs use platform-specific callbacks like or
https://{domain}/ios/{bundleId}/callbackhttps://{domain}/android/{packageName}/callback - WPF/WinForms use the generic callback
https://{yourDomain}/mobile
The callback is intercepted by the WebView2 control's event — no system-level URL scheme registration is required. You do NOT need to configure Info.plist, AndroidManifest.xml, or Windows protocol handlers.
NavigationStartingConfigure in the Auth0 Dashboard:
- Allowed Callback URLs:
https://{yourDomain}/mobile - Allowed Logout URLs:
https://{yourDomain}/mobile
WPF SDK默认使用作为回调URL,这与移动原生SDK不同:
https://{yourDomain}/mobile- 移动SDK使用平台特定回调,如或
https://{domain}/ios/{bundleId}/callbackhttps://{domain}/android/{packageName}/callback - WPF/WinForms使用通用的回调
https://{yourDomain}/mobile
回调由WebView2控件的事件拦截——无需注册系统级URL scheme。你无需配置Info.plist、AndroidManifest.xml或Windows协议处理程序。
NavigationStarting在Auth0控制台配置:
- 允许回调URL:
https://{yourDomain}/mobile - 允许登出URL:
https://{yourDomain}/mobile
Done When
完成标准
- package installed
Auth0.OidcClient.WPF - configured with Domain and ClientId
Auth0Client - Login/logout flow working (WebView2 popup opens for authentication)
- User profile claims accessible after login
- Callback URL registered in Auth0 Dashboard
https://{yourDomain}/mobile - Build succeeds with no errors
- Tested on real device (physical Windows machine, not just remote desktop)
- 已安装包
Auth0.OidcClient.WPF - 已使用Domain和ClientId配置
Auth0Client - 登录/登出流程正常工作(WebView2弹窗打开进行身份验证)
- 登录后可访问用户配置声明
- 回调URL 已在Auth0控制台注册
https://{yourDomain}/mobile - 构建成功且无错误
- 在真实设备(物理Windows机器,而非仅远程桌面)上测试通过
Detailed Documentation
详细文档
- Setup Guide — Auth0 tenant configuration, SDK installation, callback URL setup
- Integration Patterns — Login/logout flows, token refresh, user profile, error handling
- API Reference & Testing — Full reference, claims, testing checklist, troubleshooting
Auth0ClientOptions
- 设置指南 — Auth0租户配置、SDK安装、回调URL设置
- 集成模式 — 登录/登出流程、令牌刷新、用户配置、错误处理
- API参考与测试 — 完整参考、声明、测试清单、故障排除
Auth0ClientOptions
Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
| App type not set to Native in Auth0 Dashboard | Change application type to "Native" in Dashboard settings |
| Missing callback URL in Auth0 Dashboard | Add |
Using | Domain should be hostname only (e.g., |
| WebView2 Runtime not installed | Install Microsoft Edge WebView2 Runtime on Windows 10 (included with Windows 11) |
Not requesting | Add |
| Storing ClientSecret in code | Native apps do NOT use a Client Secret — remove it |
| Trying to register URL scheme in registry/manifest | WPF uses WebView2 in-process — no URL scheme registration needed (unlike MAUI which needs AppxManifest) |
| 错误 | 修复方案 |
|---|---|
| Auth0控制台中应用类型未设置为Native | 在控制台设置中将应用类型更改为“Native” |
| Auth0控制台中缺少回调URL | 将 |
Domain配置中使用 | Domain应仅为主机名(例如 |
| 未安装WebView2 Runtime | 在Windows 10上安装Microsoft Edge WebView2 Runtime(Windows 11已预装) |
未请求 | 在 |
| 在代码中存储ClientSecret | 原生应用不使用Client Secret——移除该配置 |
| 尝试在注册表/清单中注册URL scheme | WPF使用进程内WebView2——无需注册URL scheme(与需要AppxManifest的MAUI不同) |
Testing Notes
测试注意事项
Agent instruction: Remind the user to test on a physical device. Some WebView2 behaviors (popup windows, certificate handling) may differ in remote desktop or virtual machine environments vs. physical Windows machines. Test the full login → WebView2 → callback → token flow on real hardware before shipping.
Testing Checklist:
- Login flow: Click login → WebView2 popup opens → authenticate → popup closes → user info displayed
- Logout flow: Click logout → WebView2 popup opens → session cleared → popup closes
- Token refresh: with stored refresh token works
RefreshTokenAsync - Cancel: User closes WebView2 window → app handles gracefully
UserCancel - Physical device: Test on a real Windows machine (not just virtual environment)
- Multiple logins: Verify login works after logout (no stale state)
Agent 指令: 提醒用户在物理设备上测试。部分WebView2行为(弹窗、证书处理)在远程桌面或虚拟机环境中可能与物理Windows机器不同。发布前请在真实硬件上测试完整的登录→WebView2→回调→令牌流程。
测试清单:
- 登录流程:点击登录→WebView2弹窗打开→完成身份验证→弹窗关闭→显示用户信息
- 登出流程:点击登出→WebView2弹窗打开→会话清除→弹窗关闭
- 令牌刷新:使用存储的刷新令牌调用成功
RefreshTokenAsync - 取消操作:用户关闭WebView2窗口→应用优雅处理错误
UserCancel - 物理设备:在真实Windows机器上测试(而非仅虚拟环境)
- 多次登录:验证登出后登录仍可正常工作(无过期状态)
Related Skills
相关技能
- auth0-winforms — Windows Forms desktop apps
- auth0-maui — .NET MAUI cross-platform apps
- auth0-aspnetcore-authentication — ASP.NET Core server-side web apps
- auth0-aspnetcore-api — ASP.NET Core Web API with JWT validation
- auth0-winforms — Windows Forms桌面应用
- auth0-maui — .NET MAUI跨平台应用
- auth0-aspnetcore-authentication — ASP.NET Core服务器端Web应用
- auth0-aspnetcore-api — 带JWT验证的ASP.NET Core Web API
Quick Reference
快速参考
csharp
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;
}csharp
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)
MainWindow.xaml (WPF UI)
xml
<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>xml
<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 Code-Behind)
MainWindow.xaml.cs (WPF Code-Behind)
csharp
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();
}
}csharp
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();
}
}