EasyReasy.Auth.Client 1.7.0

dotnet add package EasyReasy.Auth.Client --version 1.7.0
                    
NuGet\Install-Package EasyReasy.Auth.Client -Version 1.7.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EasyReasy.Auth.Client" Version="1.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EasyReasy.Auth.Client" Version="1.7.0" />
                    
Directory.Packages.props
<PackageReference Include="EasyReasy.Auth.Client" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EasyReasy.Auth.Client --version 1.7.0
                    
#r "nuget: EasyReasy.Auth.Client, 1.7.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EasyReasy.Auth.Client@1.7.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EasyReasy.Auth.Client&version=1.7.0
                    
Install as a Cake Addin
#tool nuget:?package=EasyReasy.Auth.Client&version=1.7.0
                    
Install as a Cake Tool

EasyReasy.Auth.Client

← Back to EasyReasy System

NuGet

A lightweight .NET client library for authenticating with EasyReasy.Auth servers, designed for simplicity and automatic token management.

Overview

EasyReasy.Auth.Client provides a simple HTTP client wrapper that automatically handles authentication with EasyReasy.Auth servers. It supports both API key and username/password authentication, with automatic token refresh and retry logic.

Why Use EasyReasy.Auth.Client?

  • Automatic authentication: Handles JWT token acquisition and renewal transparently
  • Multiple auth methods: Support for API key and username/password authentication
  • Token management: Automatic token refresh before expiration (5-minute buffer)
  • Retry logic: Automatically retries requests on 401 Unauthorized with fresh tokens
  • Simple API: Drop-in replacement for HttpClient with minimal code changes
  • Flexible configuration: Customizable auth endpoints and HTTP client settings

Quick Start

1. Add to your project

Install via NuGet:

dotnet add package EasyReasy.Auth.Client

2. Create an authorized client

Credentials must carry something. Both credential constructors reject a null credential with ArgumentNullException and an empty one with ArgumentException: an empty credential carries nothing to authenticate with, so it is refused rather than sent. A whitespace-only credential is a value you supplied and is sent as given — the client does not decide what the server will accept.

API Key Authentication
using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient authorizedClient = new AuthorizedHttpClient(httpClient, "your-api-key-here");

    // The client will automatically authenticate on first use
    HttpResponseMessage response = await authorizedClient.GetAsync("api/data");
}
Username/Password Authentication
using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient authorizedClient = new AuthorizedHttpClient(
        httpClient, 
        username: "your-username", 
        password: "your-password");

    // The client will automatically authenticate on first use
    HttpResponseMessage response = await authorizedClient.GetAsync("api/data");
}

3. Use the client like a regular HttpClient

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient authorizedClient = new AuthorizedHttpClient(httpClient, "your-api-key");

    // GET requests
    HttpResponseMessage response = await authorizedClient.GetAsync("api/users");

    // POST requests
    StringContent content = new StringContent("{\"name\":\"John\"}", Encoding.UTF8, "application/json");
    HttpResponseMessage response = await authorizedClient.PostAsync("api/users", content);

    // Custom requests
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Put, "api/users/123");
    request.Content = new StringContent("{\"name\":\"Jane\"}", Encoding.UTF8, "application/json");
    HttpResponseMessage response = await authorizedClient.SendAsync(request);
}

Advanced Usage

Custom Auth Endpoints

By default, the client uses the standard EasyReasy.Auth endpoints, as paths relative to the client's base address:

  • API Key: api/auth/apikey
  • Username/Password: api/auth/login

Keep your own endpoints relative too. A leading slash makes the path absolute against the host, discarding any path prefix in the base address — https://api.example.com/myapp plus /api/auth/login resolves to https://api.example.com/api/auth/login.

You can customize these endpoints:

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    // Custom API key endpoint
    AuthorizedHttpClient apiKeyClient = new AuthorizedHttpClient(
        httpClient, 
        "your-api-key", 
        authEndpoint: "custom/auth/apikey");

    // Custom login endpoint
    AuthorizedHttpClient loginClient = new AuthorizedHttpClient(
        httpClient, 
        "username", 
        "password", 
        authEndpoint: "custom/auth/login");
}

Manual Authentication Control

You can manually control when authentication happens:

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient client = new AuthorizedHttpClient(httpClient, "api-key");

    // Force authentication now
    await client.EnsureAuthorizedAsync();

    // Check authentication type
    if (client.AuthenticationType == AuthorizedHttpClient.AuthType.ApiKey)
    {
        Console.WriteLine("Using API key authentication");
    }
}

Handling Authorization Issues

Sometimes the server may reject a token even when the client thinks it's still valid. The client provides methods to handle these scenarios:

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient client = new AuthorizedHttpClient(httpClient, "api-key");

    try
    {
        HttpResponseMessage response = await client.GetAsync("api/data");
        // Process response
    }
    catch (UnauthorizedAccessException)
    {
        // Force a fresh authorization attempt
        await client.ForceAuthorizeAsync();
        
        // Try the request again
        HttpResponseMessage response = await client.GetAsync("api/data");
    }
}
Force Authorization Methods
  • ForceAuthorizeAsync(): Bypasses the authorization check and always performs a fresh authentication. Useful when the server rejects a token that the client thinks is still valid.

  • ForceReauthorizeAsync(): Clears all current authorization state and performs a completely fresh authentication. This ensures no residual state interferes with the new authentication.

