0
# Provider Framework
1
2
The provider framework is the foundation of Keycloak's extensibility system. It provides the core interfaces and patterns that enable developers to create custom providers for authentication, user storage, credential management, and other extension points.
3
4
## Core Interfaces
5
6
### Provider
7
8
Base interface that all Keycloak providers must implement.
9
10
```java { .api }
11
public interface Provider {
12
/**
13
* Called when the provider is closed and should clean up any resources.
14
*/
15
void close();
16
}
17
```
18
19
### ProviderFactory
20
21
Factory interface for creating provider instances. One factory instance exists per server.
22
23
```java { .api }
24
public interface ProviderFactory<T extends Provider> {
25
/**
26
* Creates a new provider instance for the given session.
27
*
28
* @param session the Keycloak session
29
* @return new provider instance
30
*/
31
T create(KeycloakSession session);
32
33
/**
34
* Called once when the factory is first created. Configuration is from keycloak_server.json.
35
*
36
* @param config configuration scope
37
*/
38
void init(Config.Scope config);
39
40
/**
41
* Called after all provider factories have been initialized.
42
*
43
* @param factory the session factory
44
*/
45
void postInit(KeycloakSessionFactory factory);
46
47
/**
48
* Called when the server shuts down.
49
*/
50
void close();
51
52
/**
53
* Returns the unique identifier for this provider factory.
54
*
55
* @return provider ID
56
*/
57
String getId();
58
59
/**
60
* Returns the execution order for this factory. Lower values execute first.
61
*
62
* @return order value (default: 0)
63
*/
64
default int order() {
65
return 0;
66
}
67
68
/**
69
* Returns metadata for configuration properties supported by this factory.
70
*
71
* @return list of configuration property metadata
72
*/
73
default List<ProviderConfigProperty> getConfigMetadata() {
74
return Collections.emptyList();
75
}
76
77
/**
78
* Declares dependencies on other providers. Ensures dependent providers
79
* are initialized before this factory's postInit() is called.
80
*
81
* @return set of provider classes this factory depends on
82
*/
83
default Set<Class<? extends Provider>> dependsOn() {
84
return Collections.emptySet();
85
}
86
}
87
```
88
89
### Spi
90
91
Defines a Service Provider Interface, linking provider and factory classes.
92
93
```java { .api }
94
public interface Spi {
95
/**
96
* Whether this SPI is internal to Keycloak (not for external use).
97
*
98
* @return true if internal
99
*/
100
boolean isInternal();
101
102
/**
103
* Returns the name of this SPI.
104
*
105
* @return SPI name
106
*/
107
String getName();
108
109
/**
110
* Returns the provider interface class.
111
*
112
* @return provider class
113
*/
114
Class<? extends Provider> getProviderClass();
115
116
/**
117
* Returns the provider factory interface class.
118
*
119
* @return provider factory class
120
*/
121
Class<? extends ProviderFactory> getProviderFactoryClass();
122
123
/**
124
* Whether this SPI is enabled by default.
125
*
126
* @return true if enabled (default: true)
127
*/
128
default boolean isEnabled() {
129
return true;
130
}
131
}
132
```
133
134
## Configuration Support
135
136
### ProviderConfigProperty
137
138
Describes configuration properties for provider factories.
139
140
```java { .api }
141
public class ProviderConfigProperty {
142
public static final String BOOLEAN_TYPE = "boolean";
143
public static final String STRING_TYPE = "String";
144
public static final String PASSWORD = "Password";
145
public static final String LIST_TYPE = "List";
146
public static final String ROLE_TYPE = "Role";
147
public static final String CLIENT_LIST_TYPE = "ClientList";
148
149
private String name;
150
private String label;
151
private String helpText;
152
private String type;
153
private Object defaultValue;
154
private List<String> options;
155
private boolean secret;
156
157
public ProviderConfigProperty() {}
158
159
public ProviderConfigProperty(String name, String label, String helpText, String type, Object defaultValue) {
160
this.name = name;
161
this.label = label;
162
this.helpText = helpText;
163
this.type = type;
164
this.defaultValue = defaultValue;
165
}
166
167
// Getters and setters
168
public String getName() { return name; }
169
public void setName(String name) { this.name = name; }
170
171
public String getLabel() { return label; }
172
public void setLabel(String label) { this.label = label; }
173
174
public String getHelpText() { return helpText; }
175
public void setHelpText(String helpText) { this.helpText = helpText; }
176
177
public String getType() { return type; }
178
public void setType(String type) { this.type = type; }
179
180
public Object getDefaultValue() { return defaultValue; }
181
public void setDefaultValue(Object defaultValue) { this.defaultValue = defaultValue; }
182
183
public List<String> getOptions() { return options; }
184
public void setOptions(List<String> options) { this.options = options; }
185
186
public boolean isSecret() { return secret; }
187
public void setSecret(boolean secret) { this.secret = secret; }
188
}
189
```
190
191
### ConfiguredProvider
192
193
Marker interface for providers that require configuration.
194
195
```java { .api }
196
public interface ConfiguredProvider {
197
// Marker interface - no methods required
198
}
199
```
200
201
## Event System
202
203
### ProviderEvent
204
205
Base interface for provider events.
206
207
```java { .api }
208
public interface ProviderEvent {
209
// Marker interface for provider events
210
}
211
```
212
213
### ProviderEventListener
214
215
Listens for provider events.
216
217
```java { .api }
218
public interface ProviderEventListener {
219
/**
220
* Called when a provider event occurs.
221
*
222
* @param event the provider event
223
*/
224
void onEvent(ProviderEvent event);
225
}
226
```
227
228
### ProviderEventManager
229
230
Manages provider event listeners and dispatching.
231
232
```java { .api }
233
public interface ProviderEventManager {
234
/**
235
* Registers an event listener.
236
*
237
* @param listener the event listener
238
*/
239
void register(ProviderEventListener listener);
240
241
/**
242
* Unregisters an event listener.
243
*
244
* @param listener the event listener
245
*/
246
void unregister(ProviderEventListener listener);
247
248
/**
249
* Publishes an event to all registered listeners.
250
*
251
* @param event the event to publish
252
*/
253
void publish(ProviderEvent event);
254
}
255
```
256
257
## Usage Examples
258
259
### Creating a Custom Provider
260
261
```java
262
// 1. Define your provider interface
263
public interface MyCustomProvider extends Provider {
264
void doSomething(String input);
265
String getSomething();
266
}
267
268
// 2. Implement the provider
269
public class MyCustomProviderImpl implements MyCustomProvider {
270
private final KeycloakSession session;
271
272
public MyCustomProviderImpl(KeycloakSession session) {
273
this.session = session;
274
}
275
276
@Override
277
public void doSomething(String input) {
278
// Implementation logic
279
}
280
281
@Override
282
public String getSomething() {
283
return "something";
284
}
285
286
@Override
287
public void close() {
288
// Cleanup resources
289
}
290
}
291
292
// 3. Create the provider factory
293
public class MyCustomProviderFactory implements ProviderFactory<MyCustomProvider> {
294
public static final String PROVIDER_ID = "my-custom";
295
296
@Override
297
public MyCustomProvider create(KeycloakSession session) {
298
return new MyCustomProviderImpl(session);
299
}
300
301
@Override
302
public void init(Config.Scope config) {
303
// Initialize from configuration
304
String setting = config.get("mySetting", "defaultValue");
305
}
306
307
@Override
308
public void postInit(KeycloakSessionFactory factory) {
309
// Post-initialization logic
310
}
311
312
@Override
313
public void close() {
314
// Cleanup on shutdown
315
}
316
317
@Override
318
public String getId() {
319
return PROVIDER_ID;
320
}
321
322
@Override
323
public List<ProviderConfigProperty> getConfigMetadata() {
324
List<ProviderConfigProperty> properties = new ArrayList<>();
325
properties.add(new ProviderConfigProperty(
326
"mySetting",
327
"My Setting",
328
"Description of my setting",
329
ProviderConfigProperty.STRING_TYPE,
330
"defaultValue"
331
));
332
return properties;
333
}
334
}
335
336
// 4. Define the SPI
337
public class MyCustomSpi implements Spi {
338
@Override
339
public boolean isInternal() {
340
return false;
341
}
342
343
@Override
344
public String getName() {
345
return "my-custom";
346
}
347
348
@Override
349
public Class<? extends Provider> getProviderClass() {
350
return MyCustomProvider.class;
351
}
352
353
@Override
354
public Class<? extends ProviderFactory> getProviderFactoryClass() {
355
return MyCustomProviderFactory.class;
356
}
357
}
358
```
359
360
### Using Providers in Code
361
362
```java
363
// Access a provider from KeycloakSession
364
KeycloakSession session = // obtain session
365
MyCustomProvider provider = session.getProvider(MyCustomProvider.class);
366
provider.doSomething("input");
367
String result = provider.getSomething();
368
369
// Access a specific provider implementation
370
MyCustomProvider provider = session.getProvider(MyCustomProvider.class, "my-custom");
371
```
372
373
### Provider Configuration
374
375
In `keycloak-server.json`:
376
377
```json
378
{
379
"providers": [
380
{
381
"name": "my-custom",
382
"enabled": true,
383
"properties": {
384
"mySetting": "customValue"
385
}
386
}
387
]
388
}
389
```
390
391
## Common Patterns
392
393
### Lifecycle Management
394
395
```java
396
public class MyProviderFactory implements ProviderFactory<MyProvider> {
397
private volatile MyExternalService externalService;
398
399
@Override
400
public void init(Config.Scope config) {
401
// Initialize shared resources
402
String endpoint = config.get("endpoint");
403
this.externalService = new MyExternalService(endpoint);
404
}
405
406
@Override
407
public MyProvider create(KeycloakSession session) {
408
return new MyProviderImpl(session, externalService);
409
}
410
411
@Override
412
public void close() {
413
// Cleanup shared resources
414
if (externalService != null) {
415
externalService.shutdown();
416
}
417
}
418
}
419
```
420
421
### Dependency Injection
422
423
```java
424
public class MyProviderFactory implements ProviderFactory<MyProvider> {
425
@Override
426
public Set<Class<? extends Provider>> dependsOn() {
427
return Set.of(OtherProvider.class);
428
}
429
430
@Override
431
public void postInit(KeycloakSessionFactory factory) {
432
// Access dependent providers after they're initialized
433
try (KeycloakSession session = factory.create()) {
434
OtherProvider other = session.getProvider(OtherProvider.class);
435
// Use the other provider for initialization
436
}
437
}
438
}
439
```
440
441
### Configuration Validation
442
443
```java
444
@Override
445
public List<ProviderConfigProperty> getConfigMetadata() {
446
return List.of(
447
new ProviderConfigProperty("url", "Service URL", "URL of the external service",
448
ProviderConfigProperty.STRING_TYPE, null),
449
new ProviderConfigProperty("timeout", "Timeout", "Connection timeout in seconds",
450
ProviderConfigProperty.STRING_TYPE, "30"),
451
new ProviderConfigProperty("enabled", "Enabled", "Enable this provider",
452
ProviderConfigProperty.BOOLEAN_TYPE, true)
453
);
454
}
455
```