Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/hardiksinghbehl/budget-pkce-spring-boot
Budget Proof Key for Code Exchange (PKCE) implementation using Java Spring-boot
https://github.com/hardiksinghbehl/budget-pkce-spring-boot
java pkce pkce-authentication proof-key-for-code-exchange spring-boot spring-security
Last synced: about 1 month ago
JSON representation
Budget Proof Key for Code Exchange (PKCE) implementation using Java Spring-boot
- Host: GitHub
- URL: https://github.com/hardiksinghbehl/budget-pkce-spring-boot
- Owner: hardikSinghBehl
- Created: 2021-10-15T10:24:25.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2021-10-18T05:32:08.000Z (about 3 years ago)
- Last Synced: 2024-05-10T18:57:45.604Z (8 months ago)
- Topics: java, pkce, pkce-authentication, proof-key-for-code-exchange, spring-boot, spring-security
- Language: Java
- Homepage:
- Size: 103 KB
- Stars: 9
- Watchers: 1
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## Low Budget Proof Key for Code Exchange (PKCE) Implementation using Java Spring-boot
#### Just for fun, low budget implementation of PKCE Auth Flow using a single Spring-boot application that exposes APIs to act as an authorization and resource server both.
### Screen Recording showing Auth Flow (62 Seconds)
https://user-images.githubusercontent.com/69693621/137596996-2b5d48ce-9d5b-4e17-9472-c774eddd725f.mov---
## Authorization Code Flow with Proof Key for Code Exchange (PKCE)
1.) **Configure Client-id and Redirect-URI in `application.properties` file as per [PkceConfigurationProperties.class](https://github.com/hardikSinghBehl/budget-pkce-spring-boot/blob/main/src/main/java/com/behl/ehrmantraut/security/configuration/properties/PkceConfigurationProperties.java)**```
com.behl.ehrmantraut.security.client-id=
com.behl.ehrmantraut.security.redirect-uri=
com.behl.ehrmantraut.security.response-type=code
com.behl.ehrmantraut.security.code-challenge-method=S256
com.behl.ehrmantraut.security.grant-type=authorization_code
com.behl.ehrmantraut.security.code-expiration-minutes=2
```2.) **Create the code verifier and challenge**
Before each authentication request, the client app should generate a `code verifier` and a `code challenge`.
* The code verifier is a cryptographically random string between 43 and 128 characters in length. It can contain letters, digits, underscores, periods, hyphens, or tildes.
* In order to generate the code challenge, the client should hash the code verifier using the SHA256 algorithm. Then, base64url encode the hash that is generated.
* Sample Code verifier and code Challenge for demo (Not to be kept static and should be dynamically calculated before every request)
* Code Verifier
```
dcFKDCmdcYmcmW6DXu2BfSrkGB1cKwFAI5Jv7he9RDo
```
* Code Challenge
```
Ijcr0PLd8HvnhB9AZXlhmPPJjyLyaPkianM0ERzD860
```3.) **Hit /authenticate POST API with the below data in the request body (Sample JSON given)**
```
{
"emailId": "[email protected]",
"password": "noHalfMeasures",
"clientId": "",
"responseType": "code",
"redirectUri": "",
"codeChallengeMethod": "S256",
"codeChallenge": "",
"state": ""
}
```
* [Reference](https://datatracker.ietf.org/doc/html/rfc6749#section-10.12) for using `state`
4.) Recieve `code` and `state` in the request parameter of the provided redirect-URI after successfull authentication
* This code is a `one-time-use` commodity to `exchange token(s)` from the server
* The redirection is done through `ResponseEntity.class`
```
return ResponseEntity.status(HttpStatus.FOUND).location("attach query params (code and optional state to redirect-uri)").build();
```
* **Hit /token POST API with the below data in the request body (Sample JSON given)**
```
{
"clientId": "",
"grantType": "authorization_code",
"code": "",
"redirectUri": "",
"codeVerifier": ""
}
```
5.) On success, the response will have a 200 OK status and the following Sample JSON data in the response body```
{
"accessToken": "eyJhbGciOiJIUzI1NiJ9.eyJlbWFpbF9pZCI6Im1pa2UuZWhybWFudHJhdXRAZ21haWwuY29tIiwic3ViIjoibWlrZS5laHJtYW50cmF1dEBnbWFpbC5jb20iLCJhY2NvdW50X2NyZWF0aW9uX3RpbWVzdGFtcCI6IjIwMjEtMTAtMTZUMTQ6NDM6MTguMDQ1MDgwIiwidXNlcl9pZCI6ImZiNTRhNjdlLWI5NWItNDM2OS1iNjExLTdmYjRlYTA0NGQ4NiIsImV4cCI6MTYzNDM5OTAyMiwiaWF0IjoxNjM0Mzk1NDIyfQ._hUb127nUzI-GTkMIUbstTa21tuqRpsanektHnqzwCQ",
"tokenType": "Bearer",
"refreshToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtaWtlLmVocm1hbnRyYXV0QGdtYWlsLmNvbSIsImV4cCI6MTYzNTY5MTQyMiwiaWF0IjoxNjM0Mzk1NDIyfQ.Lf7dQNSDZ9NUp6W4a8HwtZb0dWrgy9wpsxH4Pjb2VOg",
"expiresIn": 3600
}
```
* The recieved `accessToken` allows the client to make requests to the Server on behalf of the logged in-user using the `Authorization Bearer Mechanism`.6.) A request to refresh an access token can be sent to the same `/token endpoint` with the below data in the request body (Sample JSON given)
```
{
"clientId": "",
"grantType": "refresh_token",
"refreshToken": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJtaWtlLmVocm1hbnRyYXV0QGdtYWlsLmNvbSIsImV4cCI6MTYzNTY5MTQyMiwiaWF0IjoxNjM0Mzk1NDIyfQ.Lf7dQNSDZ9NUp6W4a8HwtZb0dWrgy9wpsxH4Pjb2VOg"
}
```
---### PRs welcome, Star repository to show support
### Tech stack used
* Java 17
* Spring-boot 2.5.5
* Spring-Security and [JJWT](https://github.com/jwtk/jjwt)
* Spring-JPA/Hibernate
* H2 in-memory DB
* Lombok
* LoadingCache (in [Guava](https://github.com/google/guava)) to store userAuthenticationDetails in memory### Local Setup
* Install Java 17 (recommended to use [SdkMan](https://sdkman.io))`sdk install java 17-open`
* Install Maven (recommended to use [SdkMan](https://sdkman.io))`sdk install maven`
* Clone the repo and Go to application.properties under src/main/resources and configure properties as required
* Run the below command in core
`mvn clean install`
* To start the application, run any of the below 2 commands
`mvn spring-boot:run &`
`java -jar /target/budget-pkce-0.0.1-SNAPSHOT.jar`
* Access the swagger-ui
`http://localhost:8080/swagger-ui.html`