구글 로그인은 몇번 해봤던 터라 어려움은없지만
애플 로그인은 처음이라 문서화 목적으로 작성한다.
우선, 애플 개발자 계정이 필요하다. Plaything에서 공용으로 사용하는 개발자 계정을 사용했다.
구글 로그인과는 흐름이 조금 다르다.
클라이언트에서 token을 받아오고, 애플서버에 퍼블릭 키를 요청한다음 토큰을 서명해야 한다.
우선 개발자 설정을 해줘야 하는데 참고를 보면서 하면 된다.
@PostMapping("/apple/login")
public ResponseEntity<LoginResponse> appleLogin(@RequestHeader("Transaction-id") String transactionId,
@RequestBody AppleLoginRequest request) throws JsonProcessingException, BadRequestException, NoSuchAlgorithmException, InvalidKeySpecException {
ApplePublicKeyResponse publicKeys = appleApiClient.getPublicKeys();
Map<String, String> headers = jwtProvider.parseHeaders(request.identityToken());
PublicKey publicKey = applePublicKeyGenerator.generatePublicKey(headers, publicKeys);
Claims claim = jwtProvider.getTokenClaims(request.identityToken(), publicKey);
authServiceV1.validateAppleLogin(claim);
LoginResult result = authServiceV1.login(OAuth2Provider.APPLE, claim.getId(), transactionId, request.fcmToken());
return ResponseEntity.ok()
.header("Authorization", "Bearer " + result.token())
.body(result.loginResponse());
}
전체 흐름은 위처럼 만들어주면 된다.
우선 애플에서 공개하는 퍼블릭키를 먼저 받아와야 한다.
@FeignClient(name = "appleApi", url = "https://appleid.apple.com")
public interface AppleApiClient {
@GetMapping("/auth/keys")
ApplePublicKeyResponse getPublicKeys();
}
이 API 요청을 보내면 사진처럼 Public key의 list가 반환된다.
여기서 내가 사용할 키를 Identity token의 kid와 alg를 통해서 찾고서 사용한다.
애플 공식문서를 보면, identity token을 검증해야 한다는 내용이 나온다.
이때, 서버의 퍼블릭키를 활용해서 토큰을 검증한다.
이외에도 iss필드가 'https://appleid.apple.com'인지, exipration time을 지나진 않았는지 등에 대한 검증이 필요하다.
이렇게 각각 검증을 해주었다.
이제 Identity token을 디코딩해주고, public key를 활용해 유저 정보를 담은 Claimes를 만들어주어야 한다.
public Map<String, String> parseHeaders(String token) throws JsonProcessingException {
// JWT의 첫 번째 부분(헤더)을 가져옴
String header = token.split("\\.")[0];
// Base64 디코딩 후 JSON을 Map으로 변환
return objectMapper.readValue(decodeHeader(header), Map.class);
}
public String decodeHeader(String token) {
return new String(Base64.getDecoder().decode(token), StandardCharsets.UTF_8);
}
이렇게 identity token을 디코딩해주고, Public key도 자바에서 사용할 수 있게 변경이 필요하다. 관련 내용은 여기를 참고하면 된다.
public Claims getTokenClaims(String token, PublicKey publicKey) {
return Jwts.parser()
.verifyWith(publicKey)
.build()
.parseSignedClaims(token)
.getPayload();
}
퍼블릭키와 identity token을 통해서 claimes를 만들고
여기서 유저 식별자 정보를 받아오면 된다.
JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
테스트용으로 identity token을 만들어서 애플이 제공한 Public key로 내용을 확인하려고 하니, 예외가 발생했다.
내가 만든 임의의 private key로 서명한 identity token을 애플의 public key로 검증하니 실패한 것으로 보인다.
(애플 서버의 private key를 사용한 게 아니니 당연한 일이다)