Skip to content

Commit 59aacad

Browse files
authored
[improve/#440] OAuth 성공 리다이렉트에서 access token 제거 (#447)
* improve: OAuth 성공 리다이렉트에서 access 토큰 노출 제거 * improve: 리다이렉트 url 대신 이름을 로그인 성공 리다이렉트 url로 개선 * improve: CI/CD 파이프라인에도 관련 사항을 반영 * test: email에 query 관련 파라미터가 들어가도 별도로 생성되지 않도록 함을 테스트로 보장 * improve: 더이상 OAuth 로그인 성공 시 access token은 생성하지 않도록 변경 * refactor: 클래스 이름을 refresh 토큰에 맞게 명확하게 변경
1 parent 52b7949 commit 59aacad

19 files changed

Lines changed: 194 additions & 115 deletions

.github/workflows/cd.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,13 @@ jobs:
6464
KAKAO_REST_API_KEY: ${{ secrets.KAKAO_REST_API_KEY }}
6565
KAKAO_CLIENT_SECRET: ${{ secrets.KAKAO_CLIENT_SECRET }}
6666
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
67-
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
68-
APPLE_CLIENT_ID: ${{ secrets.APPLE_CLIENT_ID }}
69-
JWT_SECRET: ${{ secrets.JWT_SECRET }}
70-
JWT_REDIRECT_URI: ${{ secrets.JWT_REDIRECT_URI }}
71-
JWT_REDIRECT_URI_DEV: ${{ secrets.JWT_REDIRECT_URI_DEV }}
72-
JWT_LOGIN_FAILURE_REDIRECT_URI: ${{ secrets.JWT_LOGIN_FAILURE_REDIRECT_URI }}
73-
JWT_LOGIN_FAILURE_REDIRECT_URI_DEV: ${{ secrets.JWT_LOGIN_FAILURE_REDIRECT_URI_DEV }}
67+
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
68+
APPLE_CLIENT_ID: ${{ secrets.APPLE_CLIENT_ID }}
69+
JWT_SECRET: ${{ secrets.JWT_SECRET }}
70+
JWT_LOGIN_SUCCESS_REDIRECT_URI: ${{ secrets.JWT_LOGIN_SUCCESS_REDIRECT_URI }}
71+
JWT_LOGIN_SUCCESS_REDIRECT_URI_DEV: ${{ secrets.JWT_LOGIN_SUCCESS_REDIRECT_URI_DEV }}
72+
JWT_LOGIN_FAILURE_REDIRECT_URI: ${{ secrets.JWT_LOGIN_FAILURE_REDIRECT_URI }}
73+
JWT_LOGIN_FAILURE_REDIRECT_URI_DEV: ${{ secrets.JWT_LOGIN_FAILURE_REDIRECT_URI_DEV }}
7474
SERVER_DOMAIN: ${{ secrets.SERVER_DOMAIN }}
7575
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED: ${{ secrets.CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED }}
7676
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV: ${{ secrets.CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED }}
@@ -115,12 +115,12 @@ jobs:
115115
command_timeout: 10m
116116
envs: >-
117117
DOCKER_IMAGE,BRANCH,SPRING_PROFILES_ACTIVE,DB_URL,DB_PASSWORD,REDIS_PASSWORD,
118-
DISCORD_WEBHOOK_URL,ANTHROPIC_API_KEY,OPENAI_API_KEY,
119-
KAKAO_REST_API_KEY,KAKAO_CLIENT_SECRET,
120-
APPLE_TEAM_ID,APPLE_KEY_ID,APPLE_CLIENT_ID,
121-
JWT_SECRET,JWT_REDIRECT_URI,JWT_REDIRECT_URI_DEV,JWT_LOGIN_FAILURE_REDIRECT_URI,JWT_LOGIN_FAILURE_REDIRECT_URI_DEV,SERVER_DOMAIN,
122-
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED,CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL,
123-
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV,CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV
118+
DISCORD_WEBHOOK_URL,ANTHROPIC_API_KEY,OPENAI_API_KEY,
119+
KAKAO_REST_API_KEY,KAKAO_CLIENT_SECRET,
120+
APPLE_TEAM_ID,APPLE_KEY_ID,APPLE_CLIENT_ID,
121+
JWT_SECRET,JWT_LOGIN_SUCCESS_REDIRECT_URI,JWT_LOGIN_SUCCESS_REDIRECT_URI_DEV,JWT_LOGIN_FAILURE_REDIRECT_URI,JWT_LOGIN_FAILURE_REDIRECT_URI_DEV,SERVER_DOMAIN,
122+
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED,CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL,
123+
CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV,CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_DELIVERY_BASE_URL_DEV
124124
script: |
125125
cd ~/deploy
126126
chmod +x scripts/deploy.sh

docker/docker-compose.blue.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ services:
1818
- APPLE_TEAM_ID=${APPLE_TEAM_ID}
1919
- APPLE_KEY_ID=${APPLE_KEY_ID}
2020
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
21-
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
22-
- JWT_SECRET=${JWT_SECRET}
23-
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI}
21+
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
22+
- JWT_SECRET=${JWT_SECRET}
23+
- JWT_LOGIN_SUCCESS_REDIRECT_URI=${JWT_LOGIN_SUCCESS_REDIRECT_URI}
2424
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI}
2525
- SERVER_DOMAIN=${SERVER_DOMAIN}
2626
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED}

