This repository contains a simple demo project for a secure document management API built with Kotlin and Spring Boot. It functions an OAuth 2.0 Resource Server, securing endpoints with JSON Web Tokens (JWTs). The project highlights best practices for configuring JWT validation, including custom audience checks, and mapping JWT claims (scopes, roles, permissions) to Spring Security authorities for fine-grained access control.
- Framework: Built with Spring Boot and Kotlin.
- Security: Implements an OAuth 2.0 Resource Server using Spring Security.
- Authentication: Secures endpoints using JWT Bearer Tokens.
- JWT Validation: Features a custom JWT decoder with validation for both
issuerandaudienceclaims. - Authorization:
- Demonstrates claim mapping from a JWT (
scope,roles,permissions) to Spring SecurityGrantedAuthorityobjects. - Uses method-level security (
@PreAuthorize) for fine-grained endpoint protection.
- Demonstrates claim mapping from a JWT (
- JDK 17 or newer
- Gradle
-
Clone the repository:
git clone https://github.com/origamifolds/doc-manager-kotlin-demo.git
-
Navigate to the project directory:
cd doc-manager-kotlin-demo -
Run the application:
-
On macOS/Linux:
./gradlew bootRun
-
On Windows:
gradlew.bat bootRun
-
The server will start on http://localhost:8080.
- The application is configured as a stateless resource server, disabling sessions, CSRF, and basic/form login.
- A custom
jwtDecoderbean is configured to validate JWTs against a specificissuer(https://myapp.com/auth) andaudience(http://localhost:8080/api/). - A
jwtAuthenticationConverterbean maps claims from the JWT payload to Spring Security authorities. It processesscope,roles, andpermissionsclaims, prefixing scopes withSCOPE_and roles withROLE_.
The server is configured to use the public.pem file located in src/main/resources to verify the signature of incoming JWTs. The corresponding private.pem is also included in the repository for local testing and token generation.
- Endpoint:
GET /api/fetchDocuments - Description: A protected endpoint to retrieve documents.
- Authorization: Requires a valid JWT Bearer token. To gain access, the token must be valid and grant all of the following authorities:
SCOPE_read:documents(checked at the filter chain level)ROLE_admin(checked via@PreAuthorize)documents:read:all(checked via@PreAuthorize)
To call the protected /api/fetchDocuments endpoint, you must generate a JWT that meets the following criteria:
- Signature: Signed with the
private.pemkey provided in this repository. - Issuer (
issclaim): The value must behttps://myapp.com/auth. - Audience (
audclaim): The value must behttp://localhost:8080/api/. - Payload Claims: The payload must include the claims required to grant the necessary authorities:
scope: A string containing"read:documents"roles: An array containing"admin"permissions: An array containing"documents:read:all"
Example cURL Request:
# Replace <YOUR_GENERATED_JWT> with a valid token
curl -X GET http://localhost:8080/api/fetchDocuments \
-H "Authorization: Bearer <YOUR_GENERATED_JWT>"You can use online tools like jwt.io or a local script to generate a token using the provided RSA keys and the required payload claims.
