Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/marchena96/Paradigma-lab1/llms.txt

Use this file to discover all available pages before exploring further.

LibraryService API uses JWT Bearer authentication. A signed token is issued at POST /login and must be attached to every request to a protected endpoint as an Authorization: Bearer <token> header. Requests that are missing or carry an invalid token receive a 401 Unauthorized response automatically — no extra handling is needed in individual controllers.

How it works

1

Client sends credentials

The client POSTs a JSON body containing email and password to /login.
2

AuthController delegates to IAuthenticationService

AuthController.Login passes the credentials to IAuthenticationService.AuthenticateAsync. If the credentials are invalid the method returns null and the controller immediately returns 401 Unauthorized.
3

TokenGenerator signs the JWT

When AuthenticateAsync returns a valid User object, AuthController calls TokenGenerator.GenerateToken(validuser, jwtSettings). The generator builds a set of claims, creates a symmetric HMAC SHA-256 signing key from JwtSettings.SecretKey, and constructs a JwtSecurityToken.
4

Claims are embedded in the token

Three standard claims are written into the JWT payload: NameIdentifier (the user’s integer ID as a string), Email, and Role.
5

Token is returned to the client

The signed, compact token string is returned inside a TokenResponse record. The token expires one hour from issuance (DateTime.UtcNow.AddHours(1)) and the server validates lifetime with zero clock skew, meaning no grace period is applied.

Getting a token

Send a POST request to /login with a JSON body containing the email and password fields:
curl -s -X POST https://localhost:7098/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin","password":"1234"}'
A successful response (200 OK) returns the TokenResponse record serialised as JSON:
{"token": "<jwt-string>"}
If the credentials do not match, the API returns 401 Unauthorized with an empty body.

Using the token

Pass the token in the Authorization header on every request to a protected endpoint:
curl -s https://localhost:7098/api/libraries/1/books \
  -H "Authorization: Bearer <jwt-string>"
Replace <jwt-string> with the exact value of the token field returned by /login.

Token structure

The JWT payload contains three claims built from the authenticated User object:
ClaimTypeValue
NameIdentifierClaimTypes.NameIdentifierUser ID (integer serialised as a string)
EmailClaimTypes.EmailUser’s email address
RoleClaimTypes.RoleUser’s role (e.g. admin)

Validation parameters

The JWT Bearer middleware is configured in Startup.ConfigureServices with the following TokenValidationParameters:
ParameterSetting
AlgorithmHS256 (HMAC SHA-256)
IssuerMyApp (from JwtSettings.Issuer)
Audiencelocalhost:80 (from JwtSettings.Audience)
Signing keySymmetric key derived from JwtSettings.SecretKey (UTF-8 bytes)
Clock skewZero (TimeSpan.Zero) — no grace period
Token lifetimeValidated (ValidateLifetime = true)
Both issuer and audience validation are enabled (ValidateIssuer = true, ValidateAudience = true), so a token issued with a different issuer or audience string will be rejected even if the signature is valid.

Protected endpoints

AuthController is the only controller with an access-control attribute. POST /login is decorated with [AllowAnonymous] and is always publicly accessible — no token is needed to obtain one. All other endpoints in the API do not carry an [Authorize] attribute and are accessible without a token at the controller level.
MethodRouteAccess
POST/loginPublic — [AllowAnonymous]
GET/api/libraries/{libraryId}/booksNo [Authorize] attribute
POST/api/libraries/{libraryId}/booksNo [Authorize] attribute

TokenGenerator source

The full implementation of TokenGenerator.GenerateToken used to sign every token:
public static class TokenGenerator
{
    public static string GenerateToken(User user, JwtSettings jwtSettings) 
    {
        var claims = new[]
        {
            new Claim (ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim (ClaimTypes.Email, user.Email),
            new Claim (ClaimTypes.Role, user.Role)
        };

        // Crea una llave simetrica para utilzar cinfrando el token.
        SymmetricSecurityKey key = new SymmetricSecurityKey (Encoding.UTF8.GetBytes(jwtSettings.SecretKey));

        // Crear la llave que garantiza que el Token fue emitido por este servicio.
        var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        // Contruye el token
        var token = new JwtSecurityToken(
            issuer: jwtSettings.Issuer,
            audience: jwtSettings.Audience,
            claims: claims,
            expires: DateTime.UtcNow.AddHours(1),
            signingCredentials: cred
        );        

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}
The default credentials (email: "admin", password: "1234") and the SecretKey value ("a_very_long_super_secret_key_here") are hardcoded for lab and development use only. AuthenticationService.AuthenticateAsync checks these values with a literal string comparison, not a database lookup. Replace both the credentials and the secret key before deploying to any shared or production environment.

Build docs developers (and LLMs) love