Conversation
…into fix-api-deploy # Conflicts: # .github/workflows/deploy.yml
…er into fix/oauth2-redirecting
There was a problem hiding this comment.
Pull request overview
This PR modifies the OAuth2 authentication flow to redirect to a frontend callback URL instead of returning JSON responses directly. The changes also include various configuration updates, code cleanup, and infrastructure modifications.
Changes:
- OAuth2 success handler now redirects to frontend with URL-encoded data instead of returning JSON responses
- JWT token validity configuration changed from milliseconds to seconds (with critical bug)
- Added email field to UserInfoResponse and mail configuration to application.yml
- Updated deployment workflow from AWS ECR to GitHub Container Registry (GHCR) with on-premise deployment
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/until/the/eternity/das/oauth/handler/OAuth2SuccessHandler.java | Refactored to redirect to frontend callback URL with encoded data/error in query parameters |
| src/main/resources/application-sample.yml | Added mail config, changed JWT validity to seconds, made DB host configurable, added S3 endpoint config |
| src/main/java/until/the/eternity/das/auth/presentation/AuthController.java | Added JWT token generation and cookie setting after social signup completion |
| src/main/java/until/the/eternity/das/oauth/service/SocialAuthService.java | Added jwtForSocialSignUp method, made profile image optional |
| src/main/java/until/the/eternity/das/user/dto/response/UserInfoResponse.java | Added email field to response |
| src/main/java/until/the/eternity/das/common/util/CookieUtil.java | Hardcoded cookie domain to .memonogi.com |
| src/main/java/until/the/eternity/das/common/application/S3Service.java | Improved image deletion with URI parsing |
| src/main/resources/db/migration/V20250721224045__insert_default_data.sql | Changed schema name from 'devnogi' to 'auth' |
| .github/workflows/deploy-prod.yml | New deployment workflow using GHCR and on-premise server |
| docker-compose-auth-prod.yml | New production docker-compose configuration |
| Dockerfile | Changed exposed port from 8080 to 8091 |
| src/main/java/until/the/eternity/das/DasApplication.java | Added timezone configuration and async support |
| Multiple files | Removed various TODO comments and code cleanup |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| access-token-validity: ${JWT_ACCESS_TOKEN_VALIDITY:3600} # seconds (1 hour) | ||
| refresh-token-validity: ${JWT_REFRESH_TOKEN_VALIDITY:86400} # seconds (1 day) |
There was a problem hiding this comment.
The JWT token validity configuration has been changed from milliseconds to seconds (3600 instead of 3600000 for access token, 86400 instead of 86400000 for refresh token), but the JwtUtil.createToken method still expects milliseconds.
In JwtUtil.java line 79, the code uses new Date(now.getTime() + expiration) where getTime() returns milliseconds since epoch, and it directly adds the expiration value. This means the tokens will now expire in 3600 milliseconds (3.6 seconds) instead of 1 hour, and 86400 milliseconds (86.4 seconds) instead of 1 day.
This will cause tokens to expire almost immediately, breaking authentication functionality. Either revert the configuration values back to milliseconds, or update JwtUtil.createToken to multiply the expiration value by 1000 to convert seconds to milliseconds.
| access-token-validity: ${JWT_ACCESS_TOKEN_VALIDITY:3600} # seconds (1 hour) | |
| refresh-token-validity: ${JWT_REFRESH_TOKEN_VALIDITY:86400} # seconds (1 day) | |
| access-token-validity: ${JWT_ACCESS_TOKEN_VALIDITY:3600000} # 1 hour (milliseconds) | |
| refresh-token-validity: ${JWT_REFRESH_TOKEN_VALIDITY:86400000} # 1 day (milliseconds) |
| .secure(true) | ||
| .sameSite("None") | ||
| .path("/") | ||
| .domain(".memonogi.com") |
There was a problem hiding this comment.
The domain is now hardcoded to '.memonogi.com' in the cookie configuration. This will prevent the application from working in non-production environments (local development, staging) unless those environments also use the memonogi.com domain.
Consider making the cookie domain configurable via application properties (e.g., ${app.cookie.domain:.memonogi.com}) to support different environments. For local development, the domain should typically be omitted or set to localhost.
| .secure(true) | ||
| .sameSite("None") | ||
| .path("/") | ||
| .domain(".memonogi.com") |
There was a problem hiding this comment.
The domain is now hardcoded to '.memonogi.com' in the cookie configuration. This will prevent the application from working in non-production environments (local development, staging) unless those environments also use the memonogi.com domain.
Consider making the cookie domain configurable via application properties (e.g., ${app.cookie.domain:.memonogi.com}) to support different environments. For local development, the domain should typically be omitted or set to localhost.
| host: smtp.gmail.com | ||
| port: 587 | ||
| username: ${MAIL_USERNAME:devnogi.auth@gmail.com} | ||
| password: ${MAIL_PASSWORD:ipghhpopgxncgzgg} |
There was a problem hiding this comment.
A default email password is exposed in the configuration file ('ipghhpopgxncgzgg'). Even though this is a sample configuration file, including actual credentials (even if they're app-specific passwords) is a security risk.
The default value should be a placeholder like 'your-app-password-here' or completely omitted, requiring users to set it via environment variables. If this is a real credential, it should be rotated immediately and never committed to version control.
| password: ${MAIL_PASSWORD:ipghhpopgxncgzgg} | |
| password: ${MAIL_PASSWORD:your-app-password-here} |
| VOLUME /app/config | ||
|
|
||
| EXPOSE 8080 | ||
| EXPOSE 8091 |
There was a problem hiding this comment.
The EXPOSE port has been changed from 8080 to 8091. Ensure this change is intentional and that all related configurations are updated consistently:
- The SERVER_PORT environment variable in deployment configurations
- Load balancer or reverse proxy configurations
- Documentation
- Any hardcoded references to port 8080
The docker-compose-auth-prod.yml file references ${SERVER_PORT} which should be set to 8091 in the environment configuration.
| EXPOSE 8091 | |
| EXPOSE 8080 |
| private final ObjectMapper objectMapper; | ||
| private final TokenService tokenService; | ||
|
|
||
| @Value("${app.oauth.redirect-uri:https://www.memonogi.com/social-callback}") |
There was a problem hiding this comment.
The OAuth redirect URI is hardcoded as a default value ('https://www.memonogi.com/social-callback'). While it has a default value, it should be configurable via environment-specific properties to support different environments (development, staging, production).
Consider removing the default value and requiring it to be set via environment variables, or at minimum, document that this must be overridden for non-production environments. The current setup could lead to OAuth callbacks being sent to production URLs from development/staging environments.
| @Value("${app.oauth.redirect-uri:https://www.memonogi.com/social-callback}") | |
| @Value("${app.oauth.redirect-uri}") |
| user.updateLastLoginAt(); | ||
| userRepository.save(user); |
There was a problem hiding this comment.
The user.updateLastLoginAt() call followed by userRepository.save(user) is not wrapped in a @transactional annotation. If the redirect fails after saving, or if there are concurrent requests, this could lead to inconsistent state.
Consider wrapping this logic in a @transactional method or moving it to a service layer method that handles transactions properly. Additionally, the save operation should happen before the redirect to ensure data consistency even if the redirect fails.
| datasource: | ||
| driver-class-name: com.mysql.cj.jdbc.Driver | ||
| url: jdbc:mysql://localhost:${DB_PORT}/${DB_SCHEMA} | ||
| url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA} |
There was a problem hiding this comment.
The database URL has been changed from 'localhost' to '${DB_HOST}', making it configurable. This is a good improvement for flexibility. However, ensure that:
- The default value or documentation specifies that DB_HOST should be 'localhost' for local development
- All deployment configurations (docker-compose files, environment files) set DB_HOST appropriately
- This breaking change is communicated to developers who may have existing local setups
Consider adding a default value like ${DB_HOST:localhost} to maintain backward compatibility.
| url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA} | |
| url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT}/${DB_SCHEMA} |
| .secure(true) | ||
| .sameSite("None") | ||
| .path("/") | ||
| .domain(".memonogi.com") |
There was a problem hiding this comment.
The domain is now hardcoded to '.memonogi.com' in the cookie configuration. This will prevent the application from working in non-production environments (local development, staging) unless those environments also use the memonogi.com domain.
Consider making the cookie domain configurable via application properties (e.g., ${app.cookie.domain:.memonogi.com}) to support different environments. For local development, the domain should typically be omitted or set to localhost.
| SignUpResponse result = socialAuthService.completeSocialSignup(request); | ||
|
|
||
| LoginResultResponse loginResultResponse = socialAuthService.jwtForSocialSignUp(result.id()); | ||
|
|
||
| cookieUtil.createAccessTokenCookie(response, loginResultResponse.accessToken()); | ||
| cookieUtil.createRefreshTokenCookie(response, loginResultResponse.refreshToken()); |
There was a problem hiding this comment.
After completing social signup, the code calls two separate @transactional methods: completeSocialSignup() and jwtForSocialSignUp(). If jwtForSocialSignUp() fails (e.g., due to token generation error), the user will be created but won't receive JWT tokens, leading to an incomplete registration state.
Consider combining these operations into a single transactional method, or implement compensating logic to handle failures in the token generation step. Additionally, consider whether it's appropriate to update lastLoginAt immediately after signup - typically this should only be updated on subsequent logins, not on initial registration.
📋 상세 설명
📊 체크리스트
📆 마감일