A simple example of a REST API implementing authentication using JSON Web Tokens (JWT). This project was built to demonstrate the core concepts of user authentication, token generation, and protected routes using a clean and minimal setup.
- User registration
- User login with JWT generation
- Token-based authentication
- Protected routes
- Refresh token support
- Simple and easy-to-understand structure
- Kotlin
- Ktor (Server)
- JWT Authentication
- Exposed (ORM)
- In-memory database (for simplicity)
This project is intended for learning and demonstration purposes. It shows how to:
- Implement authentication using JWT
- Structure a simple backend API
- Handle login and protected endpoints
- Work with tokens (access & refresh)
-
User registers with email and password
-
User logs in and receives a JWT (access token)
-
The token is sent in the
Authorizationheader for protected requests:Authorization: Bearer <token> -
The server validates the token before granting access
Health check route
Responses:
200 OK→ Server is running ("ok")
Authenticate user and return JWT tokens
Request:
{
"email": "test@example.com",
"password": "123456"
}Responses:
200 OK→ Authentication successful, returns tokens400 Bad Request→ Invalid request body or parsing error404 Not Found→ Invalid email or password
Create a new user and return JWT tokens
Request:
{
"name": "test",
"email": "test@example.com",
"password": "123456"
}Responses:
201 Created→ User successfully created, returns tokens400 Bad Request→ Invalid request body or parsing error409 Conflict→ A user with this email already exists
All routes below require the
Authorizationheader:
Authorization: Bearer <token>
Generate new tokens using a refresh token
Token Requirement:
- Must be a refresh token (
type = "refresh")
Responses:
200 OK→ New tokens generated401 Unauthorized→ Missing/invalid token or invalid user ID403 Forbidden→ Token is not a refresh token404 Not Found→ User not found
Validate an access token and return user data
Token Requirement:
- Must be an access token (
type = "access")
Responses:
200 OK→ Token is valid, returns user data400 Bad Request→ Missing or malformed token claim (type)401 Unauthorized→ Missing/invalid token or claims403 Forbidden→ Token is not an access token
Success Response Example:
{
"id": 0,
"name": "test",
"email": "test@example.com"
}-
Access Token
- Used to access protected routes
- Required for
/verify
-
Refresh Token
- Used to generate new tokens
- Required for
/refreshToken
Using the wrong token type will result in a 403 Forbidden.
Common status codes used across the API:
400 Bad Request→ Invalid request or unexpected error401 Unauthorized→ Authentication failure or invalid token403 Forbidden→ Valid token but wrong type404 Not Found→ Resource not found409 Conflict→ Business rule violation (e.g., email already exists)
-
Clone the repository:
git clone https://github.com/MayckGomes/JWT-Login-API-Simple.git -
Navigate to the project folder:
cd JWT-Login-API-Simple -
Run the application:
./gradlew run -
The server will start (default:
http://localhost:8080)
You can test the API using tools like:
- Postman
- Insomnia
- cURL
-
This project uses an in-memory database, so data will be lost when the server restarts
-
It is not production-ready and should be extended with:
- Password hashing (e.g., BCrypt)
- Persistent database
- Better error handling
- Token revocation strategy (e.g., Redis)
Made for educational purposes 💡