Skip to content

Authentication Interfaces and Commands

This document covers Fusion's core authentication interfaces (IAuth, IAuthBackend), the User class, session-related types, and authentication commands.

Overview

Fusion's authentication system is built around two complementary interfaces:

  • IAuth - Client-facing API for reading authentication state
  • IAuthBackend - Server-side API for modifying authentication state

Both interfaces are compute services, meaning their query results automatically invalidate when authentication state changes.

IAuth Interface

View Source

The IAuth interface provides client-safe authentication operations. It requires a Session parameter and only exposes data the current user is allowed to access.

Commands

CommandDescription
SignOut(Auth_SignOut)Signs out the current session
EditUser(Auth_EditUser)Edits the current user's profile
UpdatePresence(Session)Updates the session's last-seen timestamp

Queries (Compute Methods)

MethodReturn TypeDescription
IsSignOutForced(Session)Task<bool>Checks if a forced sign-out was triggered
GetAuthInfo(Session)Task<SessionAuthInfo?>Gets authentication info for the session
GetSessionInfo(Session)Task<SessionInfo?>Gets full session information
GetUser(Session)Task<User?>Gets the authenticated user
GetUserSessions(Session)Task<ImmutableArray<SessionInfo>>Gets all sessions for the current user

Usage Example

csharp
public class OrderService : IOrderService
{
    private readonly IAuth _auth;

    [ComputeMethod]
    public virtual async Task<List<Order>> GetMyOrders(
        Session session,
        CancellationToken ct = default)
    {
        // This creates a dependency on auth state
        var user = await _auth.GetUser(session, ct).Require();

        // If user signs out, this computed value invalidates automatically
        return await GetOrdersForUser(user.Id, ct);
    }
}

IAuthBackend Interface

View Source

The IAuthBackend interface provides server-side authentication operations. It does not require a Session for queries and allows modification of any user's data.

Security Note: IAuthBackend is marked with IBackendService, which means it's never exposed over RPC. It should only be used on the server.

Commands

CommandDescription
SignIn(AuthBackend_SignIn)Authenticates a session with a user
SetupSession(AuthBackend_SetupSession)Creates or updates session metadata
SetOptions(AuthBackend_SetSessionOptions)Sets session options

Queries

MethodReturn TypeDescription
GetUser(shard, userId)Task<User?>Gets any user by ID (no session required)

Authentication Commands

Auth_SignOut

Signs out a session, optionally forcing sign-out or kicking other sessions.

csharp
[DataContract]
public partial record Auth_SignOut : ISessionCommand<Unit>
{
    public Session Session { get; init; }
    public string? KickUserSessionHash { get; init; }  // Kick specific session
    public bool KickAllUserSessions { get; init; }     // Kick all user's sessions
    public bool Force { get; init; }                   // Force sign-out (requires new session)
}

Usage:

csharp
// Simple sign-out
await Commander.Call(new Auth_SignOut(session));

// Forced sign-out (invalidates session permanently)
await Commander.Call(new Auth_SignOut(session, force: true));

// Kick a specific session
await Commander.Call(new Auth_SignOut(session, kickSessionHash, force: true));

// Kick all sessions ("Sign out everywhere")
await Commander.Call(new Auth_SignOut(session) { KickAllUserSessions = true, Force = true });

Auth_EditUser

Edits the current user's profile.

csharp
[DataContract]
public partial record Auth_EditUser(
    Session Session,
    string? Name
) : ISessionCommand<Unit>;

Usage:

csharp
await Commander.Call(new Auth_EditUser(session, "New Name"));

AuthBackend_SignIn

Authenticates a session with a user (server-side only).

csharp
[DataContract]
public partial record AuthBackend_SignIn(
    Session Session,
    User User,
    UserIdentity AuthenticatedIdentity
) : ISessionCommand<Unit>, IBackendCommand;

Usage:

csharp
var user = new User("user-123", "John Doe") {
    Claims = claims,
    Identities = new ApiMap<UserIdentity, string>() {
        { new UserIdentity("Google", "google-id-123"), "" }
    }
};
var identity = user.Identities.Single().Key;
await Commander.Call(new AuthBackend_SignIn(session, user, identity));

AuthBackend_SetupSession

Creates or updates session metadata (IP address, user agent, options).

csharp
[DataContract]
public partial record AuthBackend_SetupSession(
    Session Session,
    string IPAddress,
    string UserAgent,
    PropertyBag Options
) : ISessionCommand<SessionInfo>, IBackendCommand
{
    // Hides Options from ToString() unless sanitization is suspended
    protected virtual bool PrintMembers(StringBuilder builder);
}

AuthBackend_SetSessionOptions

Sets custom options on a session.

csharp
[DataContract]
public partial record AuthBackend_SetSessionOptions(
    Session Session,
    PropertyBag Options,
    long? ExpectedVersion = null
) : ISessionCommand<Unit>;

User Class

View Source

The User class represents an authenticated user.

Properties

PropertyTypeDescription
IdstringUnique user identifier
NamestringDisplay name
VersionlongOptimistic concurrency version
ClaimsApiMap<string, string>User claims (key-value pairs)
IdentitiesApiMap<UserIdentity, string>Authentication identities

Key Methods

MethodDescription
IsAuthenticated()Returns true if Id is not empty
IsGuest()Returns true if Id is empty
IsInRole(role)Checks if user has the specified role claim
ToClaimsPrincipal()Converts to ClaimsPrincipal for ASP.NET Core integration
ToClientSideUser()Creates a copy with masked identity secrets
WithClaim(name, value)Creates a copy with an added claim
WithIdentity(identity)Creates a copy with an added identity

Static Requirements

csharp
// Throws if user is null
var user = await Auth.GetUser(session, ct).Require();

// Throws if user is null or not authenticated
var user = await Auth.GetUser(session, ct).Require(User.MustBeAuthenticated);

Creating Users

csharp
// Guest user (not authenticated)
var guest = User.NewGuest("Anonymous");

// Authenticated user
var user = new User("user-123", "John Doe")
    .WithClaim(ClaimTypes.Email, "[email protected]")
    .WithIdentity(new UserIdentity("Google", "google-id-123"));

UserIdentity

View Source

UserIdentity represents an authentication identity (e.g., Google, GitHub, local account).

Properties

PropertyTypeDescription
IdstringFull identity ID (schema/id format)
SchemastringAuthentication schema (e.g., "Google", "GitHub")
SchemaBoundIdstringID within the schema
IsValidboolReturns true if Id is not empty

Creating Identities

csharp
// From schema and ID
var identity = new UserIdentity("Google", "google-user-id");

// Using tuple syntax
UserIdentity identity = ("GitHub", "github-user-id");

// From serialized string
var identity = new UserIdentity("Google/google-user-id");

Default Schema

csharp
// Set the default schema (used when parsing IDs without explicit schema)
UserIdentity.DefaultSchema = "Local";

// This identity uses the default schema
var identity = new UserIdentity("user-123");
// identity.Schema == "Local"
// identity.SchemaBoundId == "user-123"

Session Class

View Source

The Session class represents a user session, typically stored in an HTTP-only cookie.

Properties

PropertyTypeDescription
IdstringUnique session identifier (min 8 chars). A bearer credential — never log it
HashstringShort (8 hex chars) non-cryptographic XxHash3 of Id, used to identify a session in the UI and on the wire
Sha256HashReadOnlyMemory<byte>SHA-256 of Id, computed once and cached. Use it when a strong, collision-resistant identifier is needed

Static Members

MemberDescription
DefaultSpecial session ("~") for client-side use
FactoryCreates new sessions (default: generates GUIDs)
ValidatorValidates session IDs

ToString() Is Redacted