// Force fresh authentication without clearing state
await client.ForceAuthorizeAsync();

// Clear all state and perform fresh authentication
await client.ForceReauthorizeAsync();

Persisting Auth State with Callbacks

All constructors accept an optional onAuthResponseChanged callback that fires whenever the auth state changes — on initial authentication, token refresh, or re-auth. This is useful for CLI tools and long-running processes that want to persist the token to disk:

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    // First launch: authenticate with API key and persist the token
    AuthorizedHttpClient client = new AuthorizedHttpClient(
        httpClient,
        "your-api-key",
        onAuthResponseChanged: authResponse =>
        {
            File.WriteAllText("auth-state.json", authResponse.ToJson());
        });

    await client.GetAsync("api/data");
}

// Subsequent launches: reuse the persisted token
string savedJson = File.ReadAllText("auth-state.json");
AuthResponse savedAuth = AuthResponse.FromJson(savedJson);

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient client = new AuthorizedHttpClient(
        httpClient,
        savedAuth,
        onAuthResponseChanged: authResponse =>
        {
            // Keeps the persisted state up to date on transparent token refreshes
            File.WriteAllText("auth-state.json", authResponse.ToJson());
        });

    await client.GetAsync("api/data");
}

Token Expiration

The client automatically handles token expiration:

  1. Detects when token expires within 5 minutes
  2. Automatically re-authenticates before making requests
  3. Retries failed requests once with a fresh token

Logging Out

LogoutAsync() posts the current refresh token to the server's logout endpoint (default /api/auth/logout) and then clears all local auth state. The server call is best-effort — HTTP failures do not prevent local state from being cleared, so the client always ends up in an unauthenticated state after the call.

using HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/");
using AuthorizedHttpClient client = new AuthorizedHttpClient(
    httpClient, username: "user", password: "pass");

await client.GetAsync("api/data");

// Later — revoke the refresh token family and clear local state.
await client.LogoutAsync();

// Subsequent requests will trigger a fresh authentication flow
// (only possible when the client has credentials — API key or username/password.
// A pre-authorized client cannot re-authenticate after logout.)

You can override the logout endpoint path via the logoutEndpoint constructor parameter if your server mounts it elsewhere.

Best Practices

1. HttpClient Lifecycle Management

The AuthorizedHttpClient doesn't dispose the underlying HttpClient. Manage the HttpClient lifecycle according to your application's needs:

// For long-lived applications
HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/");

// Reuse the same AuthorizedHttpClient instance
AuthorizedHttpClient authorizedClient = new AuthorizedHttpClient(httpClient, "api-key");

// Use throughout your application
// Don't dispose the AuthorizedHttpClient unless you're done with the HttpClient

2. Error Handling

Always handle authentication and network errors:

using (HttpClient httpClient = AuthorizedHttpClient.CreateHttpClient("https://api.example.com/"))
{
    AuthorizedHttpClient authorizedClient = new AuthorizedHttpClient(httpClient, "api-key");
    
    try
    {
        HttpResponseMessage response = await authorizedClient.GetAsync("api/data");
        response.EnsureSuccessStatusCode();
        
        string content = await response.Content.ReadAsStringAsync();
        // Process response
    }
    catch (UnauthorizedAccessException)
    {
        // Handle credentials the server rejected (the auth endpoint answered 401)
    }
    catch (HttpRequestException)
    {
        // Handle network/server errors. Only a 401 from the auth endpoint surfaces as
        // UnauthorizedAccessException; any other unsuccessful status lands here.
    }
}

Note that construction itself throws when a credential carries nothing — ArgumentNullException for null, ArgumentException for an empty string. If your credentials come from configuration that may be unset, validate them before constructing the client, or the throw lands on the constructor line rather than inside the try above.

Migration from 1.6.0

Both credential constructors now reject an empty credential. new AuthorizedHttpClient(httpClient, "") and new AuthorizedHttpClient(httpClient, "", "") previously constructed successfully and failed later, at the first request; they now throw ArgumentException at construction. null continues to throw ArgumentNullException, and a whitespace-only credential is still sent to the server unchanged.

If you were relying on the old behaviour to defer credential validation to the server, move that check ahead of the constructor.

The username/password constructor now normalizes the base address. It previously skipped the trailing-slash normalization the other two constructors perform, so a base address carrying a path prefix (https://api.example.com/myapp) lost that prefix when the auth endpoint was appended — the login POST went to https://api.example.com/api/auth/login. If you worked around this by passing an absolute authEndpoint, or by adding the trailing slash yourself, that workaround is no longer needed (and remains harmless).

The request models now pin their wire field names. LoginAuthRequest and ApiKeyAuthRequest carry [JsonPropertyName] attributes and expose the names as constants (UsernameFieldName, PasswordFieldName, ApiKeyFieldName, ClientIdFieldName), matching the server-side models. The body this client sends is unchanged; it can no longer drift if a property is renamed or if JsonSerializerSettings.CurrentOptions is assigned a different naming policy.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on EasyReasy.Auth.Client:

Package Downloads
EasyReasy.Ollama.Client

Client library for the EasyReasy Ollama server

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.7.0 199 9/10/2026
1.5.0 1,604 4/2/2026
1.4.0 131 4/2/2026
1.3.0 138 3/24/2026
1.2.1 125 3/21/2026
1.2.0 130 2/18/2026
1.1.0 323 8/29/2025
1.0.0 375 8/7/2025