스프링 부트와 Keycloak 을 연동하며 Redirect uri 에러를 한번도 마주하지 않은 사람은 없을 것이다.
필자는 대부분의 에러가 redircet_uri 에러였고, 어떻게 해결했는지 적어보려 한다.
당시에는 알려진 정보도 없고 버전이 바뀐지 얼마 안되었기 때문에 해결하기 더 어려웠던 것 같다.(2023.04 기준)
(이제는 저 화면들만 봐도 지긋지긋하다..)
대부분 redirect_uri가 잘못 설정되어 로그인 및 인증이 제대로 동작하지 않았다.
redirect_uri 에러에도 종류가 여러가지가 있다.
처음 로그인 화면을 띄울때 발생하는 redirect_uri 에러이다.
아이디와 비밀번호를 입력하고 로그인을 시도하면 발생하는 redirect_uri 에러이다.
Google 또는 Gihub을 이용한 OAuth 로그인 시 발생하는 redirect_uri 에러이다.
- Keycloak 클라이언트 설정에서 정의한 redirect_uri와 실제 애플리케이션에서 사용하는 redirect_uri가 일치하지 않음
- Spring Boot 애플리케이션의 설정에서 redirect_uri가 잘못 설정되어 있음
- 로그인 후 리다이렉트 될 키클락 클라이언트 uri을 redirect_uri에 추가해주지 않음
- Valid Redirect URI 잘못 설정되어 있음
여기서 키클락 클라이언트란 80 서버에서 동작하는 키클락을 실행시키는 springboot 이다.(헷갈리지 말것 **)
8080 서버에서 동작하는 것이 키클락 서버이다.
1. Gateway에서 user-service의 /login 호출
2. 키클락 서버의 로그인 페이지로 리다이렉트
3. 로그인 성공 시 키클락 클라이언트의 /auth 경로로 리다이렉트
4. 인증 성공 시 토큰을 쿠키에 담아서 프론트엔드로 리다이렉트
Keycloak 17 이전 버전에서는 전통적인 WildFly 기반 배포 모델을 사용했다.
http://localhost:8080/auth/realms/{realm-name}/protocol/openid-connect/auth?response_type=code&client_id=admin-client&redirect_uri={redirect_uri}&scope=openid&nonce=asb3
http://localhost:8080/auth/realms/{realm-name}/protocol/openid-connect/token
http://localhost:8080/login/oauth2/code/keycloak
그래서 다음과 같은 URI 패턴을 사용했다.
Keycloak 17 버전 이후부터는 Quarkus 기반의 새로운 배포 모델을 도입했다.
이로 인해 URL 패턴에 일부 변경 사항이 발생했다.
http://localhost:8080/realms/{realm-name}/protocol/openid-connect/auth?response_type=code&client_id=admin-client&redirect_uri={redirect_uri}&scope=openid&nonce=asb3
http://localhost:8080/realms/{realm-name}/protocol/openid-connect/token
http://localhost:8080/login/oauth2/code/keycloak
17 이후 버전부터는 /auth 라는 경로가 사라진 것을 확인할 수 있다.
경로가 변경된 것을 모르고 /auth 경로를 포함해서 계속 리다이렉트 시켰고, 로그인 페이지가 뜨지 않았다. 에러 메시지도 redirect_uri 딱 하나 줘서 며칠씩 해결하느라 고생했던 기억이 있다.
따라서 키클락 17 이후 버전을 사용한다면 변경된 URL 패턴을 사용해야 한다!
이슈 1번의 경우, 로그인 화면을 호출할때 변경된 URL 패턴을 적용시켜주어 해결하였다.
=> /auth 제외
@GetMapping("/login")
public void login(Principal principal, HttpServletRequest request, HttpServletResponse response)
throws IOException {
response.sendRedirect(keycloakServerUrl
+ "/realms/master/protocol/openid-connect/auth?response_type=code&client_id=admin-client&redirect_uri="
+ keycloakClientUrl + "/auth&scope=openid&nonce=asb3"
);
}
keycloak:
realm: master
client-url: http://localhost
server-url: http://localhost:8080
아이디와 비밀번호를 입력하고 로그인을 시도하면 발생하는 redirect_uri는 Valid Redirect URL 주소와 스프링 부트에서 redirect_uri를 수정해야 한다.
http://localhost:80/*
http://localhost:8080/login/oauth2/code/keycloak
keycloakServerUrl
+ "/realms/master/protocol/openid-connect/auth?response_type=code&client_id=admin-client&redirect_uri="
+ keycloakClientUrl + "/auth&scope=openid&nonce=asb3
=> 이렇게 하면 로그인 성공 시 위에서 설정한 localhost:80/auth 경로로 리다이렉트 되고, 인증 코드를 사용하여 액세스 토큰을 요청하고, 토큰을 쿠키에 저장한 후, 프론트엔드로 리다이렉션한다.
OAuth Login 시에도 마찬가지로 로그인 성공하면 인증 경로(http://localhost:80/auth)로 리다이렉트 되어야 했다. 이와 관련된 설정을 해주지 않아 인증 오류 혹은 리다이렉트 에러가 났다.
Google
Google Cloud Platform 접속 - API 및 서비스 - 사용자 인증 정보 - 생성한 프로젝트 선택
http://localhost:80
**그 외의 Github 등 Identity provider도 동일하게 진행한다.
server:
port: 80
spring:
application:
name: SSO-service
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/master
jwk-set-uri: ${spring.security.oauth2.resourceserver.jwt.issuer-uri}/protocol/openid-connect/certs
client:
provider:
github:
authorization-uri: https://github.com/login/oauth/authorize
token-uri: https://github.com/login/oauth/access_token
user-info-uri: https://api.github.com/user
user-name-attribute: login
keycloak:
issuer-uri: http://localhost:8080/realms/master
user-name-attribute: preferred_username
registration:
google:
client-id: ----
client-secret: ---
scope:
- email
- profile
redirect-uri: "http://localhost:8080/realms/master/broker/google/endpoint"
client-name: Google
provider: google
keycloak:
provider: keycloak
client-id: SSOService
client-secret: ---
scope: openid
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/login/oauth2/code/keycloak'
github:
client-id: --
client-secret: ---
authorization-grant-type: authorization_code
redirect-uri: "http://localhost:8080/realms/master/broker/github/endpoint"
client-name: GitHub
provider: github
jwt:
auth:
converter:
resource-id: SSOService
principal-attribute: preferred_username
keycloak:
realm: master
client-url: http://localhost
server-url: http://localhost:8080
auth-server-url: http://localhost:8080/auth
ssl-required: external
resource: admin-client
credentials:
secret: admin-secret
use-resource-role-mappings: true
bearer-only: true
logout-url: http://localhost:8080/realms/master/protocol/openid-connect/logout
logout-redirect-url: http://localhost:8080/realms/master/protocol/openid-connect/logout?post_logout_redirect_uri=http://socoa.online/&client_id=admin-client
mykeycloak:
client:
id: admin-cli
admin:
name: --
password: ---
socoa:
domain: localhost
gateway:
url: http://localhost:8000
코드를 참고하여 잘못된 부분은 없는지 확인하길 바란다.