Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Gianluca-X/DigitalMoney/llms.txt

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

Digital Money House uses JSON Web Tokens (JWT) for all API authentication. Every protected endpoint requires a signed Bearer token issued by the auth-service. Tokens are generated with the HS256 algorithm, carry the authenticated user’s email as the subject, embed the user’s role, and expire 24 hours after they are issued. This page walks through the full lifecycle — from creating an account to attaching the token to every API call.

Authentication Flow

1

Register a new user

Create your user account by sending a POST request to /users/register. Supply your personal details in the request body. A successful call returns a 201 Created response with your new user record.
curl -X POST http://localhost:8085/users/register \
  -H 'Content-Type: application/json' \
  -d '{
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "jane@example.com",
    "password": "S3cur3P@ss!",
    "dni": "12345678"
  }'
2

Verify your email address

After registration the auth-service sends a verification email to the address you provided. Check your inbox and click the verification link, or call the verification endpoint directly with the code from the email:
curl -X GET "http://localhost:8085/auth/verify?code=YOUR_VERIFICATION_CODE"
Login attempts made before email verification is complete will be rejected with 403 Forbidden and an EmailNotVerifiedException error.
3

Log in and receive your JWT token

Once your email is verified, exchange your credentials for a JWT token:
curl -X POST http://localhost:8085/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email": "jane@example.com", "password": "S3cur3P@ss!"}'
A successful login returns a JSON response containing the token:
{
  "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqYW5lQGV4YW1wbGUuY29tIiwicm9sZSI6IlVTRVIiLCJpYXQiOjE3MDAwMDAwMDAsImV4cCI6MTcwMDA4NjQwMH0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
}
Copy the value of token — you will include it in every subsequent request.
4

Attach the token to API requests

Pass the token in the Authorization header as a Bearer credential:
curl http://localhost:8085/accounts/1/balance \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...'
Every downstream service — including accounts-service and user-service — validates this header independently before processing the request.

JWT Token Details

Tokens are produced by JwtUtil in the auth-service and signed with a shared secret configured via jwt.secret. The key properties of every token are:
PropertyValue
AlgorithmHS256
Subject (sub)User’s email address
Role claimrole (e.g. "USER" or "ADMIN")
Issued at (iat)Current UTC timestamp
Expiry (exp)Issued-at + 86 400 000 ms (24 hours)
The relevant token-generation code:
public String generateToken(User user) {
    return Jwts.builder()
            .setSubject(user.getEmail())
            .claim("role", user.getRol().name())
            .setIssuedAt(new Date())
            .setExpiration(new Date(System.currentTimeMillis() + 86400000))
            .signWith(SignatureAlgorithm.HS256, secret)
            .compact();
}

How the Token is Validated

Auth-service filter

The JwtAuthFilter in the auth-service runs on every request (except /auth/login and /auth/register). It:
  1. Reads the Authorization header.
  2. Strips the Bearer prefix to extract the raw token string.
  3. Calls JwtUtil.getUsernameFromToken() to extract the email subject.
  4. Loads user details from the database and verifies the token signature with JwtUtil.isValidToken().
  5. Sets the authenticated principal in Spring Security’s SecurityContextHolder.

API Gateway filter

The Spring Cloud Gateway passes the Authorization header through to every downstream service unchanged via JwtGatewayFilter:
if (token != null && token.startsWith("Bearer ")) {
    exchange.getRequest().mutate()
            .header(HttpHeaders.AUTHORIZATION, token)
            .build();
}

Accounts-service filter

JwtAuthenticationFilter in the accounts-service parses the JWT directly (it does not call the auth-service). It extracts the role claim (or falls back to a roles list), builds the corresponding Spring Security GrantedAuthority list, and looks up the matching Account entity by the email subject before admitting the request.

Role-Based Access Control

Every user has one of two roles embedded in their JWT:
RoleAccess
ROLE_USERCan only read and modify their own data.
ROLE_ADMINCan access and modify data for any account or user.
Controllers enforce this through a checkOwnerOrAdmin pattern. Here is the canonical implementation from the user-service:
public void checkOwnerOrAdmin(Authentication auth, Long targetUserId) {
    String email = auth.getPrincipal().toString();
    User user = userService.findByEmail(email);

    if (user == null) {
        throw new UnauthorizedException("Usuario no encontrado.");
    }

    boolean isAdmin = auth.getAuthorities()
            .stream()
            .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));

    boolean isOwner = user.getId().equals(targetUserId);

    if (!isAdmin && !isOwner) {
        throw new UnauthorizedException("No tienes permisos para acceder a este recurso.");
    }
}
This helper is called before every mutating or sensitive read operation. For example, DELETE /users/delete/{userId} will succeed only if the authenticated user is the owner of that record or an admin.

Internal Service-to-Service Tokens

Some endpoints — such as POST /accounts/create — are called by other microservices rather than by external clients. These inter-service calls authenticate with a static internal.token value configured in application.properties:
if (authHeader != null && authHeader.equals("Bearer " + internalToken)) {
    // Internal request authorised — proceed without a user JWT
}
The internal.token is for service-to-service communication only. Never expose it to client applications or include it in any front-end code.

Token Expiry and Refresh

Tokens are valid for exactly 24 hours from the moment they are issued. There is no refresh-token endpoint — once a token expires, the user must log in again with POST /auth/login to obtain a new one.
Build your client to check for a 401 Unauthorized response and automatically redirect the user to the login screen when their token has expired.

Security Best Practices

  • Never store tokens in localStorage — use HttpOnly cookies or secure in-memory storage to reduce XSS exposure.
  • Always use HTTPS in production. Transmitting a Bearer token over plain HTTP allows it to be intercepted in transit.
  • Do not log tokens in application or access logs. The token is equivalent to a password for the duration of its validity.
  • Treat the jwt.secret value as a highly sensitive secret. Rotate it immediately if it is ever exposed.

Build docs developers (and LLMs) love