Skip to content

.NET reference

Package: ArrowLabs.Auth.Client (NuGet), net10.0. All types are in the ArrowLabs.Auth.Client namespace.

MemberSignatureNotes
AddArrowLabsAuthIServiceCollection.AddArrowLabsAuth(Action<ArrowLabsAuthOptions>)Configures JWT bearer + Authority/JWKS discovery, RS256-only, sub/roles claim mapping.
ArrowLabsAuthOptions{ string BaseUrl; string Audience; bool RequireHttpsMetadata = true }RequireHttpsMetadata = false only for local dev.
MethodReturnsClaim
GetUserId()string?sub
GetOrgId()string?org_id
GetOrgSlug()string?org
GetEmail()string?email
GetRoles()IReadOnlyList<string>roles
GetAppAccess()IReadOnlyList<string>app_access

Claim names are also constants on ArrowLabsClaimTypes.

MemberSignatureNotes
AddArrowLabsOAuthClientIServiceCollection.AddArrowLabsOAuthClient(Action<ArrowLabsOAuthOptions>)Registers IArrowLabsOAuthClient as a typed HttpClient.
ArrowLabsOAuthOptions{ string BaseUrl; string ClientId; string? ClientSecret; string? RedirectUri }ClientSecret for confidential clients only.
Pkce.Generate()PkcePair{ Verifier, Challenge, Method = "S256" }.
Pkce.Challenge(verifier)stringBASE64URL(SHA256(verifier)).
MethodSignature
BuildAuthorizationUrl(codeChallenge, redirectUri, scope?, state?, nonce?) => string
ExchangeCodeAsync(code, redirectUri, codeVerifier?, ct) => Task<TokenResult>
RefreshTokensAsync(refreshToken, ct) => Task<TokenResult>
RevokeTokenAsync(refreshToken, ct) => Task<RevokeResult>

TokenResult = Success(AccessToken, TokenType, ExpiresIn, RefreshToken?, IdToken?) | Failure(Error, ErrorDescription?). RevokeResult = Success | Failure(Error, ErrorDescription?). Transport errors → Failure("network_error", null).

MemberSignatureNotes
AddArrowLabsEventConsumerIServiceCollection.AddArrowLabsEventConsumer(Action<ArrowLabsEventConsumerOptions>)Registers a hosted consumer.
AddArrowLabsEventHandler<THandler>IServiceCollection.AddArrowLabsEventHandler<THandler>()Binds the handler to each IArrowLabsEventHandler<T> it implements.
ArrowLabsEventConsumerOptions{ string AmqpUrl; string ClientId; string? QueueName; ushort PrefetchCount = 10 }
IArrowLabsEventHandler<TPayload>Task HandleAsync(TPayload, EventEnvelope, CancellationToken)Implement + register; multiple per type allowed.
IArrowLabsEventDeduplicatorTask<bool> IsDuplicateAsync(eventId, ct) / Task MarkProcessedAsync(eventId, ct)Optional, DI-resolved.

EventEnvelope = { EventId, EventType, EventVersion, OccurredAt, OrganisationId, ActorUserId }. Event types: PlatformEventTypes constants; payloads: UserRegisteredPayload, UserSuspendedPayload, … Runtime dependency: RabbitMQ.Client. Failure → nack-no-requeue → DLQ.