Migrate Spring Boot example to Spring Boot 4, Keycloak 26 and Angular 22 - #41
Closed
Wictorgirardi wants to merge 2 commits into
Closed
Wictorgirardi wants to merge 2 commits into
Wictorgirardi wants to merge 2 commits into
Conversation
This was referenced Sep 24, 2026
Contributor
Author
|
Combined into #46 with the other Spring Boot example. The changes are the same; only the commit SHAs differ. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on #28: this branch includes its commit, so review the last commit only until #28 is merged.
Summary
spring-boot-starter-security,spring-boot-starter-security-oauth2-resource-serverandspring-boot-starter-webmvc, plus their-teststarters.GET /api/test/anonymousis public. The old config required a token on all of/api/**, including this endpoint./api/**,/errorand the protected resource metadata are denied.app.cors.allowed-origins./api/test/userincludes the caller'spreferred_username.JwtClaimsConverteris a plain converter without the unchecked cast.jwk-set-uriare removed. The issuer can be overridden withKEYCLOAK_ISSUER_URI.docker-compose.ymlrunsquay.io/phasetwo/phasetwo-keycloak:26.6on port 8888.keycloak/demo-realm-realm.json: the publicdemo-spaclient with PKCE, the realm roleuser, and two users.test/testhas the role;noaccess/noaccessdoesn't.provideAppInitializer.disablePKCE. Tokens are kept in session storage instead of local storage, and debug output is off.provideOAuthClientattaches the access token only to requests to the API.authGuardprotects/protected. The old guard always returnedof(true).tools/e2e-smokeruns against it.TestControllerTestssends requests through the security filter chain and checks the public endpoint, 401, 403, 200 and CORS.JwtClaimsConverterTestschecks the role mapping. None of them need Keycloak.spring-boot-keycloak.ymlruns the shared Gradle workflow for the API and the shared Node workflow for the client.Test plan
./gradlew buildpasses with the Java 21 toolchain. The client'spnpm install --frozen-lockfile && pnpm lint && pnpm test && pnpm buildpasses on Node 24./api/test/anonymousanswers 200 without a token;/api/test/useranswers 401 without a token and with a malformed one;http://localhost:4200and rejected with 403 from another origin.testgets 200 from/api/test/user, andnoaccessgets 403;/protectedgo through Keycloak and come back;tools/e2e-smokepasses on port 4200 withtest/test.Docs drift
blog/2024-05-09-secure-spring-boot.mdx:com.example.spring-boot-keycloak), and the screenshot is outdated.demo-realmwithtest/testandnoaccess/noaccess.demo-spa(PKCE,http://localhost:4200/*, web origin and post logout+), not a confidential client as in_oidc_client_creation_client_auth.mdx.templates/frameworks/_springboot.mdx:${KEYCLOAK_ISSUER_URI:…}, dropsjwk-set-uriand addsapp.cors.allowed-origins.src/main/java/com/example/springbootkeycloak.SecurityConfighas CORS, public/errorandGET /api/test/anonymous, andanyRequest().denyAll(), without@EnableWebSecurityor constructor injection.JwtClaimsConverteris not a@Componentand has no unchecked cast.TestControlleruses@GetMappingand returns JSON records./anonymousis public; the post says both endpoints need a token.NgModule,APP_INITIALIZER,HttpClientModule, local storage anddisablePKCE: true→ a standaloneapp.config.tswithprovideOAuthClientandprovideAppInitializer, PKCE, and session storage.npm run start→pnpm start.user.componentwith*ngIfand a guard that always passed →homewith@if, API buttons, and a functionalauthGuardon/protected.