Skip to main content

Overview

The Trippins API uses JWT (JSON Web Token) authentication to secure endpoints and verify user identity. Most API endpoints require a valid JWT token to access protected resources.
JWT tokens are generated during login and must be included in the Authorization header for all authenticated requests.

How JWT Authentication Works

The authentication flow follows these steps:
  1. User Login: Client sends credentials (email and password) to the login endpoint
  2. Token Generation: Server validates credentials and returns a JWT token with user roles
  3. Token Storage: Client stores the token securely (typically in memory or secure storage)
  4. Authenticated Requests: Client includes the token in the Authorization header
  5. Token Validation: Server validates the token and grants access if valid

Login Endpoint

POST /v1/api/login

Authenticates a user with their email and password, returning a JWT token and user roles.
email
string
required
User’s email address
password
string
required
User’s password

Request Example

curl -X POST https://localhost:8443/v1/api/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "securePassword123"
  }'
// JavaScript/Node.js example
const response = await fetch('https://localhost:8443/v1/api/login', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    email: '[email protected]',
    password: 'securePassword123'
  })
});

const data = await response.json();
console.log('JWT Token:', data.jwt);
console.log('User Roles:', data.roles);
# Python example
import requests

response = requests.post(
    'https://localhost:8443/v1/api/login',
    json={
        'email': '[email protected]',
        'password': 'securePassword123'
    }
)

data = response.json()
jwt_token = data['jwt']
roles = data['roles']

Success Response (200 OK)

{
  "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlcyI6WyJST0xFX1VTRVIiXSwic3ViIjoiam9obi5kb2VAZXhhbXBsZS5jb20iLCJpYXQiOjE3MDk1NjQ4MDAsImV4cCI6MTcwOTYwMDgwMH0.abc123...",
  "roles": [
    "ROLE_USER"
  ]
}
jwt
string
The JWT access token to use for authenticated requests. This token is valid for 10 hours from the time of issuance.
roles
array
Array of role strings assigned to the user. Common roles include ROLE_USER and ROLE_ADMIN.

Error Responses

{
  "error": "Unauthorized",
  "message": "Bad credentials"
}
The email or password provided is incorrect.
{
  "error": "Bad Request",
  "message": "Invalid input"
}
The request body is malformed or missing required fields.

Including JWT in Requests

Once you have obtained a JWT token, include it in subsequent API requests using one of two methods: Include the token in the Authorization header with the Bearer scheme:
curl https://localhost:8443/v1/api/houses \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
// JavaScript example
const response = await fetch('https://localhost:8443/v1/api/houses', {
  headers: {
    'Authorization': `Bearer ${jwtToken}`
  }
});
# Python example
headers = {
    'Authorization': f'Bearer {jwt_token}'
}
response = requests.get('https://localhost:8443/v1/api/houses', headers=headers)
The API also accepts JWT tokens via cookies. The cookie must be named JWT:
curl https://localhost:8443/v1/api/houses \
  --cookie "JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
The Authorization header method is preferred for API clients. Cookie-based authentication is primarily used by the web application.

JWT Token Structure

The JWT token contains encoded information about the authenticated user:

Token Components

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9    ← Header
.
eyJyb2xlcyI6WyJST0xFX1VTRVIiXSwic3ViIj  ← Payload
oiam9obi5kb2VAZXhhbXBsZS5jb20iLCJpYXQi
OjE3MDk1NjQ4MDAsImV4cCI6MTcwOTYwMDgwMH0
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c  ← Signature

Decoded Payload

{
  "roles": ["ROLE_USER"],
  "sub": "[email protected]",
  "iat": 1709564800,
  "exp": 1709600800
}
roles
array
User’s assigned roles for authorization
sub
string
Subject - the user’s email address
iat
integer
Issued At - Unix timestamp when token was created
exp
integer
Expiration - Unix timestamp when token expires

Token Expiration and Renewal

Token Lifetime

JWT tokens issued by the Trippins API are valid for 10 hours from the time of creation.
private String createToken(Map<String, Object> claims, String subject) {
    return Jwts.builder()
            .setClaims(claims)
            .setSubject(subject)
            .setIssuedAt(new Date(System.currentTimeMillis()))
            .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) // 10 hours
            .signWith(SECRET_KEY, SignatureAlgorithm.HS256)
            .compact();
}

Handling Expired Tokens

When a token expires, API requests will fail with a 401 Unauthorized response. To handle this:
  1. Detect Expiration: Check for 401 responses
  2. Re-authenticate: Prompt the user to log in again
  3. Obtain New Token: Call /v1/api/login with credentials
The API does not currently support refresh tokens. Users must re-authenticate with their email and password after token expiration.

Token Validation Flow

The server validates tokens on every request using the JwtRequestFilter:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {

    final String authorizationHeader = request.getHeader("Authorization");

    String username = null;
    String jwt = null;

    if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
        jwt = authorizationHeader.substring(7);
        username = jwtUtil.extractUsername(jwt);
    }
    else{
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("JWT".equals(cookie.getName())) {
                    jwt = cookie.getValue();
                    username = jwtUtil.extractUsername(jwt);
                }
            }
    }

    }

    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
        UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
        if (jwtUtil.validateToken(jwt, userDetails)) {
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            usernamePasswordAuthenticationToken
                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        }
    }
    chain.doFilter(request, response);
}

