.NET EndUser auth
Axowl.Sdk signs end users into a Blazor WebAssembly app. Your app never sees a password:
it hands the user to Axowl’s hosted Account Portal, and gets back a signed JWT it can send to
your own API.
This is the end-user plane. For your server verifying those tokens see Reference → Authentication; for permission checks inside the app see SDK → Identity.
Install
Section titled “Install”<ProjectReference Include="..\..\..\axowl-sdk\dotnet\Axowl.Sdk\Axowl.Sdk.csproj" />Register
Section titled “Register”AddAxowlSdk wires the token store, an AuthenticationStateProvider (so <AuthorizeView> works
with no extra code), and IAxowlAuth. It needs an HttpClient already in the container
(AxowlServiceCollectionExtensions.cs:15).
builder.Services.AddScoped(_ => new HttpClient { BaseAddress = new Uri(apiBaseUrl) });
builder.Services.AddAxowlSdk(o =>{ o.ApiBaseUrl = "https://testapi.axowl.com"; // Axowl API o.HostedLoginUrl = "https://login.axowl.com"; // Account Portal o.ApplicationKey = "app_…"; // your Application's key});| Option | Purpose |
|---|---|
ApiBaseUrl | Axowl API origin — the code-for-token exchange is called here |
HostedLoginUrl | Account Portal origin the user is redirected to |
ApplicationKey | Identifies your Application (app_…) |
CodeParam | Query key carrying the one-time code on return (default suits the portal) |
TokenStorageKey | localStorage key for the JWT (AxowlTokenStore.cs:19) |
Complete the round trip
Section titled “Complete the round trip”Sign-in is a redirect: the user leaves for the portal and comes back with a one-time code in
the URL. Call HandleRedirectCallbackAsync() once on app start — typically in your layout’s
OnInitializedAsync — or sign-in never finishes.
@inject Axowl.Sdk.IAxowlAuth Auth
protected override async Task OnInitializedAsync(){ await Auth.HandleRedirectCallbackAsync();}It exchanges the code at
/api/public/apps/{ApplicationKey}/auth/session/exchange, stores the JWT, flips auth state, and
strips the code from the address bar. Returns true when a sign-in completed on that call
(AxowlAuth.cs:31).
Gate a page behind sign-in
Section titled “Gate a page behind sign-in”For a page that an anonymous visitor has no business seeing, RequireSignInAsync forwards to the
portal and tells you to stop rendering.
protected override async Task OnInitializedAsync(){ if (await Auth.RequireSignInAsync($"{Nav.BaseUri.TrimEnd('/')}/register")) return; // redirecting — render nothing
// signed in (or a previous attempt failed) — carry on}| Returns | Meaning |
|---|---|
true | A redirect was started. Return immediately. |
false | Signed in or already attempted once in this browser session. |
The second case matters: if sign-in cannot complete — the user cancelled, or the return URL isn’t
an allowed Callback URL — forwarding again would trap them in a loop with nothing on screen. After
one attempt the SDK stops and hands control back so you can show a “sign-in required” message.
The marker lives in sessionStorage, so a new tab tomorrow forwards again; if storage is blocked
(private mode, embedded webview) the SDK never forwards.
Call your API
Section titled “Call your API”var token = await Auth.GetAccessTokenAsync();if (token is not null) request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);Never returns an expired token — on expiry it clears the session and flips to signed-out, so your
app re-authenticates instead of sending a dead token (AxowlAuth.cs:76).
Sign out
Section titled “Sign out”await Auth.SignOutAsync(); // your app onlySignOutAsync clears the stored JWT and flips auth state to signed-out (AxowlAuth.cs:113). That
is all it does. There is no server call, and no session outside your app is touched.
Four different logouts
Section titled “Four different logouts”“Log out” means four different things in this system, and only the first is yours by default.
| Call | What it ends | Yours? |
|---|---|---|
IAxowlAuth.SignOutAsync() | The JWT your app stored | ✅ this is what the SDK does |
POST /api/public/apps/{key}/auth/logout | Nothing, but it emits EndUserLoggedOutEvent | optional |
GET /api/public/orgs/{slug}/end-session | OIDC RP-initiated logout: validates post_logout_redirect_uri against your Application’s registered list, then redirects | OIDC clients only |
POST /api/auth/logout | The Axowl dashboard cookie session | ❌ not your plane |
Tokens stay valid until they expire
Section titled “Tokens stay valid until they expire”An EndUser JWT is a stateless bearer token. Your API verifies it against the org’s JWKS without ever calling Axowl, so there is no checkpoint at which Axowl could withdraw one mid-life. Signing out locally does not shorten the token you just discarded.
Register your Callback URLs
Section titled “Register your Callback URLs”Add every URL you pass to SignIn / RequireSignInAsync — exact match, including any trailing
slash — under Applications → your app → Authentication → Callback URLs. Returning to two
different pages means two entries:
https://yourapp.com/https://yourapp.com/registerThis is the most common first-integration failure, because the sign-in itself looks fine right up until the portal refuses to come back.
Interface summary
Section titled “Interface summary”IAxowlAuth (IAxowlAuth.cs):
| Member | Purpose |
|---|---|
CurrentUser | The signed-in end user, or null |
HandleRedirectCallbackAsync() | Finish sign-in on return — call once at app start |
RequireSignInAsync(returnUrl) | Gate a page; true = redirecting, stop rendering |
SignIn(redirectUrl) | Redirect to the portal now |
BuildLoginUrl(redirectUrl) | Build the portal URL without navigating |
GetAccessTokenAsync() | JWT for Authorization: Bearer, or null |
SignOutAsync() | Clear the local session — your app only, see Sign out |
Build the login URL with BuildLoginUrl rather than assembling it from config — the portal’s URL
shape belongs to the SDK, and hand-built copies break the day it changes.