Authentication and Authorization in APIs and Applications
When developing APIs and applications, two main questions must be addressed: “Who will access?” and “Can they access?” These are directly related to authentication and authorization, which are essential for ensuring security and proper application behavior.
Authentication vs. Authorization
- Authentication: Identifies who is accessing the system, making the user or service authentic.
- Authorization: Determines whether the who is allowed to access a resource or perform a specific action.
The process:
- The application first validates the requested route.
- Then checks whether authentication and authorization are required for the resource.
Authentication
Different methods can be used for authentication, with the most common being:
- JWT (JSON Web Token)
- OAuth 2.0
- Cookie
- Basic Authentication
JWT Example
When JWT authentication is configured, the authentication pipeline verifies the token’s validity when a request reaches the application. If valid, the pipeline allows the request to proceed; otherwise, it returns an authentication error.
Bypassing Authentication
If an endpoint does not require authentication, use the [AllowAnonymous]
attribute to skip authentication for that specific route.
Without Authentication:
[AllowAnonymous]
[HttpGet("public")]
public IActionResult PublicEndpoint()
{
return Ok("This endpoint does not require authentication.");
}
With Authentication:
[Authorize]
[HttpGet("protected")]
public IActionResult ProtectedEndpoint()
{
return Ok("This endpoint requires authentication.");
}
[AllowAnonymous]
: Skips authentication for the endpoint.[Authorize]
: Requires authentication. If authentication fails, the server returns 401 - Unauthorized.
Attributes can be applied:
- Globally to the controller.
- Individually to specific endpoints.
Note: Attributes applied to specific endpoints override those applied at the controller level.
Authorization
Authorization can be configured using roles or policies. These tools provide detailed control over which users can access specific endpoints.
Policies
Policies allow you to define custom rules for authorization. For example:
- An endpoint validating two-factor authentication may require the
TwoFactorPending
attribute to beTrue
before access is granted.
Creating a Policy
- Configure the policy in
Program.cs
:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("TwoFactorPending", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(c =>
c.Type == "TwoFactorPending" && c.Value == "True")));
});
2. Apply the policy to the endpoint:
[Authorize(Policy = "TwoFactorPending")]
[HttpGet("two-factor")]
public IActionResult TwoFactorEndpoint()
{
return Ok("Two-factor authentication is pending.");
}
If the policy conditions are not met, the application returns 403 — Forbidden.
Roles
Roles define permissions based on user groups or specific roles.
Example with Roles:
[Authorize(Roles = "Admin")]
[HttpGet("admin-only")]
public IActionResult AdminOnlyEndpoint()
{
return Ok("Access granted to administrators only.");
}
The middleware verifies whether the JWT token contains the required role claim. If not, the server returns 403 — Forbidden.
JWT with Claims
Information such as roles and policies is often embedded within the JWT token. A typical JWT token payload might look like this:
{
"sub": "1234567890",
"name": "John Doe",
"roles": ["Admin", "User"],
"iat": 1516239022
}
When processing the token:
- The middleware extracts the claims.
- It verifies whether the roles or policy conditions meet the endpoint’s requirements.
To include roles in the JWT token during generation:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, "user@example.com"),
new Claim(ClaimTypes.Role, "Admin"),
new Claim("TwoFactorPending", "True")
};
var token = new JwtSecurityToken(
issuer: "YourIssuer",
audience: "YourAudience",
claims: claims,
expires: DateTime.UtcNow.AddHours(1),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
Conclusion
By effectively combining authentication and authorization, you can protect application resources, ensuring only authorized users or services have access. Roles and policies provide granular control, while modern methods like JWT offer a secure and efficient authentication mechanism.