Skip to content

Commit 16245d0

Browse files
authored
Merge pull request #12 from auth0/add-spotless-check
Feat: Added splotless check
2 parents 4e32fef + a2ae314 commit 16245d0

14 files changed

Lines changed: 1152 additions & 1180 deletions

.version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.0-beta.1
1+
1.0.0-beta.0

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
![Java Version](https://img.shields.io/badge/java-8%2B-blue)
77
![License](https://img.shields.io/badge/license-MIT-green)
88

9-
A comprehensive Java library for Auth0 JWT authentication with built-in **DPoP (Demonstration of Proof-of-Possession)** support. This multi-module project provides both a core authentication library and Spring Boot integration for secure API development.
9+
A comprehensive Java library for Auth0 JWT authentication with built-in **DPoP (Demonstration of Proof-of-Possession)** support. This project provides Spring Boot integration for secure API development.
1010

1111
## 🏗️ Architecture Overview
1212

@@ -37,15 +37,15 @@ If you're building a Spring Boot application, use the Spring Boot integration:
3737
<dependency>
3838
<groupId>com.auth0</groupId>
3939
<artifactId>auth0-springboot-api</artifactId>
40-
<version>1.0.0-SNAPSHOT</version>
40+
<version>1.0.0-beta.0</version>
4141
</dependency>
4242
```
4343

4444
**👉 [Get started with Spring Boot integration →](./auth0-springboot-api/README.md)**
4545

4646
### For Core Java Applications
4747

48-
The core library (`auth0-api-java`) is currently an internal module used by the Spring Boot integration. It provides:
48+
It provides:
4949

5050
- JWT validation with Auth0 JWKS integration
5151
- DPoP proof validation per [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)
@@ -78,11 +78,11 @@ This project uses Gradle with a multi-module setup:
7878

7979
## 📦 Publishing
8080

81-
Only the Spring Boot integration module is published as a public artifact:
81+
Spring Boot integration module is published as a public artifact:
8282

83-
| Module | Group ID | Artifact ID | Version | Status |
84-
| ---------------------- | ----------- | ---------------------- | ---------------- | ---------------- |
85-
| `auth0-springboot-api` | `com.auth0` | `auth0-springboot-api` | `1.0.0-SNAPSHOT` | 📦 **Published** |
83+
| Module | Group ID | Artifact ID | Version | Status |
84+
| ---------------------- | ----------- | ---------------------- |----------------| ---------------- |
85+
| `auth0-springboot-api` | `com.auth0` | `auth0-springboot-api` | `1.0.0-beta.0` | 📦 **Published** |
8686

8787
The core library (`auth0-api-java`) is bundled as an internal dependency within the Spring Boot module and is not published separately.
8888

auth0-springboot-api/README.md

Lines changed: 2 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ This library builds on top of the standard Spring Security JWT authentication, p
1111

1212
## Requirements
1313

14-
- This library currently supports **Java 8+** for core functionality
1514
- **Spring Boot 3.2+** (requires Java 17+) for Spring Boot integration
1615

1716
## Getting Started
@@ -24,15 +23,15 @@ Add the dependency via Maven:
2423
<dependency>
2524
<groupId>com.auth0</groupId>
2625
<artifactId>auth0-springboot-api</artifactId>
27-
<version>1.0.0</version>
26+
<version>1.0.0-beta.0</version>
2827
</dependency>
2928
```
3029

3130
or Gradle:
3231

3332
```gradle
3433
dependencies {
35-
implementation 'com.auth0:auth0-springboot-api:1.0.0'
34+
implementation 'com.auth0:auth0-springboot-api:1.0.0-beta.0'
3635
}
3736
```
3837

@@ -176,49 +175,6 @@ curl -H "Authorization: DPoP <jwt_token>" \
176175

177176
## Advanced Features
178177

179-
### Manual JWT Validation
180-
181-
For scenarios requiring manual token validation, inject and use the `AuthClient`:
182-
183-
```java
184-
@RestController
185-
public class CustomController {
186-
187-
@Autowired
188-
private AuthClient authClient;
189-
190-
@PostMapping("/api/custom-validation")
191-
public ResponseEntity<String> customValidation(HttpServletRequest request) {
192-
try {
193-
// Extract headers and request info
194-
Map<String, String> headers = extractHeaders(request);
195-
HttpRequestInfo requestInfo = new HttpRequestInfo(
196-
request.getMethod(),
197-
request.getRequestURL().toString(),
198-
null
199-
);
200-
201-
// Manual validation
202-
AuthenticationContext context = authClient.verifyRequest(headers, requestInfo);
203-
String userId = (String) context.getClaims().get("sub");
204-
205-
return ResponseEntity.ok("Token valid for user: " + userId);
206-
207-
} catch (BaseAuthException e) {
208-
return ResponseEntity.status(401).body("Authentication failed: " + e.getMessage());
209-
}
210-
}
211-
212-
private Map<String, String> extractHeaders(HttpServletRequest request) {
213-
Map<String, String> headers = new HashMap<>();
214-
Collections.list(request.getHeaderNames()).forEach(headerName ->
215-
headers.put(headerName, request.getHeader(headerName))
216-
);
217-
return headers;
218-
}
219-
}
220-
```
221-
222178
### Custom Claim Validation
223179

224180
Access JWT claims directly through `Auth0AuthenticationToken`'s clean API:

auth0-springboot-api/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ plugins {
22
id 'java-library'
33
id 'org.springframework.boot' version '3.2.0'
44
id 'io.spring.dependency-management' version '1.1.4'
5+
id "com.diffplug.spotless" version "6.25.0"
56
}
67

78
apply from: rootProject.file('gradle/versioning.gradle')
@@ -50,5 +51,12 @@ jar {
5051
archiveClassifier = ''
5152
}
5253

54+
spotless {
55+
java {
56+
googleJavaFormat()
57+
target 'src/**/*.java'
58+
}
59+
}
60+
5361

5462
logger.lifecycle("Using version ${version} for ${name} group ${group}")

auth0-springboot-api/src/main/java/com/auth0/spring/boot/Auth0AuthenticationFilter.java

Lines changed: 84 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,134 +11,127 @@
1111
import jakarta.servlet.ServletException;
1212
import jakarta.servlet.http.HttpServletRequest;
1313
import jakarta.servlet.http.HttpServletResponse;
14+
import java.io.IOException;
15+
import java.util.*;
1416
import org.springframework.security.core.context.SecurityContextHolder;
1517
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
1618
import org.springframework.web.filter.OncePerRequestFilter;
1719

18-
import java.io.IOException;
19-
import java.util.*;
20-
2120
public class Auth0AuthenticationFilter extends OncePerRequestFilter {
2221

23-
private final AuthClient authClient;
22+
private final AuthClient authClient;
2423

25-
private final Auth0Properties auth0Properties;
24+
private final Auth0Properties auth0Properties;
2625

27-
public Auth0AuthenticationFilter(AuthClient authClient, Auth0Properties auth0Properties) {
28-
this.authClient = authClient;
29-
this.auth0Properties = auth0Properties;
30-
}
26+
public Auth0AuthenticationFilter(AuthClient authClient, Auth0Properties auth0Properties) {
27+
this.authClient = authClient;
28+
this.auth0Properties = auth0Properties;
29+
}
3130

32-
@Override
33-
protected void doFilterInternal(
34-
HttpServletRequest request,
35-
HttpServletResponse response,
36-
FilterChain chain
37-
) throws ServletException, IOException {
31+
@Override
32+
protected void doFilterInternal(
33+
HttpServletRequest request, HttpServletResponse response, FilterChain chain)
34+
throws ServletException, IOException {
3835

39-
try {
36+
try {
4037

41-
Map<String, String> headers = extractHeaders(request);
38+
Map<String, String> headers = extractHeaders(request);
4239

43-
String authorizationHeader = headers.get("authorization");
44-
if (authorizationHeader == null || authorizationHeader.trim().isEmpty()) {
45-
chain.doFilter(request, response);
46-
return;
47-
}
40+
String authorizationHeader = headers.get("authorization");
41+
if (authorizationHeader == null || authorizationHeader.trim().isEmpty()) {
42+
chain.doFilter(request, response);
43+
return;
44+
}
4845

49-
HttpRequestInfo requestInfo = extractRequestInfo(request);
46+
HttpRequestInfo requestInfo = extractRequestInfo(request);
5047

51-
AuthenticationContext ctx = authClient.verifyRequest(headers, requestInfo);
48+
AuthenticationContext ctx = authClient.verifyRequest(headers, requestInfo);
5249

53-
Auth0AuthenticationToken authentication = new Auth0AuthenticationToken(ctx);
54-
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
50+
Auth0AuthenticationToken authentication = new Auth0AuthenticationToken(ctx);
51+
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
5552

56-
SecurityContextHolder.getContext().setAuthentication(authentication);
53+
SecurityContextHolder.getContext().setAuthentication(authentication);
5754

58-
chain.doFilter(request, response);
55+
chain.doFilter(request, response);
5956

60-
} catch (BaseAuthException ex) {
61-
response.setStatus(ex.getStatusCode());
57+
} catch (BaseAuthException ex) {
58+
response.setStatus(ex.getStatusCode());
6259

63-
Map<String, String> exceptionHeaders = ex.getHeaders();
64-
String wwwAuthenticate = exceptionHeaders.get("WWW-Authenticate");
60+
Map<String, String> exceptionHeaders = ex.getHeaders();
61+
String wwwAuthenticate = exceptionHeaders.get("WWW-Authenticate");
6562

66-
if (wwwAuthenticate != null) {
67-
response.addHeader("WWW-Authenticate", wwwAuthenticate);
68-
}
69-
SecurityContextHolder.clearContext();
70-
}
63+
if (wwwAuthenticate != null) {
64+
response.addHeader("WWW-Authenticate", wwwAuthenticate);
65+
}
66+
SecurityContextHolder.clearContext();
7167
}
68+
}
7269

73-
Map<String, String> extractHeaders(HttpServletRequest request)
74-
throws MissingAuthorizationException {
70+
Map<String, String> extractHeaders(HttpServletRequest request)
71+
throws MissingAuthorizationException {
7572

76-
List<String> authHeaders = Collections.list(request.getHeaders("Authorization"));
77-
if (authHeaders != null && authHeaders.size() > 1) {
78-
String firstValue = authHeaders.get(0);
73+
List<String> authHeaders = Collections.list(request.getHeaders("Authorization"));
74+
if (authHeaders != null && authHeaders.size() > 1) {
75+
String firstValue = authHeaders.get(0);
7976

80-
MissingAuthorizationException ex = new MissingAuthorizationException();
77+
MissingAuthorizationException ex = new MissingAuthorizationException();
8178

82-
String[] parts = firstValue.trim().split("\\s+", 2);
79+
String[] parts = firstValue.trim().split("\\s+", 2);
8380

84-
DPoPMode dpopMode = auth0Properties.getDpopMode();
85-
if (dpopMode == null) {
86-
dpopMode = DPoPMode.ALLOWED; // default fallback
87-
}
81+
DPoPMode dpopMode = auth0Properties.getDpopMode();
82+
if (dpopMode == null) {
83+
dpopMode = DPoPMode.ALLOWED; // default fallback
84+
}
8885

89-
List<String> challenges = WWWAuthenticateBuilder.buildChallenges(
90-
ex.getErrorCode(),
91-
ex.getErrorDescription(),
92-
dpopMode,
93-
parts[0].toLowerCase(Locale.ROOT)
94-
);
86+
List<String> challenges =
87+
WWWAuthenticateBuilder.buildChallenges(
88+
ex.getErrorCode(),
89+
ex.getErrorDescription(),
90+
dpopMode,
91+
parts[0].toLowerCase(Locale.ROOT));
9592

96-
if (!challenges.isEmpty()) {
97-
ex.addHeader("WWW-Authenticate", String.join(", ", challenges));
98-
}
93+
if (!challenges.isEmpty()) {
94+
ex.addHeader("WWW-Authenticate", String.join(", ", challenges));
95+
}
9996

100-
throw ex;
101-
}
102-
103-
Map<String, String> headers = new HashMap<>();
104-
Enumeration<String> names = request.getHeaderNames();
105-
106-
if (names != null) {
107-
while (names.hasMoreElements()) {
108-
String name = names.nextElement();
109-
headers.put(
110-
name.toLowerCase(Locale.ROOT),
111-
request.getHeader(name)
112-
);
113-
}
114-
}
115-
116-
return headers;
97+
throw ex;
11798
}
11899

119-
HttpRequestInfo extractRequestInfo(HttpServletRequest request) {
120-
String htu = buildHtu(request);
121-
return new HttpRequestInfo(request.getMethod(), htu, null);
100+
Map<String, String> headers = new HashMap<>();
101+
Enumeration<String> names = request.getHeaderNames();
102+
103+
if (names != null) {
104+
while (names.hasMoreElements()) {
105+
String name = names.nextElement();
106+
headers.put(name.toLowerCase(Locale.ROOT), request.getHeader(name));
107+
}
122108
}
123109

124-
static String buildHtu(HttpServletRequest request) {
125-
String scheme = request.getScheme().toLowerCase(Locale.ROOT);
126-
String host = request.getServerName().toLowerCase(Locale.ROOT);
110+
return headers;
111+
}
127112

128-
int port = request.getServerPort();
129-
boolean defaultPort =
130-
(scheme.equals("http") && port == 80) ||
131-
(scheme.equals("https") && port == 443);
113+
HttpRequestInfo extractRequestInfo(HttpServletRequest request) {
114+
String htu = buildHtu(request);
115+
return new HttpRequestInfo(request.getMethod(), htu, null);
116+
}
132117

133-
StringBuilder htu = new StringBuilder();
134-
htu.append(scheme).append("://").append(host);
118+
static String buildHtu(HttpServletRequest request) {
119+
String scheme = request.getScheme().toLowerCase(Locale.ROOT);
120+
String host = request.getServerName().toLowerCase(Locale.ROOT);
135121

136-
if (!defaultPort) {
137-
htu.append(":").append(port);
138-
}
122+
int port = request.getServerPort();
123+
boolean defaultPort =
124+
(scheme.equals("http") && port == 80) || (scheme.equals("https") && port == 443);
139125

140-
htu.append(request.getRequestURI());
126+
StringBuilder htu = new StringBuilder();
127+
htu.append(scheme).append("://").append(host);
141128

142-
return htu.toString();
129+
if (!defaultPort) {
130+
htu.append(":").append(port);
143131
}
132+
133+
htu.append(request.getRequestURI());
134+
135+
return htu.toString();
136+
}
144137
}

0 commit comments

Comments
 (0)