Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
f5f3a69
[BOOK-179] chore: apis, gateway - 유틸클래스 패키지 이동
move-hoon Jul 28, 2025
fb422de
[BOOK-179] chore: buildSrc, apis - 애플 로그인 로직에 사용될 의존성 추가
move-hoon Jul 28, 2025
1f99f1c
[BOOK-179] chore: apis - BouncyCastle PKIX 의존성 추가
move-hoon Jul 28, 2025
4c8e488
[BOOK-179] feat: SocialLoginRequest에 Apple 로그인용 authorizationCode 필드 …
move-hoon Jul 28, 2025
9684fde
[BOOK-179] feat: apis - AuthErrorCode에 잘못된 요청 및 내부 서버 오류 관련 에러 코드 추가
move-hoon Jul 28, 2025
c8d878d
[BOOK-179] feat: apis - Apple 로그인용 client-secret 생성기 클래스 추가
move-hoon Jul 28, 2025
e11c07a
[BOOK-179] feat: apis - Apple 로그인용 idToken 처리 및 검증 클래스 추가
move-hoon Jul 28, 2025
a0ad3a8
[BOOK-179] feat: apis - Apple 로그인용 개인 키 로더 클래스 추가
move-hoon Jul 28, 2025
ef3ddc9
[BOOK-179] refactor: apis - AuthTokenService로 역할 변경
move-hoon Jul 28, 2025
ce234b3
[BOOK-179] refactor: apis - AuthUseCase에서 AuthTokenHelper를 AuthTokenS…
move-hoon Jul 28, 2025
7e0ab49
[BOOK-179] feat: apis - Apple 로그인용 PEM 형식 키 쌍 파서 클래스 추가
move-hoon Jul 28, 2025
4ee7bfd
[BOOK-179] feat: apis - Apple 로그인용 authorizationCode 필드 추가
move-hoon Jul 28, 2025
13def58
[BOOK-179] delete: apis - AppleJwtHelper.kt 파일 삭제
move-hoon Jul 28, 2025
133a984
[BOOK-179] feat: apis - Apple 인증 전략 개선 및 AudienceValidator, AppleOaut…
move-hoon Jul 28, 2025
3b3b967
[BOOK-179] feat: apis - Apple OAuth 인증을 위한 JWKSource 및 JwtEncoder, Jw…
move-hoon Jul 28, 2025
6f0b792
[BOOK-179] chore: apis - AuthController에서 불필요한 주석 제거 및 application.ym…
move-hoon Jul 28, 2025
77179de
[BOOK-179] chore: buildSrc - BouncyCastle에 PKIX 의존성 추가
move-hoon Jul 28, 2025
459fde7
[BOOK-179] chore: apis - 역할에 맞는 네이밍으로 변경
move-hoon Jul 30, 2025
8d19a77
[BOOK-179] feat: domain, infra - apple 리프레쉬 토큰 칼럼 추가
move-hoon Jul 30, 2025
a999ab1
[BOOK-179] feat: domain - UserAuthVO 클래스 생성 (appleRefreshToken 포함)
move-hoon Jul 30, 2025
2bae78e
[BOOK-179] refactor: domain - 애플 리프레쉬 토큰 저장을 위해 UserIdentityVO를 UserA…
move-hoon Jul 30, 2025
cbc73a4
[BOOK-179] refactor: apis - dto 필드에 애플 리프레쉬 토큰 필드 추가
move-hoon Jul 30, 2025
4846f5b
[BOOK-179] refactor: apis - KakaoApiHelper를 KakaoApiManager로 리네이밍 및 예…
move-hoon Jul 30, 2025
22e5809
[BOOK-179] refactor: apis - KakaoApiHelper를 KakaoApiManager로 리네이밍 변경사…
move-hoon Jul 30, 2025
8b1be25
[BOOK-179] chore: apis - TokenService를 RefreshTokenService로 역할에 맞게 리네이밍
move-hoon Jul 30, 2025
cc4ecc0
[BOOK-179] delete: apis - JwtConfig 내부에 validate 로직을 구현함으로서 AudienceV…
move-hoon Jul 30, 2025
5345650
[BOOK-179] chore: apis - 사용하지 않는 Import문 제거
move-hoon Jul 30, 2025
aa0c320
[BOOK-179] feat: infra, apis - Apple OAuth 연동을 위한 클래스 추가
move-hoon Jul 30, 2025
61d734b
[BOOK-179] refactor: apis, domain - 에러코드 통일화
move-hoon Jul 30, 2025
6b9be47
[BOOK-179] refactor: apis - refreshTokenService로 네이밍 변경한 부분 반영
move-hoon Jul 30, 2025
3c3ed33
[BOOK-179] fix: apis - 누락된 validation 추가
move-hoon Jul 30, 2025
1396a2b
[BOOK-179] feat: infra - Apple OAuth 클라이언트 시크릿 포함 요청 반환 DTO 추가
move-hoon Jul 30, 2025
6e6f071
[BOOK-179] feat: apis - 애플 로그인의 경우 refreshToken을 받아와 DB에 저장하는 기능 추가
move-hoon Jul 30, 2025
16bdc59
[BOOK-179] chore: apis - 명세 한국어로 변경하여 다른 도메인과 통일
move-hoon Jul 30, 2025
e8d1968
[BOOK-179] fix: apis - Apple JWT 키 파싱 오류 해결
move-hoon Jul 30, 2025
240ade8
[BOOK-179] chore: apis - Kakao admin-key 환경 변수로 변경
move-hoon Jul 30, 2025
8c23a14
[BOOK-179] refactor: apis, infra - 애플 로그인 시 refreshToken 누락에 대한 에러 코드…
move-hoon Jul 30, 2025
27a4598
[BOOK-179] chore: 코드레빗 collapse_walkthrough를 false로 변경
move-hoon Jul 30, 2025
d35387a
[BOOK-179] fix: conflict 해결
move-hoon Aug 5, 2025
5f2fd66
[BOOK-179] chore: apis, domain - 오류 코드 메시지를 한국어로 변경
move-hoon Aug 5, 2025
1a00c0b
[BOOK-179] feat: apis - 유효성 검사를 위한 @Validated 및 @Valid 어노테이션 추가
move-hoon Aug 5, 2025
4d6c201
[BOOK-179] feat: CI/CD - Apple 인증 키를 비밀 파일로 추가
move-hoon Aug 5, 2025
5295456
[BOOK-179] chore: apis, infra - OAuth 설정을 application-external.yml로 이동
move-hoon Aug 5, 2025
464a354
[BOOK-179] refactor: kakao-login.html에 Apple 로그인 기능 개선 및 콜백 처리 추가
move-hoon Aug 5, 2025
a4d6823
[BOOK-179] test: apis - ApplicationContext 로딩 실패 오류 해결
move-hoon Aug 5, 2025
52b23f6
[BOOK-179] refactor: apis - ApplePrivateKeyLoader 빈 등록을 test 환경에서 비활성화
move-hoon Aug 5, 2025
13ac77c
[BOOK-179] chore: apis - 테스트용 dummy Aladin API 키 및 Apple OAuth 설정 추가
move-hoon Aug 5, 2025
a521bc0
[BOOK-179] chore: gateway - securityconfig 파일 주석 제거
move-hoon Aug 5, 2025
be30814
[BOOK-179] refactor: AladinApi 및 AladinRestClient에서 ttbKey를 non-null로 변경
move-hoon Aug 5, 2025
fd7d406
[BOOK-179] chore: infra - application-external.yml에서 Apple OAuth 설정의 …
move-hoon Aug 5, 2025
7c1171c
[BOOK-179] refactor: apis - Apple ID 토큰 유효성 검사 시 예외 처리 추가 및 오류 코드 정의
move-hoon Aug 5, 2025
c7505ea
[BOOK-179] chore: apis, infra - Aladin API 키 이름을 하이픈 형식으로 변경
move-hoon Aug 5, 2025
3afcb9a
[BOOK-179] refactor: apis - ApplePrivateKeyLoader에서 Apple 개인 키 파싱 시 예…
move-hoon Aug 5, 2025
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
2 changes: 1 addition & 1 deletion .coderabbit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ reviews:
high_level_summary: true
poem: false
review_status: true
collapse_walkthrough: true
collapse_walkthrough: false
auto_review:
enabled: true
drafts: false
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
echo "${{ secrets.APPLE_AUTH_KEY }}" > ./secret/AuthKey.p8
chmod 600 ./secret/*

- name: Set up JDK 21
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/dev-ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
mkdir ./secret
echo "${{ secrets.DEV_SECRET_PROPERTIES }}" > ./secret/application-dev-secret.properties
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
echo "${{ secrets.APPLE_AUTH_KEY }}" > ./secret/AuthKey.p8
chmod 600 ./secret/*

- name: Set up Docker Buildx
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/prod-ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
mkdir ./secret
echo "${{ secrets.PROD_SECRET_PROPERTIES }}" > ./secret/application-prod-secret.properties
echo "${{ secrets.TEST_SECRET_PROPERTIES }}" > ./secret/application-test-secret.properties
echo "${{ secrets.APPLE_AUTH_KEY }}" > ./secret/AuthKey.p8
chmod 600 ./secret/*

- name: Set up Docker Buildx
Expand Down
6 changes: 6 additions & 0 deletions apis/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ dependencies {
implementation(Dependencies.Spring.BOOT_STARTER_SECURITY)
implementation(Dependencies.Spring.BOOT_STARTER_VALIDATION)
implementation(Dependencies.Spring.BOOT_STARTER_ACTUATOR)
implementation(Dependencies.Spring.BOOT_STARTER_OAUTH2_CLIENT)

implementation(Dependencies.Database.MYSQL_CONNECTOR)

implementation(Dependencies.Swagger.SPRINGDOC_OPENAPI_STARTER_WEBMVC_UI)

implementation(Dependencies.Logging.KOTLIN_LOGGING)

implementation(Dependencies.BouncyCastle.BC_PROV)
implementation(Dependencies.BouncyCastle.BC_PKIX)

annotationProcessor(Dependencies.Spring.CONFIGURATION_PROCESSOR)

testImplementation(Dependencies.Spring.BOOT_STARTER_TEST)
testImplementation(Dependencies.TestContainers.MYSQL)
testImplementation(Dependencies.TestContainers.JUNIT_JUPITER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ import org.yapp.apis.auth.dto.response.UserProfileResponse
import org.yapp.apis.auth.usecase.AuthUseCase
import java.util.*

/**
* Implementation of the authentication controller API.
*/
@RestController
@RequestMapping("/api/v1/auth")
class AuthController(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,28 @@ import org.yapp.apis.auth.dto.response.UserProfileResponse
import org.yapp.globalutils.exception.ErrorResponse
import java.util.*

@Tag(name = "Authentication", description = "Authentication API")
@Tag(name = "Authentication", description = "인증 관련 API")
interface AuthControllerApi {

@Operation(
summary = "Sign in or sign up with social login",
description = "Sign in a user with social login credentials (Kakao or Apple). If the user doesn't exist, they will be automatically registered."
summary = "소셜 로그인",
description = "카카오 또는 애플 계정으로 로그인합니다. 사용자가 존재하지 않으면 자동으로 회원가입됩니다."
)
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "Successful sign in or sign up",
description = "로그인/회원가입 성공",
content = [Content(schema = Schema(implementation = AuthResponse::class))]
),
ApiResponse(
responseCode = "400",
description = "Invalid request or credentials",
description = "잘못된 요청 또는 인증 정보",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
),
ApiResponse(
responseCode = "409",
description = "Email already in use with a different account",
description = "이미 다른 계정으로 사용 중인 이메일",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
)
]
Expand All @@ -51,74 +51,74 @@ interface AuthControllerApi {
fun signIn(@RequestBody @Valid request: SocialLoginRequest): ResponseEntity<AuthResponse>

@Operation(
summary = "Refresh token",
description = "Refresh an access token using a refresh token. Returns both a new access token and a new refresh token."
summary = "토큰 갱신",
description = "리프레시 토큰을 사용하여 액세스 토큰을 갱신합니다. 새로운 액세스 토큰과 리프레시 토큰을 반환합니다."
)
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "Successful token refresh",
description = "토큰 갱신 성공",
content = [Content(schema = Schema(implementation = AuthResponse::class))]
),
ApiResponse(
responseCode = "400",
description = "Invalid refresh token",
description = "유효하지 않은 리프레시 토큰",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
),
ApiResponse(
responseCode = "404",
description = "Refresh token not found",
description = "리프레시 토큰을 찾을 수 없음",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
)
]
)
@PostMapping("/refresh")
fun refreshToken(@RequestBody @Valid request: TokenRefreshRequest): ResponseEntity<AuthResponse>

