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:
| Endpoint | Method | Description |
|---|---|---|
/auth/signup | POST | Create a new account |
/auth/login/emailpwd | POST | Login with email + password |
/auth/login/unamepwd | POST | Login with username + password |
/auth/refresh | POST | Refresh an expired access token |
/auth/upgrade | POST | Upgrade 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
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] | |
|---|---|---|
| HTTP | Yes | Yes |
| WebSocket | Yes | No |
| TCP / UDP | Yes | No |
| Portals | Yes | No |
| Controllers | Yes | Yes |
| Role-based | Via claims | Built-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.