Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Yurben-bit/Sistema-de-Administraci-n-Escolar-Backend/llms.txt

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

Overview

EduTec Backend implements a stateless authentication system using JSON Web Tokens (JWT). This approach eliminates the need for server-side session storage, making the API scalable and suitable for distributed environments.
The application uses jjwt library version 0.11.5 for JWT operations, providing modern cryptographic standards and comprehensive token management.

Authentication Flow

The authentication process follows these steps:
┌──────────┐                  ┌──────────────┐                  ┌────────────┐
│  Client  │                  │ AuthController│                  │ JwtService │
└─────┬────┘                  └──────┬───────┘                  └─────┬──────┘
      │                              │                                 │
      │  POST /auth/login            │                                 │
      │  {username, password}        │                                 │
      ├─────────────────────────────>│                                 │
      │                              │                                 │
      │                              │  generateToken(username)        │
      │                              ├────────────────────────────────>│
      │                              │                                 │
      │                              │         JWT Token               │
      │                              │<────────────────────────────────┤
      │                              │                                 │
      │         JWT Token            │                                 │
      │<─────────────────────────────┤                                 │
      │                              │                                 │
  1. Client sends credentials to /auth/login
  2. Controller receives and extracts the LoginRequest DTO
  3. Controller delegates token generation to JwtService
  4. Service creates a signed JWT with username and expiration
  5. Token is returned to the client as a plain string
  6. Client includes token in subsequent requests via Authorization header
The current implementation does not validate credentials against the database. The login endpoint generates tokens for any username without password verification. This should be enhanced with proper authentication logic before production deployment.

JWT Service Implementation

The JwtService class handles all token operations using the JJWT library.

Service Configuration

// src/main/java/com/tecmilenio/edutec/security/JwtService.java:1-13
package com.tecmilenio.edutec.security;

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.security.Key;

@Service
public class JwtService {
    // Clave de al menos 32 caracteres
    private static final String SECRET_KEY = "12345678910111213141516171819200";
    // pre-generando la llave criptográfica solo cuando inicia la aplicación
    private static final Key KEY = Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
Marks this class as a Spring-managed service component, making it available for dependency injection throughout the application.

Token Generation

The generateToken() method creates a signed JWT containing the username and expiration time:
// src/main/java/com/tecmilenio/edutec/security/JwtService.java:19-27
public String generateToken(String username) {
    return Jwts.builder()
            .setSubject(username)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
            // Fíjate en el orden: primero la llave, luego el algoritmo
            .signWith(KEY, SignatureAlgorithm.HS256)
            .compact();
}

Token Claims

Value: Username provided during loginPurpose: Identifies the user this token belongs to
.setSubject(username)
The subject is the primary identifier stored in the token. Subsequent requests can extract this to determine which user is making the request.
Value: Current timestamp in millisecondsPurpose: Records when the token was created
.setIssuedAt(new Date(System.currentTimeMillis()))
Useful for auditing, token refresh logic, and debugging authentication issues.
Value: Current time + 10 hours (36,000,000 milliseconds)Purpose: Defines token validity period
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
Calculation breakdown:
  • 1000 ms = 1 second
  • * 60 = 1 minute
  • * 60 = 1 hour
  • * 10 = 10 hours
Tokens automatically become invalid after 10 hours, requiring users to re-authenticate. This balance between convenience and security can be adjusted based on your requirements.
Algorithm: HMAC-SHA256 (HS256)Key: Pre-computed KEY from the secret
.signWith(KEY, SignatureAlgorithm.HS256)
The signature ensures:
  • Integrity: Token data hasn’t been modified
  • Authenticity: Token was issued by this server
  • Non-repudiation: Only holders of the secret key can create valid tokens
HMAC-SHA256 is a symmetric algorithm, meaning the same key signs and verifies tokens. For asymmetric scenarios (microservices, distributed systems), consider RSA or ECDSA algorithms.

Token Format

Generated tokens follow the standard JWT format:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIiwiaWF0IjoxNzA5MjQwMDAwLCJleHAiOjE3MDkyNzYwMDB9.signature
│─────── Header ──────│──────────────────── Payload ────────────────────────│─ Signature ─│
  • Header: Algorithm and token type (Base64 encoded)
  • Payload: Claims including subject, issued at, expiration (Base64 encoded)
  • Signature: HMAC-SHA256 signature to verify integrity
You can decode tokens at jwt.io for debugging (never share tokens containing sensitive data).

Auth Controller

The AuthController provides the public API endpoint for authentication.

Login Endpoint

// src/main/java/com/tecmilenio/edutec/controller/AuthController.java:1-21
package com.tecmilenio.edutec.controller;

import com.tecmilenio.edutec.dto.LoginRequest;
import com.tecmilenio.edutec.security.JwtService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private JwtService jwtService;

