Files
XpenselyServer/docs/API.md
T

5.6 KiB
Raw Blame History

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

GET /

Health check. No authentication required.

Response: 200 OK

Welcome

4.2 Users

Base path: /api/users


POST /api/users/createUser — Register a user

Auth required: No

Request body:

{
  "username": "alice",
  "googleId": "118400012345678901234"
}
Field Type Constraints
username String Required. 330 chars. Pattern: ^[a-zA-Z0-9_.\-]+$
googleId String Required. Non-blank. Must match the JWT sub from Google.

Success response: 200 OK — returns the created AppUser object.

Error responses:

Status Condition
400 Validation failure (field errors returned as {"fieldName": "message"})
409 username already taken

GET /api/users — Get user by ID

Auth required: Yes

Query params:

Param Type Required Description
id Long Yes Database ID of the user

Success response: 200 OK — returns AppUser.

Error responses:

Status Condition
404 No user found for id

GET /api/users/byName — Get user by username

Auth required: No

Query params:

Param Type Required Description
username String Yes Exact username (case-sensitive)

Success response: 200 OK — returns AppUser.

Error responses:

Status Condition
404 No user found for username

GET /api/users/byGoogleId — Get user by Google ID

Auth required: Yes

Query params:

Param Type Required Description
id String Yes Google sub claim

Success response: 200 OK — returns AppUser.

Error responses:

Status Condition
404 No user found for that Google ID

DELETE /api/users — Delete a user

Auth required: Yes

Query params:

Param Type Required Description
id Long Yes Database ID of the user to delete

Success response: 200 OK — returns the deleted AppUser.

Error responses:

Status Condition
404 No user found for id

4.3 Expense Lists

TODO

5. Data Models

TODO

6. Error Handling

TODO

7. Recent Changes — feature/security-hardening

TODO