Since v14.2 Session.ToString() renders {first 4 chars of Id}:{Hash} — e.g. 8Kq2:1f0a3c7d — rather than the raw Id. Anything that formats a Session into a log line, an exception message or a diagnostic string used to leak a credential that is enough to impersonate the user; the redacted form reveals 24 bits of a ~120-bit id, which is still enough for a human to match a log line against a UI row or a DB record.

Use session.Id explicitly where the actual value is required (cookies, RPC arguments, database lookups) — nothing about the wire representation changed.

Hash stays XxHash3 on purpose: it's on the wire via SessionAuthInfo.SessionHash and Auth_SignOut.KickUserSessionHash, so changing it would break those comparisons across versions. Sha256Hash is the one to use when collision resistance matters.

Session Tags

Sessions can include tags for metadata:

csharp
// Create session with tags
var session = Session.New().WithTag("tenant", "acme");

// Get tag value
var tenant = session.GetTag("tenant"); // "acme"

// Get all tags
var tags = session.GetTags(); // "tenant=acme"

Default Session

The Session.Default (ID = "~") is special:

  • Used by Blazor WebAssembly clients that can't access the real session ID
  • Automatically replaced with the real session by RpcDefaultSessionReplacer on the server
csharp
// On Blazor WASM client
SessionResolver.Session = Session.Default;

// When calling server methods, Session.Default is auto-replaced
var user = await Auth.GetUser(Session.Default, ct);
// Server sees the real session from the cookie

SessionInfo

View Source

SessionInfo contains full session metadata.

Properties

PropertyTypeDescription
SessionHashstringShort hash identifying the session
VersionlongOptimistic concurrency version
CreatedAtMomentWhen the session was created
LastSeenAtMomentLast activity timestamp
IPAddressstringClient IP address
UserAgentstringClient user agent string
OptionsPropertyBagCustom session options
AuthenticatedIdentityUserIdentityThe identity used to authenticate
UserIdstringAssociated user ID
IsSignOutForcedboolWhether forced sign-out was triggered

SessionAuthInfo

View Source

SessionAuthInfo is a lightweight subset of SessionInfo containing only authentication-related data.

Properties

PropertyTypeDescription
SessionHashstringShort hash identifying the session
AuthenticatedIdentityUserIdentityThe identity used to authenticate
UserIdstringAssociated user ID
IsSignOutForcedboolWhether forced sign-out was triggered

Methods

MethodDescription
IsAuthenticated()Returns true if UserId is not empty and not force-signed-out

ISessionResolver

Resolves the current session for the scope.

csharp
public interface ISessionResolver
{
    Session Session { get; set; }
}

Registration

csharp
// Automatically registered by AddFusion()
services.AddScoped<ISessionResolver>(c => new SessionResolver(c));
services.AddScoped(c => c.GetRequiredService<ISessionResolver>().Session);

Usage

csharp
public class MyService : IMyService
{
    private readonly ISessionResolver _sessionResolver;

    [ComputeMethod]
    public virtual async Task<Data> GetData(CancellationToken ct)
    {
        var session = _sessionResolver.Session;
        // Use session...
    }
}

// Or inject Session directly
public class MyComponent : ComponentBase
{
    [Inject] public Session Session { get; set; }
}

Service Design Pattern

Fusion recommends splitting services into frontend (IXxx) and backend (IXxxBackend) interfaces:

InterfacePurposeSessionRPC Exposure
IXxxClient-facing APIRequired (first parameter)Exposed
IXxxBackendServer-side APINot requiredNever exposed

Example

csharp
// Frontend (exposed via RPC)
public interface IOrderService : IComputeService
{
    [ComputeMethod]
    Task<List<Order>> GetMyOrders(Session session, CancellationToken ct = default);
}

// Backend (server-only)
public interface IOrderBackend : IComputeService, IBackendService
{
    [ComputeMethod]
    Task<List<Order>> GetAllOrders(CancellationToken ct = default);

    [CommandHandler]
    Task CreateOrder(CreateOrderCommand command, CancellationToken ct = default);
}