docker/docker-compose.dev.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ services:
2020
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
2121
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
2222
- JWT_SECRET=${JWT_SECRET}
23-
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI_DEV}
23+
- JWT_LOGIN_SUCCESS_REDIRECT_URI=${JWT_LOGIN_SUCCESS_REDIRECT_URI_DEV}
2424
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI_DEV}
2525
- SERVER_DOMAIN=${SERVER_DOMAIN}
2626
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED_DEV}

docker/docker-compose.green.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ services:
1818
- APPLE_TEAM_ID=${APPLE_TEAM_ID}
1919
- APPLE_KEY_ID=${APPLE_KEY_ID}
2020
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
21-
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
22-
- JWT_SECRET=${JWT_SECRET}
23-
- JWT_REDIRECT_URI=${JWT_REDIRECT_URI}
21+
- APPLE_PRIVATE_KEY_PATH=/app/keys/AuthKey_${APPLE_KEY_ID}.p8
22+
- JWT_SECRET=${JWT_SECRET}
23+
- JWT_LOGIN_SUCCESS_REDIRECT_URI=${JWT_LOGIN_SUCCESS_REDIRECT_URI}
2424
- JWT_LOGIN_FAILURE_REDIRECT_URI=${JWT_LOGIN_FAILURE_REDIRECT_URI}
2525
- SERVER_DOMAIN=${SERVER_DOMAIN}
2626
- CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED=${CLOUDFLARE_THIRD_PARTY_THUMBNAIL_OPTIMIZATION_ENABLED}

src/main/java/com/techfork/auth/security/handler/login/OAuth2AuthenticationSuccessHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
@RequiredArgsConstructor
1818
public class OAuth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
1919

20-
private final OAuth2LoginTokenIssuer tokenIssuer;
20+
private final OAuth2LoginRefreshTokenIssuer refreshTokenIssuer;
2121
private final OAuth2LoginRefreshTokenWriter refreshTokenWriter;
2222
private final OAuth2LoginRedirectUrlFactory redirectUrlFactory;
2323

@@ -26,13 +26,13 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
2626
Authentication authentication) throws IOException, ServletException {
2727
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
2828

29-
OAuth2LoginTokens tokens = tokenIssuer.issue(userPrincipal);
30-
refreshTokenWriter.write(userPrincipal.getId(), tokens, response);
29+
OAuth2LoginRefreshToken issuedRefreshToken = refreshTokenIssuer.issue(userPrincipal);
30+
refreshTokenWriter.write(userPrincipal.getId(), issuedRefreshToken, response);
3131

3232
log.info("OAuth2 login success - userId: {}, role: {}, status: {}, email: {}",
3333
userPrincipal.getId(), userPrincipal.getRole(), userPrincipal.getStatus(), userPrincipal.getEmail());
3434

35-
String targetUrl = redirectUrlFactory.createSuccessRedirectUrl(userPrincipal, tokens.accessToken());
35+
String targetUrl = redirectUrlFactory.createSuccessRedirectUrl(userPrincipal);
3636

3737
getRedirectStrategy().sendRedirect(request, response, targetUrl);
3838
}

src/main/java/com/techfork/auth/security/handler/login/OAuth2LoginRedirectUrlFactory.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
import lombok.RequiredArgsConstructor;
77
import org.springframework.stereotype.Component;
88
import org.springframework.web.util.UriComponentsBuilder;
9-
import org.springframework.web.util.UriUtils;
10-
11-
import java.nio.charset.StandardCharsets;
129