    @PostMapping("/login")
    public String login(@RequestBody LoginRequest loginRequest) {
        System.out.println("El usuario " + loginRequest.getUsername() + " está intentando entrar");
        return jwtService.generateToken(loginRequest.getUsername());
    }
}
Endpoint: POST /auth/login Request Body:
{
  "username": "string",
  "password": "string"
}
Response: Plain text JWT string
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIiwiaWF0IjoxNzA5MjQwMDAwLCJleHAiOjE3MDkyNzYwMDB9.KqJ8z9X...
Status Code: 200 OK
The controller currently logs authentication attempts to the console. Consider using a proper logging framework (SLF4J/Logback) for production applications.

Login Request DTO

The LoginRequest class structures incoming authentication requests:
// src/main/java/com/tecmilenio/edutec/dto/LoginRequest.java:1-31
package com.tecmilenio.edutec.dto;

public class LoginRequest {
    private String username;
    private String password;

    public LoginRequest() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
Fields:
  • username - User’s unique identifier
  • password - User’s password (currently not validated)
Design Pattern: Plain Old Java Object (POJO) with getter/setter methods
Spring automatically deserializes JSON request bodies into this DTO using Jackson. The empty constructor is required for this process.

Security Best Practices

Current Implementation Gaps

The following security measures are missing from the current implementation:
  1. Password Verification: Credentials are not validated against the database
  2. Password Hashing: No BCrypt or similar hashing for stored passwords
  3. Token Validation: No middleware to verify tokens on protected endpoints
  4. Secret Management: Hardcoded secret key in source code
  5. HTTPS Enforcement: No SSL/TLS configuration specified
  6. Rate Limiting: No protection against brute force attacks
  7. Input Validation: No checks for empty/null username or password
Add a UserService to authenticate credentials:
@Service
public class AuthService {
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    public boolean authenticate(String username, String password) {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UnauthorizedException("Invalid credentials"));
        
        return passwordEncoder.matches(password, user.getPassword());
    }
}
Create a filter to verify JWTs on protected endpoints:
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtService jwtService;
    
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain filterChain) {
        String token = extractToken(request);
        if (token != null && jwtService.validateToken(token)) {
            String username = jwtService.extractUsername(token);
            // Set authentication in SecurityContext
        }
        filterChain.doFilter(request, response);
    }
}
Add validation methods to JwtService:
public boolean validateToken(String token) {
    try {
        Jwts.parserBuilder()
            .setSigningKey(KEY)
            .build()
            .parseClaimsJws(token);
        return true;
    } catch (JwtException e) {
        return false;
    }
}

public String extractUsername(String token) {
    return Jwts.parserBuilder()
        .setSigningKey(KEY)
        .build()
        .parseClaimsJws(token)
        .getBody()
        .getSubject();
}
Move the secret to application.properties:
jwt.secret=${JWT_SECRET:default-dev-secret-change-in-production}
jwt.expiration=36000000
Update JwtService:
@Value("${jwt.secret}")
private String secretKey;

@Value("${jwt.expiration}")
private long expirationTime;

@PostConstruct
public void init() {
    this.key = Keys.hmacShaKeyFor(secretKey.getBytes());
}
Use Bean Validation annotations:
public class LoginRequest {
    @NotBlank(message = "Username is required")
    @Size(min = 3, max = 50)
    private String username;
    
    @NotBlank(message = "Password is required")
    @Size(min = 8, message = "Password must be at least 8 characters")
    private String password;
}
Update controller:
@PostMapping("/login")
public String login(@Valid @RequestBody LoginRequest loginRequest) {
    // Validation happens automatically
}
Hash passwords before storing in the database:
@Bean
public PasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder(12);
}
Update User entity:
@PrePersist
@PreUpdate
private void encryptPassword() {
    if (this.password != null && !this.password.startsWith("$2a$")) {
        this.password = passwordEncoder.encode(this.password);
    }
}

Token Usage Example

Once implemented, clients should include tokens in the Authorization header:
GET /api/users/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huZG9lIi...

Dependencies

The JWT implementation relies on these libraries from pom.xml:109-125:
<!-- Dependencias JWT-->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.5</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.5</version>
    <scope>runtime</scope>
</dependency>
  • jjwt-api: Core JWT API and interfaces
  • jjwt-impl: Implementation of JWT specification
  • jjwt-jackson: JSON processing using Jackson library
Spring Security starter (spring-boot-starter-security) is commented out in the POM file, indicating a lightweight custom authentication approach without the full Spring Security framework.

Next Steps

Build docs developers (and LLMs) love