0
# Authentication
1
2
Pluggable authentication system supporting basic auth, OAuth, and custom authentication schemes with fine-grained authorization control.
3
4
## Capabilities
5
6
### Authenticator Interface
7
8
Core interface for converting credentials into authenticated principals.
9
10
```java { .api }
11
package io.dropwizard.auth;
12
13
public interface Authenticator<C, P> {
14
/**
15
* Authenticates the given credentials and returns an optional principal.
16
* @param credentials the credentials to authenticate
17
* @return the authenticated principal if successful, empty otherwise
18
* @throws AuthenticationException if authentication fails
19
*/
20
Optional<P> authenticate(C credentials) throws AuthenticationException;
21
}
22
```
23
24
**Usage Example:**
25
26
```java
27
public class SimpleAuthenticator implements Authenticator<BasicCredentials, User> {
28
private final UserService userService;
29
30
public SimpleAuthenticator(UserService userService) {
31
this.userService = userService;
32
}
33
34
@Override
35
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
36
if ("secret".equals(credentials.getPassword())) {
37
return userService.findByUsername(credentials.getUsername());
38
}
39
return Optional.empty();
40
}
41
}
42
```
43
44
### Authorizer Interface
45
46
Interface for implementing authorization logic to control access to resources based on roles or permissions.
47
48
```java { .api }
49
package io.dropwizard.auth;
50
51
public interface Authorizer<P> {
52
/**
53
* Determines if the principal is authorized for the given role.
54
* @param principal the authenticated principal
55
* @param role the role to check authorization for
56
* @return true if authorized, false otherwise
57
*/
58
boolean authorize(P principal, String role);
59
}
60
```
61
62
**Usage Example:**
63
64
```java
65
public class SimpleAuthorizer implements Authorizer<User> {
66
@Override
67
public boolean authorize(User user, String role) {
68
return user.getRoles().contains(role);
69
}
70
}
71
```
72
73
### Authentication Filters
74
75
Pre-built authentication filters for common authentication schemes.
76
77
```java { .api }
78
package io.dropwizard.auth;
79
80
public class BasicCredentialAuthFilter<P> extends AuthFilter<BasicCredentials, P> {
81
public static class Builder<P> extends AuthFilterBuilder<BasicCredentials, P, BasicCredentialAuthFilter<P>> {
82
public Builder<P> setAuthenticator(Authenticator<BasicCredentials, P> authenticator);
83
public Builder<P> setAuthorizer(Authorizer<P> authorizer);
84
public Builder<P> setRealm(String realm);
85
public BasicCredentialAuthFilter<P> buildAuthFilter();
86
}
87
}
88
89
public class OAuthCredentialAuthFilter<P> extends AuthFilter<String, P> {
90
public static class Builder<P> extends AuthFilterBuilder<String, P, OAuthCredentialAuthFilter<P>> {
91
public Builder<P> setAuthenticator(Authenticator<String, P> authenticator);
92
public Builder<P> setAuthorizer(Authorizer<P> authorizer);
93
public Builder<P> setPrefix(String prefix);
94
public OAuthCredentialAuthFilter<P> buildAuthFilter();
95
}
96
}
97
```
98
99
**Usage Example:**
100
101
```java
102
@Override
103
public void run(MyConfiguration configuration, Environment environment) {
104
// Basic Authentication
105
environment.jersey().register(new AuthDynamicFeature(
106
new BasicCredentialAuthFilter.Builder<User>()
107
.setAuthenticator(new SimpleAuthenticator(userService))
108
.setAuthorizer(new SimpleAuthorizer())
109
.setRealm("SUPER SECRET STUFF")
110
.buildAuthFilter()
111
));
112
113
// OAuth Authentication
114
environment.jersey().register(new AuthDynamicFeature(
115
new OAuthCredentialAuthFilter.Builder<User>()
116
.setAuthenticator(new OAuthAuthenticator(tokenService))
117
.setAuthorizer(new SimpleAuthorizer())
118
.setPrefix("Bearer")
119
.buildAuthFilter()
120
));
121
122
// Enable authorization annotations
123
environment.jersey().register(RolesAllowedDynamicFeature.class);
124
}
125
```
126
127
### Auth Dynamic Feature
128
129
Jersey dynamic feature for registering authentication filters with the application.
130
131
```java { .api }
132
package io.dropwizard.auth;
133
134
public class AuthDynamicFeature implements DynamicFeature {
135
/**
136
* Creates an auth dynamic feature with the given auth filter.
137
*/
138
public AuthDynamicFeature(AuthFilter<?, ?> authFilter);
139
140
@Override
141
public void configure(ResourceInfo resourceInfo, FeatureContext context);
142
}
143
144
@Provider
145
public class RolesAllowedDynamicFeature implements DynamicFeature {
146
/**
147
* Enables @RolesAllowed, @PermitAll, and @DenyAll annotations.
148
*/
149
@Override
150
public void configure(ResourceInfo resourceInfo, FeatureContext context);
151
}
152
```
153
154
### Authentication Annotations
155
156
JAX-RS security annotations for protecting resources and methods.
157
158
```java { .api }
159
// Security annotations
160
@RolesAllowed({"ADMIN", "USER"})
161
@PermitAll
162
@DenyAll
163
164
// Authentication context
165
@Auth Principal principal
166
```
167
168
**Usage Example:**
169
170
```java
171
@Path("/admin")
172
@RolesAllowed("ADMIN")
173
public class AdminResource {
174
175
@GET
176
@Path("/users")
177
public List<User> getAllUsers(@Auth User currentUser) {
178
// Only accessible by users with ADMIN role
179
return userService.findAll();
180
}
181
182
@POST
183
@Path("/users")
184
@RolesAllowed({"ADMIN", "MODERATOR"})
185
public User createUser(@Auth User currentUser, @Valid User newUser) {
186
// Accessible by ADMIN or MODERATOR roles
187
return userService.create(newUser);
188
}
189
}
190
191
@Path("/public")
192
@PermitAll
193
public class PublicResource {
194
195
@GET
196
@Path("/health")
197
public String health() {
198
// Publicly accessible
199
return "OK";
200
}
201
}
202
```
203
204
### Custom Authentication Schemes
205
206
Creating custom authentication filters for specialized authentication requirements.
207
208
```java { .api }
209
package io.dropwizard.auth;
210
211
public abstract class AuthFilter<C, P> implements ContainerRequestFilter {
212
/**
213
* Extracts credentials from the request.
214
*/
215
public abstract C getCredentials(ContainerRequestContext requestContext);
216
217
/**
218
* Called when authentication fails.
219
*/
220
public abstract void onAuthenticationFailure(String challenge,
221
ContainerRequestContext requestContext);
222
223
/**
224
* Called when authorization fails.
225
*/
226
public abstract void onAuthorizationFailure(String challenge,
227
ContainerRequestContext requestContext);
228
}
229
230
public abstract class AuthFilterBuilder<C, P, T extends AuthFilter<C, P>> {
231
public abstract T buildAuthFilter();
232
233
protected AuthFilterBuilder<C, P, T> setAuthenticator(Authenticator<C, P> authenticator);
234
protected AuthFilterBuilder<C, P, T> setAuthorizer(Authorizer<P> authorizer);
235
}
236
```
237
238
**Usage Example:**
239
240
```java
241
public class ApiKeyAuthFilter extends AuthFilter<String, User> {
242
243
@Override
244
public String getCredentials(ContainerRequestContext requestContext) {
245
return requestContext.getHeaderString("X-API-Key");
246
}
247
248
@Override
249
public void onAuthenticationFailure(String challenge,
250
ContainerRequestContext requestContext) {
251
requestContext.abortWith(
252
Response.status(Response.Status.UNAUTHORIZED)
253
.header(HttpHeaders.WWW_AUTHENTICATE, challenge)
254
.entity("Invalid API key")
255
.build()
256
);
257
}
258
259
@Override
260
public void onAuthorizationFailure(String challenge,
261
ContainerRequestContext requestContext) {
262
requestContext.abortWith(
263
Response.status(Response.Status.FORBIDDEN)
264
.entity("Insufficient permissions")
265
.build()
266
);
267
}
268
269
public static class Builder extends AuthFilterBuilder<String, User, ApiKeyAuthFilter> {
270
@Override
271
protected ApiKeyAuthFilter newInstance() {
272
return new ApiKeyAuthFilter();
273
}
274
}
275
}
276
```
277
278
### Caching Authenticators
279
280
Wrapper authenticators that cache authentication results to improve performance.
281
282
```java { .api }
283
package io.dropwizard.auth;
284
285
public class CachingAuthenticator<C, P> implements Authenticator<C, P> {
286
/**
287
* Creates a caching authenticator with the given cache spec.
288
*/
289
public static <C, P> CachingAuthenticator<C, P> wrap(
290
Authenticator<C, P> underlying,
291
CacheBuilderSpec cacheSpec);
292
293
/**
294
* Creates a caching authenticator with a cache builder.
295
*/
296
public static <C, P> CachingAuthenticator<C, P> wrap(
297
Authenticator<C, P> underlying,
298
CacheBuilder<Object, Object> cacheBuilder);
299
}
300
```
301
302
**Usage Example:**
303
304
```java
305
@Override
306
public void run(MyConfiguration configuration, Environment environment) {
307
// Cache authentication results for 10 minutes
308
Authenticator<BasicCredentials, User> authenticator =
309
CachingAuthenticator.wrap(
310
new DatabaseAuthenticator(userService),
311
CacheBuilderSpec.parse("maximumSize=1000, expireAfterWrite=10m")
312
);
313
314
environment.jersey().register(new AuthDynamicFeature(
315
new BasicCredentialAuthFilter.Builder<User>()
316
.setAuthenticator(authenticator)
317
.setAuthorizer(new SimpleAuthorizer())
318
.setRealm("My Service")
319
.buildAuthFilter()
320
));
321
}
322
```
323
324
## Authentication Patterns
325
326
### JWT Token Authentication
327
328
Example implementation for JSON Web Token authentication.
329
330
```java
331
public class JWTAuthenticator implements Authenticator<String, User> {
332
private final JWTVerifier verifier;
333
private final UserService userService;
334
335
public JWTAuthenticator(JWTVerifier verifier, UserService userService) {
336
this.verifier = verifier;
337
this.userService = userService;
338
}
339
340
@Override
341
public Optional<User> authenticate(String token) throws AuthenticationException {
342
try {
343
DecodedJWT jwt = verifier.verify(token);
344
String username = jwt.getSubject();
345
return userService.findByUsername(username);
346
} catch (JWTVerificationException e) {
347
return Optional.empty();
348
}
349
}
350
}
351
```
352
353
### Multi-Factor Authentication
354
355
Combining multiple authentication factors for enhanced security.
356
357
```java
358
public class MFAAuthenticator implements Authenticator<BasicCredentials, User> {
359
private final Authenticator<BasicCredentials, User> primaryAuth;
360
private final TOTPService totpService;
361
362
@Override
363
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
364
// First factor: username/password
365
Optional<User> user = primaryAuth.authenticate(credentials);
366
if (!user.isPresent()) {
367
return Optional.empty();
368
}
369
370
// Second factor: TOTP code (assumed to be in password field after |)
371
String[] parts = credentials.getPassword().split("\\|");
372
if (parts.length != 2) {
373
return Optional.empty();
374
}
375
376
String totpCode = parts[1];
377
if (!totpService.verify(user.get().getTotpSecret(), totpCode)) {
378
return Optional.empty();
379
}
380
381
return user;
382
}
383
}
384
```