Custom Shield
Create your own authentication mechanism by implementing IShieldAuth.
Implement IShieldAuth
[Service(typeof(IShieldAuth))]
public class ApiKeyAuth : IShieldAuth
{
private readonly IVault<ApiKeyVault> _keys;
public ApiKeyAuth(IVault<ApiKeyVault> keys)
{
_keys = keys;
}
public async Task<AuthResult> HandleAuthAsync(IAuthContext context)
{
string apiKey = "";
if (context is HttpAuthContext http)
apiKey = http.HttpContext.Request.Headers["X-Api-Key"].ToString();
if (string.IsNullOrEmpty(apiKey))
return new AuthResult(AuthorizationResult.Failed(), null!);
var key = await _keys.Where(k => k.Key == apiKey).FirstOrDefaultAsync();
if (key == null)
return new AuthResult(AuthorizationResult.Failed(), null!);
var details = new AuthDetails(apiKey, key.OwnerId, "", "", TimeSpan.FromHours(1));
return new AuthResult(AuthorizationResult.Success(), details);
}
}
Create a Shield Alias
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class ApiKeyShieldAttribute : ShieldAttribute
{
public ApiKeyShieldAttribute() : base(typeof(ApiKeyAuth)) { }
}
Use It
// On a portal (works on WebSocket, TCP, UDP)
[Portal("/game")]
[ApiKeyShield]
public class SecurePortal : AltruistPortal { ... }
// On an HTTP controller
[ApiController]
[Route("/api/external")]
[ApiKeyShield]
public class ExternalApiController : ControllerBase { ... }
// On a single method
[ApiKeyShield]
[Gate("admin-action")]
public async Task OnAdminAction(AdminPacket p, string clientId) { ... }
The IAuthContext
Your HandleAuthAsync receives an IAuthContext. Check which transport the request came from:
public async Task<AuthResult> HandleAuthAsync(IAuthContext context)
{
if (context is HttpAuthContext http)
{
// HTTP / WebSocket — access HttpContext, headers, cookies
var token = http.HttpContext.Request.Headers["Authorization"].ToString();
}
else
{
// TCP / UDP — access raw token from context
var token = context.Token;
}
}
Note:
See Authentication & Authorization for the built-in JWT and session shield system.