Files
XpenselyServer/docs/API.md
T

3.2 KiB

Xpensely Server — API Reference

Last updated: 2026-05-09 · Branch: feature/security-hardening

Table of Contents

  1. Overview
  2. Authentication
  3. Rate Limiting
  4. Endpoints
  5. Data Models
  6. Error Handling
  7. Recent Changes — feature/security-hardening

1. Overview

Xpensely Server is a Spring Boot REST API that manages shared expense lists for pairs of users. It uses Google OAuth2 JWT tokens for authentication. All protected endpoints require a valid Bearer token in the Authorization header.

Base URL (local dev): http://localhost:8080

Content-Type: application/json for all request and response bodies.

Public endpoints (no auth required):

Method Path Description
GET / Health check — returns "Welcome"
POST /api/users/createUser Register a new user
GET /api/users/byName Look up a user by username

All other endpoints require authentication (see Section 2).

2. Authentication

The server uses OAuth2 Resource Server authentication with Google ID JWT tokens.

How it works

  1. The client authenticates with Google and receives a Google ID JWT.
  2. Every protected API request must include this token in the header:
Authorization: Bearer <google-id-jwt>
  1. The server validates the JWT signature and extracts the sub claim (Google User ID).
  2. The sub value is used to look up the registered AppUser in the database via AuthenticatedUserResolver.
  3. If no AppUser exists for that Google ID, the request is rejected with 403 Forbidden.

Test profile

When the application runs under the test Spring profile (-Dspring.profiles.active=test), all security is disabled — every endpoint is accessible without a token. This is used for automated tests only.

User registration flow

Before a user can call any protected endpoint they must first be registered:

  1. Authenticate with Google to obtain a Google ID JWT.
  2. Call POST /api/users/createUser with the JWT's sub value as googleId and a chosen username.
  3. All subsequent protected calls use the same JWT — the server resolves the caller automatically.

3. Rate Limiting

All requests pass through a RateLimitFilter (implemented with Bucket4j).

Setting Value
Limit 60 requests per minute
Window Rolling 1-minute bucket
Key (authenticated) JWT sub claim (Google User ID)
Key (unauthenticated) X-Forwarded-For header, falling back to remote IP

When the limit is exceeded the server responds with:

HTTP 429 Too Many Requests

No Retry-After header is currently returned. Clients should back off and retry after 60 seconds.

Note: Rate limiting applies in the !test profile only. Tests run without rate limiting.

4. Endpoints

4.1 Home

TODO

4.2 Users

TODO

4.3 Expense Lists

TODO

5. Data Models

TODO

6. Error Handling

TODO

7. Recent Changes — feature/security-hardening

TODO