.NET Integration
This guide covers everything you need to integrate AuthStack into your .NET application using the official SDK.
Installation
Section titled “Installation”.NET CLI
Section titled “.NET CLI”dotnet add package AuthStack.ClientPackage Manager Console
Section titled “Package Manager Console”Install-Package AuthStack.ClientPackageReference
Section titled “PackageReference”<PackageReference Include="AuthStack.Client" Version="1.3.1" />Quick Start
Section titled “Quick Start”Initialize the Client
Section titled “Initialize the Client”using AuthStack.Client;
var client = new AuthStackClient(new AuthStackConfig{ BaseUrl = "https://api.authstack.voostack.com"});
// Initialize (restores any stored session)await client.InitializeAsync();Email/Password Authentication
Section titled “Email/Password Authentication”// Registervar result = await client.RegisterAsync( email: "user@example.com", password: "securePassword123", firstName: "John", lastName: "Doe");
if (result.IsSuccess){ Console.WriteLine($"Welcome, {result.User!.FullName}!");}
// Loginvar loginResult = await client.LoginAsync("user@example.com", "password123");
if (loginResult.IsSuccess){ Console.WriteLine($"Logged in as {loginResult.User!.Email}"); Console.WriteLine($"Access token: {loginResult.Tokens!.AccessToken}");}else{ Console.WriteLine($"Login failed: {loginResult.Error}");}OAuth Providers
Section titled “OAuth Providers”Centralized OAuth Flow (Recommended)
Section titled “Centralized OAuth Flow (Recommended)”AuthStack handles OAuth app configuration centrally. You don’t need your own OAuth credentials:
// Get the OAuth authorization URLvar authUrl = await client.GetProviderAuthUrlAsync( OAuthProvider.GitHub, "https://yourapp.com/oauth/callback");
// Redirect user to authUrl.AuthorizationUrl// After callback, link the providervar linked = await client.LinkProviderWithCodeAsync( OAuthProvider.GitHub, codeFromCallback, "https://yourapp.com/oauth/callback");With Your Own OAuth Credentials
Section titled “With Your Own OAuth Credentials”If you have your own OAuth app configured:
// Using an ID token (e.g., from Google Sign-In)var result = await client.LoginWithProviderTokenAsync( OAuthProvider.Google, googleIdToken);
// Using an authorization code (redirect flow)var result = await client.LoginWithProviderCodeAsync( OAuthProvider.GitHub, authorizationCode, "https://myapp.com/callback");Using AuthStack as Your Identity Provider
Section titled “Using AuthStack as Your Identity Provider”If your application uses AuthStack as its identity provider (users log in through AuthStack’s OAuth flow), use ExchangeCodeAsync() instead of LoginWithProviderCodeAsync().
When to Use Each Method
Section titled “When to Use Each Method”| Scenario | Method | Endpoint |
|---|---|---|
| User logs in with Google/GitHub via your app | LoginWithProviderCodeAsync() | /auth/oauth/{provider} |
| User logs in through AuthStack’s authorize page | ExchangeCodeAsync() | /oauth/token |
| Your backend exchanges code from AuthStack OAuth flow | ExchangeCodeAsync() | /oauth/token |
OAuth 2.0 Authorization Code Flow
Section titled “OAuth 2.0 Authorization Code Flow”When AuthStack is your identity provider:
// 1. Configure client with OAuth credentialsvar client = new AuthStackClient(new AuthStackConfig{ BaseUrl = "https://api.authstack.voostack.com", ClientId = "your-app-client-id", // From your OAuth app in AuthStack ClientSecret = "your-app-secret" // From your OAuth app in AuthStack});
await client.InitializeAsync();
// 2. After user is redirected back with authorization codevar result = await client.ExchangeCodeAsync(code, redirectUri);
if (result.IsSuccess){ Console.WriteLine($"Logged in as {result.User!.Email}"); // Access token is now available: result.Tokens!.AccessToken}Custom Backend Token Exchange
Section titled “Custom Backend Token Exchange”For apps that issue their own tokens, use ExchangeCodeViaBackendAsync():
// Exchange code via your own backend APIvar result = await client.ExchangeCodeViaBackendAsync( backendUrl: "https://api.myapp.com/auth/oauth/callback", code: authorizationCode, redirectUri: "https://myapp.com/callback");Your backend receives the code and can:
- Exchange it with AuthStack for tokens
- Create/lookup local user records
- Issue your own JWT tokens
Recommended GitHub Scopes
Section titled “Recommended GitHub Scopes”When using GitHub OAuth, request these scopes for full functionality:
| Scope | Purpose |
|---|---|
repo | Access private repositories |
read:user | Read user profile data |
user:email | Access user email addresses |
Provider Credentials
Section titled “Provider Credentials”After linking a provider, get their access token to make API calls:
// Get GitHub credentialsvar credentials = await client.GetProviderCredentialsAsync(OAuthProvider.GitHub);
// Check if expiredif (credentials.IsExpired){ // Re-authenticate with GitHub}
// Use with Octokit (GitHub .NET SDK)var github = new GitHubClient(new ProductHeaderValue("MyApp"));github.Credentials = new Credentials(credentials.AccessToken);var repos = await github.Repository.GetAllForCurrent();
// Or with HttpClientvar httpClient = new HttpClient();httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", credentials.AccessToken);var response = await httpClient.GetAsync("https://api.github.com/user/repos");ProviderCredentials Properties
Section titled “ProviderCredentials Properties”| Property | Type | Description |
|---|---|---|
ProviderType | string | Provider name (e.g., “github”) |
AccessToken | string | OAuth access token |
RefreshToken | string? | Refresh token (if available) |
ExpiresAt | DateTime? | Token expiration time |
Scopes | string? | Granted OAuth scopes |
IsExpired | bool | Whether token has expired |
Provider Linking
Section titled “Provider Linking”Link multiple OAuth providers to a single account:
// Get linked providersvar providers = await client.GetLinkedProvidersAsync();foreach (var provider in providers){ Console.WriteLine($"{provider.ProviderType}: {provider.Email}");}
// Link a new provider with tokenvar linked = await client.LinkProviderWithTokenAsync( OAuthProvider.GitHub, githubAccessToken);
// Link with authorization codevar linked = await client.LinkProviderWithCodeAsync( OAuthProvider.GitHub, authorizationCode, "https://yourapp.com/callback");
// Unlink a providerawait client.UnlinkProviderAsync(OAuthProvider.GitHub);Auth State Management
Section titled “Auth State Management”Event-Based Updates
Section titled “Event-Based Updates”// Listen for status changesclient.StatusChanged += (sender, status) =>{ Console.WriteLine($"Auth status changed: {status}");
switch (status) { case AuthStatus.Authenticated: Console.WriteLine("User is logged in"); break; case AuthStatus.Unauthenticated: Console.WriteLine("User is logged out"); break; case AuthStatus.Loading: Console.WriteLine("Loading..."); break; }};
// Listen for user changesclient.UserChanged += (sender, user) =>{ if (user != null) { Console.WriteLine($"Current user: {user.FullName}"); } else { Console.WriteLine("No user logged in"); }};Check Authentication Status
Section titled “Check Authentication Status”if (client.IsAuthenticated){ var user = client.CurrentUser; var accessToken = client.AccessToken; var tokens = client.Tokens;}Token Management
Section titled “Token Management”Token Refresh
Section titled “Token Refresh”// Manually refresh tokenvar success = await client.RefreshTokenAsync();if (!success){ // Token refresh failed, user needs to re-authenticate}Custom Token Storage
Section titled “Custom Token Storage”By default, tokens are stored in memory. Implement ITokenStorage for persistence:
public class SecureTokenStorage : ITokenStorage{ public async Task SaveTokensAsync(AuthTokens tokens, CancellationToken ct = default) { // Save to secure storage (e.g., encrypted file, Windows Credential Manager) var json = JsonSerializer.Serialize(tokens); await File.WriteAllTextAsync("tokens.enc", Encrypt(json), ct); }
public async Task<AuthTokens?> GetTokensAsync(CancellationToken ct = default) { if (!File.Exists("tokens.enc")) return null; var encrypted = await File.ReadAllTextAsync("tokens.enc", ct); var json = Decrypt(encrypted); return JsonSerializer.Deserialize<AuthTokens>(json); }
public async Task ClearTokensAsync(CancellationToken ct = default) { if (File.Exists("tokens.enc")) File.Delete("tokens.enc"); }
public Task<bool> HasTokensAsync(CancellationToken ct = default) { return Task.FromResult(File.Exists("tokens.enc")); }}
// Use custom storagevar client = new AuthStackClient(new AuthStackConfig{ BaseUrl = "https://api.authstack.voostack.com", TokenStorage = new SecureTokenStorage()});JWKS Token Validation
Section titled “JWKS Token Validation”AuthStack supports JWKS for validating tokens without shared secrets. Use this in your backend:
ASP.NET Core
Section titled “ASP.NET Core”services.AddAuthentication() .AddJwtBearer(options => { options.Authority = "https://api.authstack.voostack.com"; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidIssuer = "https://api.authstack.voostack.com", ValidateAudience = true, ValidAudience = "authstack" }; });JWKS Endpoints
Section titled “JWKS Endpoints”| Endpoint | Description |
|---|---|
/.well-known/jwks.json | JSON Web Key Set for token validation |
/.well-known/openid-configuration | OpenID Connect discovery document |
Error Handling
Section titled “Error Handling”try{ var result = await client.LoginAsync(email, password);}catch (AuthStackException ex){ Console.WriteLine($"Error: {ex.Message}"); Console.WriteLine($"Status Code: {ex.StatusCode}"); Console.WriteLine($"Response: {ex.ResponseData}");
// Handle specific errors based on status code if (ex.StatusCode == System.Net.HttpStatusCode.Unauthorized) { // Invalid credentials }}API Reference
Section titled “API Reference”AuthStackClient Methods
Section titled “AuthStackClient Methods”| Method | Description |
|---|---|
InitializeAsync() | Initialize and restore session |
LoginAsync() | Login with email/password |
RegisterAsync() | Register new user |
LoginWithProviderTokenAsync() | Login with OAuth token (social login) |
LoginWithProviderCodeAsync() | Login with OAuth code (social login) |
ExchangeCodeAsync() | Exchange code when AuthStack is your IdP |
ExchangeCodeViaBackendAsync() | Exchange code via custom backend |
RefreshTokenAsync() | Refresh access token |
FetchCurrentUserAsync() | Refresh user data |
GetLinkedProvidersAsync() | Get linked OAuth providers |
LinkProviderWithTokenAsync() | Link OAuth provider with token |
LinkProviderWithCodeAsync() | Link OAuth provider with code |
UnlinkProviderAsync() | Unlink OAuth provider |
GetProviderAuthUrlAsync() | Get OAuth authorization URL |
GetProviderCredentialsAsync() | Get provider access token |
LogoutAsync() | Logout and clear tokens |
ClearLocalAuthAsync() | Clear local auth without server call |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
Status | AuthStatus | Current authentication status |
CurrentUser | UserInfo? | Current authenticated user |
Tokens | AuthTokens? | Current auth tokens |
IsAuthenticated | bool | Whether user is authenticated |
IsInitialized | bool | Whether client is initialized |
AccessToken | string? | Current access token |
Events
Section titled “Events”| Event | Description |
|---|---|
StatusChanged | Fired when auth status changes |
UserChanged | Fired when current user changes |