Authentication & Authorization

Altruist provides built-in JWT authentication, a Shield system for protecting portals and HTTP endpoints, and a session upgrade flow for real-time connections.

Config

altruist:
  security:
    mode: "jwt"
    key: "your-base64-secret-key"

Note:

Setting mode: "jwt" enables the built-in JwtAuth, JwtTokenValidator, and JwtTokenIssuer services automatically.

JWT Auth Controller

Extend JwtAuthController to get signup, login, refresh, and upgrade endpoints:

[ApiController]
[Route("/auth")]
public class AuthController : JwtAuthController
{
    public AuthController(
        IJwtTokenValidator validator,
        ILoginService loginService,
        TokenSessionSyncService syncService,
        IJwtTokenIssuer issuer,
        IAuthService authService,
        ILoggerFactory loggerFactory)
        : base(validator, loginService, syncService, issuer, authService, loggerFactory)
    {
    }
}

This gives you these endpoints:

EndpointMethodDescription
/auth/signupPOSTCreate a new account
/auth/login/emailpwdPOSTLogin with email + password
/auth/login/unamepwdPOSTLogin with username + password
/auth/refreshPOSTRefresh an expired access token
/auth/upgradePOSTUpgrade JWT to session token

Signup

curl -X POST http://localhost:3000/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "player@example.com", "username": "hero", "password": "secret123"}'

Login

curl -X POST http://localhost:3000/auth/login/unamepwd \
  -H "Content-Type: application/json" \
  -d '{"username": "hero", "password": "secret123"}'

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIs...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

Client Types (HTTP Auth)

public class LoginResponse
{
    [JsonPropertyName("accessToken")] public string AccessToken { get; set; } = "";
    [JsonPropertyName("refreshToken")] public string RefreshToken { get; set; } = "";
}

public class UpgradeResponse
{
    [JsonPropertyName("accessToken")] public string AccessToken { get; set; } = "";
    [JsonPropertyName("refreshToken")] public string RefreshToken { get; set; } = "";
    [JsonPropertyName("accessExpiration")] public DateTime AccessExpiration { get; set; }
    [JsonPropertyName("refreshExpiration")] public DateTime RefreshExpiration { get; set; }
}

Custom Claims

Override GetClaimsForLogin to add game-specific claims:

protected override IEnumerable<Claim> GetClaimsForLogin(AccountModel account, LoginRequest request)
{
    var claims = base.GetClaimsForLogin(account, request).ToList();
    claims.Add(new Claim("AccountId", account.StorageId));
    claims.Add(new Claim(ClaimTypes.Role, "player"));
    return claims;
}

The Shield System

[Shield] protects portals and HTTP controllers. It works across all transports — WebSocket, TCP, UDP, and HTTP.

Protecting a Portal

[Portal("/game")]
[JwtShield]
public class SecureGamePortal : AltruistPortal
{
    [Gate("action")]
    public async Task OnAction(ActionPacket packet, string clientId)
    {
        // Only authenticated clients reach here
    }
}

Protecting an HTTP Controller

[ApiController]
[Route("/api/admin")]
[JwtShield]
public class AdminController : ControllerBase
{
    [HttpGet("stats")]
    public IActionResult GetStats()
    {
        // Only requests with valid JWT reach here
    }
}

Note:

[JwtShield] is a shorthand for [Shield(typeof(JwtAuth))]. Both work the same way.

Method-Level Shield

Apply shields to individual methods instead of the whole class:

[Portal("/game")]
public class GamePortal : AltruistPortal
{
    [Gate("public-chat")]
    public async Task OnPublicChat(ChatPacket p, string clientId)
    {
        // No auth required
    }

    [JwtShield]
    [Gate("private-action")]
    public async Task OnPrivateAction(ActionPacket p, string clientId)
    {
        // Auth required for this gate only
    }
}

How Shield Works

Loading diagram...

Custom Shield

You can create your own authentication mechanism by implementing IShieldAuth. See Custom Shield for the full guide with examples.

ASP.NET [Authorize]

Standard ASP.NET [Authorize] works on HTTP controllers. Altruist's JWT config sets up the authentication middleware automatically:

[ApiController]
[Route("/api/data")]
[Authorize]
public class DataController : ControllerBase
{
    [HttpGet]
    public IActionResult GetData()
    {
        var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        return Ok(new { userId });
    }

    [Authorize(Roles = "admin")]
    [HttpDelete("{id}")]
    public IActionResult Delete(string id) { ... }
}

Shield vs Authorize

[JwtShield][Authorize]
HTTPYesYes
WebSocketYesNo
TCP / UDPYesNo
PortalsYesNo
ControllersYesYes
Role-basedVia claimsBuilt-in Roles = "admin"

Note:

Use [JwtShield] as your default — it works everywhere. Use [Authorize] only when you need ASP.NET-specific features like role policies on HTTP controllers.