Identity SDK
.NET — [RequirePermission]
Section titled “.NET — [RequirePermission]”dotnet add package Axowl.Sdk.Identity.Client — always install the latest version (0.2.3 is the minimum; see the caution below). The package targets .NET 10.
builder.Services.AddAxowlIdentity(opts =>{ opts.OrganizationSlug = "my-org"; // your org slug opts.Audience = "client_…"; // your application's client key // opts.Authority defaults to https://api.axowl.com. // opts.Issuer defaults to {Authority}/api/public/orgs/{OrganizationSlug} — the `iss` Axowl writes. opts.ApiKey = builder.Configuration["Axowl:ApiKey"]!; // org API key (ah_live_…) — needed for server checks});
var app = builder.Build();app.UseAuthentication();app.UseAuthorization();
// Minimal APIs — the attribute on the handler, or the convention methodapp.MapGet("/reports/monthly", [RequirePermission("report.monthly")] () => "…");app.MapGet("/wallet", () => "…").RequirePermission("wallet.read");
// Controllers[HttpGet("/wallet"), RequirePermission("wallet.read")][HttpPost("/wallet/admin"), RequirePermission("wallet.admin", ServerCheck = true)]- No token →
401, token without the permission →403, on minimal APIs and controllers alike. The attribute is an authorization requirement thatUseAuthorization()evaluates from endpoint metadata, soapp.UseAuthorization()is required. - Default (
ServerCheck=false) — reads the token’s claims (principal.HasPermission(scope), wildcard-aware), no round-trip. If the claims do not grant the scope, the server is asked once (the grant may be newer than the token). ServerCheck=true— always callsIAxowlIdentityClient.CheckPermissionAsync.- Server checks need
opts.ApiKeyand fail closed: a failed call is a deny. ctx.User.GetAxowlPrincipal().Permissionsis the list from the token’spermissionsclaim (a JSON-encoded string array, e.g.["wallet.read","report.*"]).
JS/TS — usePermission / requirePermission
Section titled “JS/TS — usePermission / requirePermission”const { can } = usePermission(); // React: can('report.view')app.get('/api/reports', requirePermission('report.view'), handler); // Express middlewarePython — verify_token / AxowlAuth.require
Section titled “Python — verify_token / AxowlAuth.require”ctx = verify_token(token, AxowlConfig(org_slug="my-org", audience="client_…")) # claims fast pathhas_permission(ctx.permissions, "report.view")
@app.get("/reports")def reports(ctx: AxowlContext = Depends(auth.require("report.view"))): # FastAPI, 403 on miss ...Server-authoritative: AxowlIdentityClient(api_key).check_permission(token, "report.view").
Full page: Python SDK.
Java — AxowlTokenVerifier / Permissions.require
Section titled “Java — AxowlTokenVerifier / Permissions.require”AxowlContext ctx = verifier.verify(token); // claims fast pathPermissions.require(ctx, "report.view"); // throws AxowlPermissionExceptionServer-authoritative: new AxowlIdentityClient(apiKey, baseUrl).checkPermission(token, "report.view").
Full page: Java SDK.
Server-authoritative resolution
Section titled “Server-authoritative resolution”Introspect and CheckPermission are served over gRPC (IdentityService) and REST
(POST /v1/identity/introspect, POST /v1/identity/check-permission). Both authenticate with the org API key
(Authorization: Bearer ah_live_…), validate the user token against the org’s RS256 JWKS, reject a token whose
session was signed out, and read the user’s permissions fresh, so revocations apply immediately.
Wildcard matching: *, x.*, exact.
In .NET, inject IAxowlIdentityClient:
var result = await identity.IntrospectAsync(token, ct); // result.Active, result.Principal, result.ExpiresAtvar check = await identity.CheckPermissionAsync(token, "wallet.withdraw", ct); // check.Granted, check.MatchedScopesIntrospect response
Section titled “Introspect response”Introspect (gRPC, or REST POST /v1/identity/introspect) returns the resolved principal.
The same fields surface on AxowlPrincipal in .NET:
| Field | Meaning |
|---|---|
active | false = expired / invalid / revoked. All other fields are empty when inactive. |
end_user_id | The end user’s id in this org. |
organization_id | The org the token was issued for (must match your API key’s org). |
connected_id | The user’s org identity badge (ConnectedId). Issued to every end user — customer or employee — one per org. This is the subject that permissions, seals, and billing attribution key on. |
is_employee | Server-authoritative at introspect time: true when the badge’s subject is an internal org member. Do not infer employment from connected_id being present — it always is. |
permissions | The user’s current permission scopes (revocations already applied). |