1310
@Component
1411
@RequiredArgsConstructor
@@ -18,12 +15,17 @@ class OAuth2LoginRedirectUrlFactory {
1815

1916
private final JwtProperties jwtProperties;
2017

21-
public String createSuccessRedirectUrl(UserPrincipal userPrincipal, String accessToken) {
18+
public String createSuccessRedirectUrl(UserPrincipal userPrincipal) {
2219
boolean isRegistered = userPrincipal.getStatus() == UserStatus.ACTIVE;
23-
String email = userPrincipal.getEmail() != null ?
24-
UriUtils.encode(userPrincipal.getEmail(), StandardCharsets.UTF_8) : "";
20+
String email = userPrincipal.getEmail() != null ? userPrincipal.getEmail() : "";
2521

26-
return String.format(jwtProperties.getRedirectUri(), isRegistered, accessToken, email);
22+
return UriComponentsBuilder.fromUriString(jwtProperties.getLoginSuccessRedirectUri())
23+
.replaceQuery(null)
24+
.queryParam("registered", isRegistered)
25+
.queryParam("email", email)
26+
.build()
27+
.encode()
28+
.toUriString();
2729
}
2830

2931
public String createFailureRedirectUrl() {

src/main/java/com/techfork/auth/security/handler/login/OAuth2LoginTokens.java renamed to src/main/java/com/techfork/auth/security/handler/login/OAuth2LoginRefreshToken.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.techfork.auth.security.handler.login;
22

3-
record OAuth2LoginTokens(
4-
String accessToken,
3+
record OAuth2LoginRefreshToken(
54
String refreshToken,
65
long refreshTokenExpiration
76
) {

src/main/java/com/techfork/auth/security/handler/login/OAuth2LoginTokenIssuer.java renamed to src/main/java/com/techfork/auth/security/handler/login/OAuth2LoginRefreshTokenIssuer.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.techfork.auth.security.handler.login;
22

3-
import com.techfork.auth.security.jwt.JwtDTO;
43
import com.techfork.auth.security.jwt.JwtProperties;
54
import com.techfork.auth.security.jwt.JwtUtil;
65
import com.techfork.auth.security.oauth.UserPrincipal;
@@ -9,16 +8,15 @@
98

109
@Component
1110
@RequiredArgsConstructor
12-
class OAuth2LoginTokenIssuer {
11+
class OAuth2LoginRefreshTokenIssuer {
1312

1413
private final JwtUtil jwtUtil;
1514
private final JwtProperties jwtProperties;
1615

17-
public OAuth2LoginTokens issue(UserPrincipal userPrincipal) {
18-
JwtDTO tokens = jwtUtil.generateTokens(userPrincipal.getId(), userPrincipal.getRole());
19-
return new OAuth2LoginTokens(
20-
tokens.accessToken(),
21-
tokens.refreshToken(),
16+
public OAuth2LoginRefreshToken issue(UserPrincipal userPrincipal) {
17+
String refreshToken = jwtUtil.generateRefreshToken(userPrincipal.getId(), userPrincipal.getRole());
18+
return new OAuth2LoginRefreshToken(
19+
refreshToken,
2220
jwtProperties.getRefreshTokenExpiration()
2321
);
2422
}

src/main/java/com/techfork/auth/security/handler/login/OAuth2LoginRefreshTokenWriter.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,16 @@ class OAuth2LoginRefreshTokenWriter {
1313
private final RefreshTokenStore refreshTokenStore;
1414
private final RefreshTokenCookieWriter refreshTokenCookieWriter;
1515

16-
public void write(Long userId, OAuth2LoginTokens tokens, HttpServletResponse response) {
17-
refreshTokenStore.saveRefreshToken(userId, tokens.refreshToken(), tokens.refreshTokenExpiration());
18-
refreshTokenCookieWriter.write(response, tokens.refreshToken(), tokens.refreshTokenExpiration());
16+
public void write(Long userId, OAuth2LoginRefreshToken issuedRefreshToken, HttpServletResponse response) {
17+
refreshTokenStore.saveRefreshToken(
18+
userId,
19+
issuedRefreshToken.refreshToken(),
20+
issuedRefreshToken.refreshTokenExpiration()
21+
);
22+
refreshTokenCookieWriter.write(
23+
response,
24+
issuedRefreshToken.refreshToken(),
25+
issuedRefreshToken.refreshTokenExpiration()
26+
);
1927
}
2028
}

src/main/java/com/techfork/auth/security/jwt/JwtProperties.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ public class JwtProperties {
1313
private String secret;
1414
private long accessTokenExpiration;
1515
private long refreshTokenExpiration;
16-
private String redirectUri;
16+
private String loginSuccessRedirectUri;
1717
private String loginFailureRedirectUri;
18-
}
18+
}

0 commit comments

Comments
 (0)