Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ coverage/

# Personal files
.idea
.vscode

# System files
.DS_Store

# ---------------------------------------------------------------------
# Add specific rules here…

# Environment files — never commit secrets. Track a .env.example template instead.
.env
89 changes: 89 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,94 @@
# MIGRATION

## V 2.x (Spring Boot 3) to V 2.2 (Spring Boot 4)

`kinde-springboot-starter` and `kinde-springboot-core` were upgraded to
[Spring Boot 4.0.x](https://spring.io/blog/2025/11/20/spring-boot-4-0-0-available-now)
and [Spring Security 7.x](https://docs.spring.io/spring-security/reference/7.0.0/migration/index.html).
If you depend on either, here is what changes for you.

### Baseline requirements

- **Java 17 or later.** Spring Boot 4 raised the minimum JVM. The SDK
itself is built on Java 25 but produces Java 17-compatible bytecode.
- **Spring Boot 4.x** in your application. Spring Boot 3.x consumers
should stay on the previous Kinde SDK release line.

### Behaviour change: JWT audience validation is now opt-in

Previously the resource-server JWT validator was hardcoded to require an
audience claim of `"api://default"` (a leftover sample value). Real Kinde
access tokens carry an empty `aud` array unless you explicitly configure
an API resource on the Kinde dashboard, so the previous default rejected
every default Kinde token with a 401:

```
"This aud claim is not equal to the configured audience"
```

The validator now skips audience checking unless you explicitly configure
an expected audience:

```yaml
kinde:
oauth2:
audience: https://your-api.example.com # optional; only set if you
# configured an API resource
# on the Kinde dashboard
```

If you previously relied on the implicit default and your tokens actually
contained `api://default` as their audience (highly unlikely for Kinde
deployments), set `kinde.oauth2.audience: api://default` to preserve the
old behaviour.

### Configuration property rename: `okta.oauth2.post-logout-redirect-uri` → `kinde.oauth2.post-logout-redirect-uri`

RP-Initiated logout (redirect to the IdP's logout endpoint after a local
sign-out) is wired in by the SDK when this property is set. The previous
property name was an Okta-fork leftover that nobody in a Kinde deployment
could plausibly have set. To enable RP-Initiated logout now:

```yaml
kinde:
oauth2:
post-logout-redirect-uri: http://localhost:8080 # where to land
# after Kinde
# clears its
# session
```

The same rename applies to the reactive (WebFlux) auto-configuration.

### New transitive dependencies for `kinde-springboot-starter`

Spring Boot 4 split OAuth2 auto-configuration out of
`spring-boot-autoconfigure` into dedicated starters. The
`kinde-springboot-starter` pom now pulls them in for you:

- `spring-boot-starter-oauth2-client`
- `spring-boot-starter-oauth2-resource-server`

You do **not** need to add them to your own pom unless you previously
declared them explicitly and want to keep that explicit (which is fine).

### Spring Security 7 source-level changes (only affects custom code)

If you previously customized security by writing your own
`SecurityFilterChain` against Spring Security 6 APIs, some method
signatures have changed in Spring Security 7. Notable items:

- `oauth2Login(Customizer)` and `oauth2ResourceServer(Customizer)`
signatures changed slightly; the lambda forms still work but the
no-arg deprecated forms are gone.
- `WebSecurityConfigurerAdapter` (long deprecated) is fully removed.
- Several token-endpoint client classes moved packages. The SDK does
this internally; you are only affected if you wired your own
`OAuth2AccessTokenResponseClient` bean.

The [official Spring Security 7 migration guide](https://docs.spring.io/spring-security/reference/7.0.0/migration/index.html)
is the source of truth.

## V 1.0.0 to V 2.0.0

The original implementation was based on Spring Boot controllers. It provided a controller that could be instantiated inline and then invoked to perform the PKCE authentication. Version 2.0.0 implements a core OAuth and OpenID library. This library provides a rich set of functions, from token management to OpenID authentication.
Expand Down
1 change: 0 additions & 1 deletion kinde-core/.env

This file was deleted.

41 changes: 41 additions & 0 deletions kinde-core/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Template for kinde-core .env. Copy to `.env` and customise as needed.
# `.env` is gitignored; this template is committed so contributors have a starting point.
#
# kinde-core is the SDK library. Most callers configure it programmatically via
# KindeClientBuilder, but the SDK will also pick up these variables from .env or
# the process environment at runtime. The full list of supported keys is defined
# in com.kinde.config.KindeParameters.

# === Tenant + credentials ===
KINDE_DOMAIN=https://<your-subdomain>.kinde.com
KINDE_CLIENT_ID=<your-kinde-client-id>
KINDE_CLIENT_SECRET=<your-kinde-client-secret>

# === OAuth flow ===
# AuthorizationType values: CODE | PKCE | CLIENT_CREDENTIALS | TOKEN
KINDE_GRANT_TYPE=CODE
KINDE_SCOPES=openid
KINDE_REDIRECT_URI=http://localhost:8080/callback
KINDE_LOGOUT_REDIRECT_URI=http://localhost:8080

# === Optional ===
# Audience claim (comma-separated). Required when calling the Kinde Management API.
# KINDE_AUDIENCE=https://<your-subdomain>.kinde.com/api

# UI language hint passed to Kinde (e.g. en, fr, de)
# KINDE_LANG=en

# Scope auth to a specific organisation
# KINDE_ORG_CODE=

# Whether Kinde redirects to a success page after registration
# KINDE_HAS_SUCCESS_PAGE=false

# Auth protocol override (typically derived by the SDK)
# KINDE_PROTOCOL=

# === Endpoint overrides (rarely needed — defaults derive from KINDE_DOMAIN) ===
# KINDE_OPENID_ENDPOINT=https://<your-subdomain>.kinde.com/.well-known/openid-configuration
# KINDE_AUTHORIZATION_ENDPOINT=https://<your-subdomain>.kinde.com/oauth2/auth
# KINDE_TOKEN_ENDPOINT=https://<your-subdomain>.kinde.com/oauth2/token
# KINDE_LOGOUT_ENDPOINT=https://<your-subdomain>.kinde.com/logout
37 changes: 1 addition & 36 deletions kinde-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,6 @@
<url>http://maven.apache.org</url>

<dependencies>
<!-- https://mvnrepository.com/artifact/com.nimbusds/oauth2-oidc-sdk -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>oauth2-oidc-sdk</artifactId>
</dependency>

<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- JUnit 5 API and Engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.nimbusds/oauth2-oidc-sdk -->
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>oauth2-oidc-sdk</artifactId>
Expand Down Expand Up @@ -71,15 +44,13 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>

<!-- Optional: For parameterized tests -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>

<!-- Mockito (if you are using it for mocking) -->
<!-- Mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
Expand All @@ -91,32 +62,26 @@
<scope>test</scope>
</dependency>


<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<!-- {version} can be 6.0.0, 7.0.0, etc. -->
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>


<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ public void setUp() {
}
""")));

///oauth2/token
System.out.println("Instanciate the wiremock service");
}


Expand Down Expand Up @@ -204,7 +202,6 @@ public void testRegisterUrlRequestTest() {
AuthorizationUrl authorizationUrl1 = kindeClientSession.register();
assertNotNull(authorizationUrl1);
assertNotNull(authorizationUrl1.getUrl());
System.out.println(authorizationUrl1.getUrl());
assertTrue(authorizationUrl1.getUrl().toString().contains("prompt=create"));
assertTrue(authorizationUrl1.getCodeVerifier() == null);

Expand All @@ -223,7 +220,6 @@ public void testRegisterUrlRequestTest() {
AuthorizationUrl authorizationUrl2 = kindeClientSession2.register();
assertNotNull(authorizationUrl2);
assertNotNull(authorizationUrl2.getUrl());
System.out.println(authorizationUrl2.getUrl());
assertTrue(authorizationUrl2.getUrl().toString().contains("prompt=create"));
assertTrue(authorizationUrl2.getUrl().toString().contains("org_code=TEST"));
assertTrue(authorizationUrl2.getUrl().toString().contains("has_success_page=true"));
Expand Down Expand Up @@ -258,7 +254,6 @@ public void testOrgCreateUrlRequestTest() {
AuthorizationUrl authorizationUrl1 = kindeClientSession.createOrg("TEST1");
assertNotNull(authorizationUrl1);
assertNotNull(authorizationUrl1.getUrl());
System.out.println(authorizationUrl1.getUrl());
assertTrue(authorizationUrl1.getUrl().toString().contains("prompt=create"));
assertTrue(authorizationUrl1.getUrl().toString().contains("org_name=TEST1"));
assertTrue(authorizationUrl1.getCodeVerifier() == null);
Expand All @@ -278,7 +273,6 @@ public void testOrgCreateUrlRequestTest() {
AuthorizationUrl authorizationUrl2 = kindeClientSession2.createOrg("TEST2");
assertNotNull(authorizationUrl2);
assertNotNull(authorizationUrl2.getUrl());
System.out.println(authorizationUrl2.getUrl());
assertTrue(authorizationUrl2.getUrl().toString().contains("prompt=create"));
assertTrue(authorizationUrl2.getUrl().toString().contains("org_code=TEST"));
assertTrue(authorizationUrl2.getUrl().toString().contains("org_name=TEST2"));
Expand Down
8 changes: 0 additions & 8 deletions kinde-core/src/test/java/com/kinde/token/IDTokenTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ public void testIDTokenTest() throws Exception {
assertTrue( kindeToken2.token().equals(token2) );
assertTrue( kindeToken2.valid() );


String tokenString = JwtGenerator.generateIDToken();
System.out.println(tokenString);

KindeToken kindeToken4 = IDToken.init(tokenString,true);

System.out.println(kindeToken4.getPermissions());

assertTrue(kindeToken2.getStringFlag("test_str").equals("test_str"));
assertTrue(kindeToken2.getIntegerFlag("test_integer").equals(1));
assertTrue(kindeToken2.getBooleanFlag("test_boolean").equals(false));
Expand Down
4 changes: 0 additions & 4 deletions kinde-j2ee/.env

This file was deleted.

41 changes: 41 additions & 0 deletions kinde-j2ee/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Template for kinde-j2ee .env. Copy to `.env` and fill in your Kinde tenant details.
# `.env` is gitignored; this template is committed so contributors have a starting point.
#
# kinde-j2ee provides KindeAuthenticationFilter / KindeAuthenticationServlet for
# Jakarta EE / Servlet web apps. The SDK reads these variables at runtime; the
# full list of supported keys is defined in com.kinde.config.KindeParameters.

# === Required: tenant + credentials ===
KINDE_DOMAIN=https://<your-subdomain>.kinde.com
KINDE_CLIENT_ID=<your-kinde-client-id>
KINDE_CLIENT_SECRET=<your-kinde-client-secret>

# === Required: OAuth flow ===
# Where Kinde redirects after the user authenticates. Must match the redirect
# URI registered on your Kinde application.
KINDE_REDIRECT_URI=http://localhost:8080/<your-context>/login
# AuthorizationType values: CODE | PKCE | CLIENT_CREDENTIALS | TOKEN
KINDE_GRANT_TYPE=CODE
KINDE_SCOPES=openid,profile,email

# === Optional ===
# Where to send users after logout
# KINDE_LOGOUT_REDIRECT_URI=http://localhost:8080/<your-context>

# Audience claim — required when calling the Kinde Management API
# KINDE_AUDIENCE=https://<your-subdomain>.kinde.com/api

# UI language hint passed to Kinde (e.g. en, fr, de)
# KINDE_LANG=en

# Scope auth to a specific organisation
# KINDE_ORG_CODE=

# Whether Kinde redirects to a success page after registration
# KINDE_HAS_SUCCESS_PAGE=false

# === Endpoint overrides (rarely needed — defaults derive from KINDE_DOMAIN) ===
# KINDE_OPENID_ENDPOINT=https://<your-subdomain>.kinde.com/.well-known/openid-configuration
# KINDE_AUTHORIZATION_ENDPOINT=https://<your-subdomain>.kinde.com/oauth2/auth
# KINDE_TOKEN_ENDPOINT=https://<your-subdomain>.kinde.com/oauth2/token
# KINDE_LOGOUT_ENDPOINT=https://<your-subdomain>.kinde.com/logout
7 changes: 0 additions & 7 deletions kinde-j2ee/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<!-- {version} can be 6.0.0, 7.0.0, etc. -->
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
Expand Down Expand Up @@ -81,10 +80,4 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<!-- Remove nexus-staging-maven-plugin if present -->
</plugins>
</build>
</project>
4 changes: 0 additions & 4 deletions kinde-management/.env

This file was deleted.

29 changes: 29 additions & 0 deletions kinde-management/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Template for kinde-management .env. Copy to `.env` and fill in your Kinde tenant details.
# `.env` is gitignored; this template is committed so contributors have a starting point.
#
# kinde-management is the SDK client for the Kinde Management API. Configure a
# Machine-to-Machine application in Kinde (admin → Applications → Add → M2M) and
# grant it Management API access. The SDK reads these variables at runtime; the
# full list of supported keys is defined in com.kinde.config.KindeParameters.

# === Required: tenant + M2M credentials ===
KINDE_DOMAIN=https://<your-subdomain>.kinde.com
KINDE_CLIENT_ID=<your-kinde-m2m-client-id>
KINDE_CLIENT_SECRET=<your-kinde-m2m-client-secret>

# === Required: target audience ===
KINDE_AUDIENCE=https://<your-subdomain>.kinde.com/api

# === OAuth flow ===
# AuthorizationType values: CODE | PKCE | CLIENT_CREDENTIALS | TOKEN
# For Management API access (M2M) use CLIENT_CREDENTIALS.
KINDE_GRANT_TYPE=CLIENT_CREDENTIALS
# Typically empty for the client_credentials flow.
KINDE_SCOPES=

# === Optional ===
# UI language hint passed to Kinde (e.g. en, fr, de)
# KINDE_LANG=en

# === Endpoint overrides (rarely needed — defaults derive from KINDE_DOMAIN) ===
# KINDE_TOKEN_ENDPOINT=https://<your-subdomain>.kinde.com/oauth2/token
Loading
Loading