or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication-sessions.mdcomponent-framework.mdcore-models.mdcredential-management.mdindex.mdorganization-management.mdprovider-framework.mdsession-management.mduser-storage.mdvalidation-framework.mdvault-integration.md

provider-framework.mddocs/

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

```