@Operation(summary = "Sign out", description = "Sign out a user by invalidating their refresh token")
@Operation(summary = "로그아웃", description = "리프레시 토큰을 무효화하여 사용자를 로그아웃합니다")
@ApiResponses(
value = [
ApiResponse(responseCode = "204", description = "Successful sign out"),
ApiResponse(responseCode = "204", description = "로그아웃 성공"),
ApiResponse(
responseCode = "400",
description = "Invalid user ID",
description = "유효하지 않은 사용자 ID",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
)
]
)
@PostMapping("/signout")
fun signOut(@AuthenticationPrincipal userId: UUID): ResponseEntity<Unit>

@Operation(summary = "Get user profile", description = "Retrieves profile information for the given user ID.")
@Operation(summary = "사용자 프로필 조회", description = "현재 로그인한 사용자의 프로필 정보를 조회합니다.")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "User profile retrieved successfully",
description = "사용자 프로필 조회 성공",
content = [Content(schema = Schema(implementation = UserProfileResponse::class))]
),
ApiResponse(
responseCode = "404",
description = "User not found",
description = "사용자를 찾을 수 없음",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
)
]
)
@GetMapping("/me")
fun getUserProfile(@AuthenticationPrincipal userId: UUID): ResponseEntity<UserProfileResponse>

