{"id":22544366,"url":"https://github.com/hardiksinghbehl/jwt-auth-flow-spring-security","last_synced_at":"2025-10-29T10:22:35.820Z","repository":{"id":40438089,"uuid":"365160272","full_name":"hardikSinghBehl/jwt-auth-flow-spring-security","owner":"hardikSinghBehl","description":"Java backend application using Spring-security to implement JWT based Authentication and Authorization","archived":false,"fork":false,"pushed_at":"2024-06-08T08:07:02.000Z","size":243,"stargazers_count":111,"open_issues_count":0,"forks_count":28,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-09T23:50:52.453Z","etag":null,"topics":["jwt","jwt-authentication","rs512","spring-boot","spring-security","spring-security-jwt","spring-security-rsa","token-revocation"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hardikSinghBehl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-07T08:06:43.000Z","updated_at":"2025-03-20T18:00:17.000Z","dependencies_parsed_at":"2023-10-25T15:51:05.410Z","dependency_job_id":"9b9a1ae7-ba5d-4b38-b795-2d3a1204b3c5","html_url":"https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hardikSinghBehl%2Fjwt-auth-flow-spring-security","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hardikSinghBehl%2Fjwt-auth-flow-spring-security/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hardikSinghBehl%2Fjwt-auth-flow-spring-security/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hardikSinghBehl%2Fjwt-auth-flow-spring-security/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hardikSinghBehl","download_url":"https://codeload.github.com/hardikSinghBehl/jwt-auth-flow-spring-security/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248131455,"owners_count":21052819,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jwt","jwt-authentication","rs512","spring-boot","spring-security","spring-security-jwt","spring-security-rsa","token-revocation"],"created_at":"2024-12-07T14:07:04.874Z","updated_at":"2025-10-29T10:22:35.712Z","avatar_url":"https://github.com/hardikSinghBehl.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## JWT Authentication and Authorization Flow using Spring Security\n##### A reference proof-of-concept that leverages Spring-security to implement JWT based authentication, API access control, Token revocation and Compromised password detection.\n##### 🛠 upgraded to Spring Boot 3 and Spring Security 6 🛠 \n\n### Key Components\n* [JwtAuthenticationFilter.java](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/filter/JwtAuthenticationFilter.java)\n* [SecurityConfiguration.java](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/SecurityConfiguration.java)\n* [ApiEndpointSecurityInspector.java](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/utility/ApiEndpointSecurityInspector.java)\n* [TokenConfigurationProperties.java](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/TokenConfigurationProperties.java)\n* [JwtUtility.java](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/utility/JwtUtility.java)\n* [TokenRevocationService.java](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/service/TokenRevocationService.java)\n\nAny request to a secured endpoint is intercepted by the [JwtAuthenticationFilter](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/filter/JwtAuthenticationFilter.java), which is added to the security filter chain and configured in the [SecurityConfiguration](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/SecurityConfiguration.java). The custom filter holds the responsibility for verifying the authenticity of the incoming access token and populating the security context. \n\n### Public API declaration\n\nAny API that needs to be made public can be annotated with [@PublicEndpoint](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/PublicEndpoint.java). Requests to the configured API paths will not evaluated by the custom security filter with the logic being governed by [ApiEndpointSecurityInspector](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/utility/ApiEndpointSecurityInspector.java).\n\nBelow is a sample controller method declared as public which will be exempted from authentication checks:\n\n```java\n@PublicEndpoint\n@GetMapping(value = \"/api/v1/something\")\npublic ResponseEntity\u003cSomething\u003e getSomething() {\n    var something = someService.fetch();\n    return ResponseEntity.ok(something);\n}\n```\n\n### Token Generation and Configuration\nThe application uses Access Tokens (JWT) and Refresh Tokens, both of which are returned to the client upon successful authentication. JWTs are signed and verified using RS512 asymmetric key pair, wherein a private key (PKCS#8 format) is used for signing and the corresponding public key is used for verification whenever a private endpoint is invoked, with these operations handled by [JwtUtility](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/utility/JwtUtility.java). Refresh tokens are random 256-bit values generated by [RefreshTokenGenerator](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/utility/RefreshTokenGenerator.java) and stored in a cache against the user identifier by [AuthenticationService](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/service/AuthenticationService.java).\n\nToken validity/expiration (In minutes) and the asymmetric key pairs can be configured in the active `.yml` file. The configured values are populated in [TokenConfigurationProperties](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/TokenConfigurationProperties.java) and referenced by the application. Below is a sample snippet.\n\n```yaml\ncom:\n  behl:\n    cerberus:\n      token:\n        access-token:\n          private-key: ${JWT_PRIVATE_KEY}\n          public-key: ${JWT_PUBLIC_KEY}\n          validity: 30\n        refresh-token:\n          validity: 120\n```\n### API Access Control\n\nAccess control is imposed by the application based on the user's current status within the system. The corresponding permissions are embedded into the generated JWT which allows for stateless access control and authorization process. \n\nFor detailed explanation, this [Document](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/documentation/API_ACCESS_CONTROL.md) can be referenced.\n\n### Token Revocation\n\nWhen a user's status is demoted to one with fewer privileges, there is a need to invalidate the existing Access Token since it retains the previous enhanced scopes. The [implementation](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/service/TokenRevocationService.java) leverages the JWT Token Identifier (JTI) and a caching mechanism to achieve this. Incoming Bearer tokens are validated by the [JwtAuthenticationFilter](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/filter/JwtAuthenticationFilter.java) to ensure they've not been revoked. By revoking access tokens promptly, the system maintains the integrity of access control.\n\nFor detailed explanation, this [Document](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/documentation/TOKEN_REVOCATION.md) can be referenced.\n\n### Authentication Failure\n\nSpring security exceptions are commenced at the AuthenticationEntryPoint. A custom implementation, [CustomAuthenticationEntryPoint](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/CustomAuthenticationEntryPoint.java) is configured in [SecurityConfiguration](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/configuration/SecurityConfiguration.java) which assumes any exceptions thrown by the authentication filters are due to token verification failure. Hence, the implementation instantiates [TokenVerificationException](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/exception/TokenVerificationException.java) and delegates the responsibility of exception handling to HandlerExceptionResolver. The exception finally gets evaluated by [ExceptionResponseHandler](https://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/blob/master/src/main/java/com/behl/cerberus/exception/ExceptionResponseHandler.java) and approprate exception response is returned to the client. \n\nThe below API response is returned by the application in the event of a token verification failure during security evaluation.\n\n```json\n{\n  \"Status\": \"401 UNAUTHORIZED\",\n  \"Description\": \"Authentication failure: Token missing, invalid, revoked or expired\"\n}\n```\n\nThe below API response is returned when authentication succeeds i.e Access Token is validated and Spring context is populated successfully, However the token does not have the permission required to access the API. \n\n```json\n{\n  \"Status\": \"403 FORBIDDEN\",\n  \"Description\": \"Access Denied: You do not have sufficient privileges to access this resource.\"\n}\n```\nIf the user's permissions have changed, the client can leverage available refresh token to request a new JWT, reflecting the new permissions that the user has obtained.\n\n### Compromised Password Detection\n\nTo protect user accounts from the use of vulnerable passwords that have been exposed in data breaches, the project uses the new compromised password detection feature added in `spring-security:6.3`. The default implementation provided uses the [Have I Been Pwned API](https://haveibeenpwned.com/API/v3#PwnedPasswords) under the hood.\n\nThe compromised password check is performed during two key scenarios:\n* **User creation**: When a new user is being registered via the user creation API, the provided password is checked.\n* **User Login**: Even if a password was not compromised at the time of user creation, it may become compromised at a later point. To address this, the login API also incorporates the compromised password check.\n\nIn case of compromised password detection in any of the above scenarios, the server responds with the below error:\n\n```json\n{\n  \"Status\": \"422 UNPROCESSABLE_ENTITY\",\n  \"Description\": \"The provided password is compromised and cannot be used for account creation.\"\n}\n```\n\nTo recover from a compromised password situation during login, a new API endpoint PUT `/users/reset-password` is exposed. This endpoint accepts the below request body payload:\n\n```json\n{\n  \"EmailId\": \"hardik@behl.com\",\n  \"CurrentPassword\": \"somethingCompromised\",\n  \"NewPassword\": \"somethingSecured\"\n}\n```\nThe new password is also checked for compromise before allowing the password reset.\n\n---\n### Local Setup\nThe below given commands can be executed in the project's base directory to build an image and start required container(s). Docker compose will initiate a MySQL and Redis container as well, with the backend swagger-ui accessible at `http://localhost:8080/swagger-ui.html`\n\n\n```bash\nJWT_PRIVATE_KEY=$(openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048)\n```\n```bash\nJWT_PUBLIC_KEY=$(echo \"$JWT_PRIVATE_KEY\" | openssl rsa -pubout -outform PEM)\n```\n```bash\nsudo docker-compose build\n```\n```bash\nsudo JWT_PRIVATE_KEY=\"$JWT_PRIVATE_KEY\" JWT_PUBLIC_KEY=\"$JWT_PUBLIC_KEY\" docker-compose up -d\n```\nThe above commands also generate an RSA key pair locally and pass them as environment variables when starting Docker Compose, so that the application can make use of the generated key pair for signing and verifying JWTs.\n\nTo remove the environment variables from memory after the application has started, the below commands can be executed\n\n```bash\nunset JWT_PRIVATE_KEY\n```\n```bash\nunset JWT_PUBLIC_KEY\n```\n\n---\n\n### Visual Walkthrough\n\nhttps://github.com/hardikSinghBehl/jwt-auth-flow-spring-security/assets/69693621/54ef4877-49b9-4112-9f85-9b9abda74068\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhardiksinghbehl%2Fjwt-auth-flow-spring-security","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhardiksinghbehl%2Fjwt-auth-flow-spring-security","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhardiksinghbehl%2Fjwt-auth-flow-spring-security/lists"}