Role-Based Authorization

The Trippins API uses role-based access control (RBAC) to restrict access to certain endpoints.

Available Roles

ROLE_USER
role
Standard user role - Can manage their own reservations, create reviews, and browse houses
ROLE_ADMIN
role
Administrator role - Can accept/deny houses, manage all users, and moderate content

Admin-Only Endpoints

Certain endpoints require the ROLE_ADMIN role:
# Accept a house (Admin only)
PUT /v1/api/admin/houses/decision/{houseId}

# Deny a house (Admin only)
DELETE /v1/api/admin/houses/decision/{houseId}

# Accept a reservation (Admin only)
PUT /v1/api/admin/reservations/decision/{reservationId}

# Deny a reservation (Admin only)
DELETE /v1/api/admin/reservations/decision/{reservationId}
Attempting to access admin-only endpoints without ROLE_ADMIN returns a 403 Forbidden response.

Example: Admin Request

# Login as admin
curl -X POST https://localhost:8443/v1/api/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "adminPass123"
  }'

# Response includes ROLE_ADMIN
{
  "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "roles": ["ROLE_USER", "ROLE_ADMIN"]
}

# Use token to access admin endpoint
curl -X PUT https://localhost:8443/v1/api/admin/houses/decision/1 \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Security Best Practices

  • Never store JWT tokens in localStorage (vulnerable to XSS attacks)
  • Use httpOnly cookies or secure in-memory storage
  • For mobile apps, use secure keychain/keystore
  • Always use HTTPS to prevent token interception
  • The API base URL uses https:// scheme
  • Never transmit tokens over unencrypted connections
  • Monitor token expiration time
  • Implement automatic re-authentication flow
  • Handle 401 responses gracefully
  • Each user should have their own token
  • Never share tokens between users or devices
  • Treat tokens like passwords
  • Ensure SSL certificate validation is enabled
  • Don’t disable certificate verification in production

Authentication Implementation Example

Here’s a complete example of implementing authentication in a client application:
class TrippinsAPIClient {
  constructor() {
    this.baseURL = 'https://localhost:8443/v1/api';
    this.token = null;
    this.roles = [];
  }

  async login(email, password) {
    try {
      const response = await fetch(`${this.baseURL}/login`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ email, password })
      });

      if (!response.ok) {
        throw new Error('Authentication failed');
      }

      const data = await response.json();
      this.token = data.jwt;
      this.roles = data.roles;
      
      // Store token securely (example uses sessionStorage)
      sessionStorage.setItem('jwt', this.token);
      
      return data;
    } catch (error) {
      console.error('Login error:', error);
      throw error;
    }
  }

  async makeAuthenticatedRequest(endpoint, options = {}) {
    if (!this.token) {
      throw new Error('Not authenticated. Please login first.');
    }

    const headers = {
      'Authorization': `Bearer ${this.token}`,
      'Content-Type': 'application/json',
      ...options.headers
    };

    try {
      const response = await fetch(`${this.baseURL}${endpoint}`, {
        ...options,
        headers
      });

      if (response.status === 401) {
        // Token expired or invalid
        this.token = null;
        sessionStorage.removeItem('jwt');
        throw new Error('Session expired. Please login again.');
      }

      return response;
    } catch (error) {
      console.error('API request error:', error);
      throw error;
    }
  }

  async getHouses() {
    const response = await this.makeAuthenticatedRequest('/houses');
    return response.json();
  }

  isAdmin() {
    return this.roles.includes('ROLE_ADMIN');
  }
}

// Usage
const client = new TrippinsAPIClient();

// Login
await client.login('[email protected]', 'password123');

// Make authenticated requests
const houses = await client.getHouses();
console.log('Houses:', houses);

// Check admin status
if (client.isAdmin()) {
  console.log('User has admin privileges');
}

Troubleshooting

Problem: Login fails with “Bad credentials” error.Solutions:
  • Verify the email address is correct
  • Ensure the password matches the registered account
  • Check that the user account exists in the database
Problem: API requests fail even with a token.Solutions:
  • Check if the token has expired (10-hour lifetime)
  • Verify the token is included in the Authorization header
  • Ensure the Bearer prefix is present: Bearer {token}
  • Re-authenticate to obtain a fresh token
Problem: Authenticated requests return 403 Forbidden.Solutions:
  • Verify the user has the required role for the endpoint
  • Admin endpoints require ROLE_ADMIN role
  • Check that the user can access the requested resource
Problem: JWT filter cannot extract username from token.Solutions:
  • Verify the token format is correct
  • Check the Authorization header format: Authorization: Bearer {token}
  • Ensure no extra spaces or characters in the header
  • If using cookies, verify the cookie name is exactly “JWT”

Next Steps

User Management API

Learn how to create and manage user accounts

Housing API

Explore endpoints for managing hotel listings

Reservations API

Handle booking and reservation operations

Reviews API

Manage customer reviews and ratings

Build docs developers (and LLMs) love