@Operation(summary = "Update terms agreement", description = "Updates the user's terms agreement status")
@Operation(summary = "약관 동의 상태 수정", description = "사용자의 약관 동의 상태를 업데이트합니다")
@ApiResponses(
value = [
ApiResponse(
responseCode = "200",
description = "Terms agreement status updated successfully",
description = "약관 동의 상태 업데이트 성공",
content = [Content(schema = Schema(implementation = UserProfileResponse::class))]
),
ApiResponse(
responseCode = "404",
description = "User not found",
description = "사용자를 찾을 수 없음",
content = [Content(schema = Schema(implementation = ErrorResponse::class))]
)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
import org.yapp.apis.auth.dto.response.UserCreateInfoResponse
import org.yapp.apis.util.NicknameGenerator
import org.yapp.apis.auth.util.NicknameGenerator
import org.yapp.domain.user.ProviderType

@Schema(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.yapp.apis.auth.dto.request

import io.swagger.v3.oas.annotations.media.Schema
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.NotNull
import org.yapp.apis.auth.dto.response.CreateUserResponse
import org.yapp.apis.auth.strategy.AppleAuthCredentials
import java.util.UUID

@Schema(
name = "SaveAppleRefreshTokenRequest",
description = "Request DTO for saving Apple refresh token with user ID and authorization code"
)
data class SaveAppleRefreshTokenRequest private constructor(
@Schema(
description = "Unique identifier of the user",
example = "a1b2c3d4-e5f6-7890-1234-56789abcdef0"
)
@field:NotNull(message = "userId must not be null")
val userId: UUID? = null,

@Schema(
description = "Authorization code from Apple OAuth process",
example = "cdef1234-abcd-5678-efgh-9012ijklmnop"
)
@field:NotBlank(message = "authorizationCode must not be blank")
val authorizationCode: String? = null,

@Schema(
description = "Apple refresh token, nullable if not issued yet",
example = "apple-refresh-token-example"
)
val appleRefreshToken: String? = null
) {
fun validUserId(): UUID = userId!!
fun validAuthorizationCode(): String = authorizationCode!!

companion object {
fun of(
userResponse: CreateUserResponse,
credentials: AppleAuthCredentials
): SaveAppleRefreshTokenRequest {
return SaveAppleRefreshTokenRequest(
userId = userResponse.id,
authorizationCode = credentials.authorizationCode,
appleRefreshToken = userResponse.appleRefreshToken
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ data class SocialLoginRequest private constructor(
required = true
)
@field:NotBlank(message = "OAuth token is required")
val oauthToken: String? = null
val oauthToken: String? = null,

@Schema(
description = "Authorization code used to issue Apple access/refresh tokens (required only for Apple login)",
example = "c322a426...",
required = false
)
val authorizationCode: String? = null
) {
fun validProviderType(): String = providerType!!
fun validOauthToken(): String = oauthToken!!
Expand All @@ -46,7 +53,11 @@ data class SocialLoginRequest private constructor(

return when (provider) {
ProviderType.KAKAO -> KakaoAuthCredentials(request.validOauthToken())
ProviderType.APPLE -> AppleAuthCredentials(request.validOauthToken())
ProviderType.APPLE -> {
val authCode = request.authorizationCode
?: throw AuthException(AuthErrorCode.INVALID_REQUEST, "Apple login requires an authorization code.")
AppleAuthCredentials(request.validOauthToken(), authCode)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import jakarta.validation.constraints.NotNull
@Schema(description = "Request to update terms agreement status")
data class TermsAgreementRequest private constructor(
@Schema(description = "Whether the user agrees to the terms of service", example = "true", required = true)
@field:NotNull(message = "termsAgreed must not be null")
val termsAgreed: Boolean? = null


) {
fun validTermsAgreed(): Boolean = termsAgreed!!
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.yapp.apis.auth.dto.response

import io.swagger.v3.oas.annotations.media.Schema
import org.yapp.domain.user.vo.UserIdentityVO
import org.yapp.domain.user.vo.UserAuthVO
import org.yapp.globalutils.auth.Role
import java.util.UUID
import java.util.*

@Schema(
name = "CreateUserResponse",
Expand All @@ -20,13 +20,20 @@ data class CreateUserResponse private constructor(
description = "사용자 역할",
example = "USER"
)
val role: Role
val role: Role,

@Schema(
description = "Apple Refresh Token (Apple 유저인 경우에만 존재)",
nullable = true
)
val appleRefreshToken: String?
) {
companion object {
fun from(identity: UserIdentityVO): CreateUserResponse {
fun from(auth: UserAuthVO): CreateUserResponse {
return CreateUserResponse(
id = identity.id.value,
role = identity.role
id = auth.id.value,
role = auth.role,
appleRefreshToken = auth.appleRefreshToken
)
}
}
Expand Down
48 changes: 33 additions & 15 deletions apis/src/main/kotlin/org/yapp/apis/auth/exception/AuthErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,51 @@ package org.yapp.apis.auth.exception
import org.springframework.http.HttpStatus
import org.yapp.globalutils.exception.BaseErrorCode

/**
* Error codes for authentication-related errors.
*/
enum class AuthErrorCode(
private val httpStatus: HttpStatus,
private val code: String,
private val message: String
) : BaseErrorCode {

/* 400 BAD_REQUEST */
UNSUPPORTED_PROVIDER_TYPE(HttpStatus.BAD_REQUEST, "AUTH_005", "Unsupported provider type."),
INVALID_CREDENTIALS(HttpStatus.BAD_REQUEST, "AUTH_006", "Invalid credentials."),
EMAIL_NOT_FOUND(HttpStatus.BAD_REQUEST, "AUTH_007", "Email not found."),
INVALID_ID_TOKEN_FORMAT(HttpStatus.BAD_REQUEST, "AUTH_008", "Invalid ID token format."),
SUBJECT_NOT_FOUND(HttpStatus.BAD_REQUEST, "AUTH_009", "Subject not found in ID token."),
FAILED_TO_PARSE_ID_TOKEN(HttpStatus.BAD_REQUEST, "AUTH_010", "Failed to parse ID token."),
FAILED_TO_GET_USER_INFO(HttpStatus.BAD_REQUEST, "AUTH_011", "Failed to get user info from provider."),
USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "AUTH_012", "User not found."),
UNSUPPORTED_PROVIDER_TYPE(HttpStatus.BAD_REQUEST, "AUTH_400_01", "지원되지 않는 공급자 타입입니다."),
INVALID_CREDENTIALS(HttpStatus.BAD_REQUEST, "AUTH_400_02", "잘못된 인증 정보입니다."),
INVALID_REQUEST(HttpStatus.BAD_REQUEST, "AUTH_400_03", "잘못된 요청입니다."),
INVALID_ID_TOKEN_FORMAT(HttpStatus.BAD_REQUEST, "AUTH_400_04", "잘못된 ID 토큰 형식입니다."),
SUBJECT_NOT_FOUND(HttpStatus.BAD_REQUEST, "AUTH_400_05", "ID 토큰에서 주체를 찾을 수 없습니다."),
FAILED_TO_PARSE_ID_TOKEN(HttpStatus.BAD_REQUEST, "AUTH_400_06", "ID 토큰 파싱에 실패했습니다."),
FAILED_TO_GET_USER_INFO(HttpStatus.BAD_REQUEST, "AUTH_400_07", "공급자로부터 사용자 정보를 가져오는데 실패했습니다."),
USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "AUTH_400_08", "사용자를 찾을 수 없습니다."),
EMAIL_NOT_FOUND(HttpStatus.BAD_REQUEST, "AUTH_400_09", "이메일을 찾을 수 없습니다."),
INVALID_APPLE_ID_TOKEN(HttpStatus.BAD_REQUEST, "AUTH_400_10", "유효하지 않은 Apple ID 토큰입니다."),

/* 401 UNAUTHORIZED */
INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_002", "Invalid refresh token."),
REFRESH_TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "AUTH_003", "Refresh token not found."),
INVALID_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_004", "Invalid access token."),
INVALID_OAUTH_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_401_01", "잘못된 소셜 OAuth 토큰입니다."),
INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_401_02", "잘못된 리프레시 토큰입니다."),
REFRESH_TOKEN_NOT_FOUND(HttpStatus.UNAUTHORIZED, "AUTH_401_03", "리프레시 토큰을 찾을 수 없습니다."),
INVALID_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED, "AUTH_401_04", "잘못된 액세스 토큰입니다."),

/* 403 FORBIDDEN */
INSUFFICIENT_PERMISSIONS(HttpStatus.FORBIDDEN, "AUTH_403_01", "요청된 리소스에 대한 권한이 부족합니다."),

/* 409 CONFLICT */
EMAIL_ALREADY_IN_USE(HttpStatus.CONFLICT, "AUTH_001", "Email already in use with a different account.");
EMAIL_ALREADY_IN_USE(HttpStatus.CONFLICT, "AUTH_409_01", "이미 다른 계정에서 사용 중인 이메일입니다."),

/* 500 INTERNAL_SERVER_ERROR */
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH_500_01", "내부 서버 오류입니다."),
FAILED_TO_LOAD_PRIVATE_KEY(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH_500_02", "Apple 개인키 로드에 실패했습니다."),
INVALID_PRIVATE_KEY_FORMAT(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH_500_03", "잘못된 개인키 형식입니다."),
FAILED_TO_COMMUNICATE_WITH_PROVIDER(
HttpStatus.INTERNAL_SERVER_ERROR,
"AUTH_500_04",
"외부 공급자와의 통신에 실패했습니다."
),
OAUTH_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH_500_05", "소셜 OAuth 서버 오류입니다."),
MISSING_APPLE_REFRESH_TOKEN(
HttpStatus.INTERNAL_SERVER_ERROR,
"AUTH_500_06",
"Apple에서 초기 로그인 시 리프레시 토큰을 제공하지 않았습니다."
);

override fun getHttpStatus(): HttpStatus = httpStatus
override fun getCode(): String = code
Expand Down
Loading