Authio.Testing
0.8.0
dotnet add package Authio.Testing --version 0.8.0
NuGet\Install-Package Authio.Testing -Version 0.8.0
<PackageReference Include="Authio.Testing" Version="0.8.0" />
<PackageVersion Include="Authio.Testing" Version="0.8.0" />
<PackageReference Include="Authio.Testing" />
paket add Authio.Testing --version 0.8.0
#r "nuget: Authio.Testing, 0.8.0"
#:package Authio.Testing@0.8.0
#addin nuget:?package=Authio.Testing&version=0.8.0
#tool nuget:?package=Authio.Testing&version=0.8.0
Authio.Testing
Test a .NET application that uses Authio without an Authio
server. FakeAuthio is an in-memory Authio reached through an HttpMessageHandler: point the SDK's named clients at it
and every request (discovery, keys, grants, introspection, userinfo, end session, Admin API) is answered in memory,
recorded, and shaped like Authio's own answers. It is the fake the SDK's own test suites run on.
dotnet add package Authio.Testing
An API test
using var fake = new FakeAuthio(); // https://authio.test, realm acme, client app
var builder = WebApplication.CreateSlimBuilder();
builder.WebHost.UseTestServer();
builder.Services.AddAuthioClient(o => { o.Authority = fake.BaseUrl; o.Realm = fake.Realm; o.ClientId = "app"; o.ClientSecret = "s3cret"; });
builder.Services.AddFakeAuthioBackchannel(fake); // the Authio and Authio.Admin clients reach the fake
builder.Services.AddAuthentication().AddAuthioJwtBearer(o => o.Audiences = ["https://api.test"]);
// …
var token = fake.Tokens.CreateAccessToken("user-1")
.WithAudience("https://api.test")
.WithScope("orders:read")
.WithAuthTime(DateTimeOffset.UtcNow) // a person; recency requirements read it
.WithAcr("2").WithAmr("pwd", "otp", "mfa")
.Build();
FakeTokenBuilder writes any claim (WithActor for a delegation chain, WithImpersonator, WithOrganization,
WithResourceAccess, Expired, SignedWithUnknownKey, WithHeaderType, …). Tokens are real RS256 JWTs signed with
fake.Tokens, whose public key the fake serves at jwks_uri; JwksOverride serves another key set instead.
A login test
The authorization endpoint redirects straight back with code, state and iss, or answers
response_mode=web_message with the page that posts the result. ID tokens carry nonce, sid, acr, amr and
at_hash.
Each FakeAuthioClient is configured like a client in Authio's console, and the fake enforces it as Authio does: what
the client requires is refused when missing, with an error naming the setting, and the extra is accepted.
| Setting | Default | Enforced |
|---|---|---|
RequirePkce |
true |
No code_challenge: invalid_request |
PkceMethods |
["S256"] |
A code_challenge without code_challenge_method, or with another method: invalid_request, required or not; a voluntary challenge is enforced at the token endpoint |
TokenEndpointAuthMethod |
from the credentials (private_key_jwt with Jwks, client_secret_basic with Secret, else none) |
Exact match at the token, introspection, revocation and device endpoints (invalid_client); a public client accepts and ignores a secret, and introspects with its client_id alone, as Authio accepts |
SigningAlgorithm |
RS256 |
HS256/HS384/HS512 sign ID tokens, UserInfo JWTs and logout tokens with Secret |
AccessTokenSigningAlgorithm |
RS256 |
HS256/HS384/HS512 sign access tokens with Secret (introspection, exchange, revocation and UserInfo read them back); refresh tokens stay RS256 |
A client signing with HS* needs a Secret of at least 32, 48 or 64 bytes (RFC 7518 §3.2), as Authio requires:
AddClient refuses a shorter one, and so does every token signed with it (EnsureSigningSecret()). A refresh that
names a resource addresses the new access token to it; the refresh token keeps its own.
| FrontChannelLogoutUri, FrontChannelLogoutSessionRequired | none, true | DeliverFrontChannelLogoutAsync loads the URI with iss and sid |
An unsupported response_mode (anything but query and web_message) is refused with invalid_request.
var redirect = await login.CreateAuthorizationAsync(new AuthioAuthorizationRequest { RedirectUri = "https://app.test/cb" });
var callback = await fake.AuthorizeAsync(redirect.Url); // follows the authorization endpoint
var result = await login.HandleCallbackAsync(callback, redirect.State);
NextLoginUser signs in another user, NextAuthorizeError answers with an error (login_required, access_denied).
Encrypted tokens
Give a client the public half of its encryption key and its ID and access tokens become nested JWEs, as Authio issues them for a client whose key source is its own:
using var rsa = RSA.Create(2048);
fake.DefaultClient.EncryptionKey = RSA.Create(rsa.ExportParameters(false));
fake.DefaultClient.EncryptionAlgorithm = "RSA-OAEP-256"; // RSA-OAEP (default), RSA-OAEP-256 or RSA1_5
// the SDK: options.ClientEncryptionKey = rsa.ExportPkcs8PrivateKeyPem();
fake.Encrypt(token, recipient, algorithm, encryption) encrypts any token the same way (the fake still recognises it at
introspection and userinfo), and FakeJweFactory.Encrypt builds a JWE straight from RFC 7516, independent of
IdentityModel. UserInfoSigned and UserInfoEncryptionKey answer UserInfo as a signed or encrypted JWT.
Logout
The end-session endpoint ends the session of the id_token_hint (EndedSessions) and redirects to a registered
post_logout_redirect_uri. Back-channel logout is delivered on demand:
using var app = testServer.CreateClient();
var answer = await fake.DeliverBackChannelLogoutAsync(app, subject, sessionId, logoutUri: "/bff/backchannel-logout");
CreateLogoutToken(sub, sid, clientId) builds the logout token alone; BackChannelDeliveries records every delivery.
Everything else
Every grant (client credentials, authorization code, refresh with rotation and reuse detection, password, device with
scripted outcomes in DeviceOutcomes, token exchange and connected accounts), forced token errors (TokenErrors),
introspection, revocation (RevokeToken), suspended subjects, discovery failures, and Admin API stubs over
fake.Admin (users, roles, groups, sessions, account credentials). ManualTimeProvider is a clock whose timers fire at
once and record the delays asked for, so polling and Retry-After waits are instant and checkable.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
-
net10.0
- Authio.Client (>= 0.8.0)
-
net8.0
- Authio.Client (>= 0.8.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.