[IMAD] 애플 로그인 Invalid_grant 에러

NCOOKIE·2024년 3월 18일
0

IMAD 프로젝트

목록 보기
11/11

배경

기존 iOS 네이티브 앱에서 애플 로그인을 웹뷰에서 구현했었는데, 이번에 공식 라이브러리를 사용해 다시 구현하기로 했다.

이를 위해 앱 측에서 애플 인가 서버로부터 발급받은 사용자 정보와 authorization code 등을 서버(스프링 API 서버)에 전달했다. 이를 받은 서버에서는 기존 방식과 마찬가지로 code를 사용해 토큰을 요청했지만 Invalid grant 에러가 발생했다.

애플 서버에 토큰 요청 시 Invalid grant 에러 발생

iOS 앱 측에서 발급받은 authorization code를 사용해 애플 서버의 /auth/token에서 토큰을 발급받으려고 했으나 계속 Invalid_grant 에러가 발생했다.

{
    "error": "invalid_grant",
    "error_description": "client_id mismatch. The code was not issued to com.example.bundle."
}

추측

공식 문서에 따르면 위 에러는 다음과 같은 이유로 발생할 수 있다고 한다.

  • authorization code를 사용해 토큰 발급을 요청할 경우
    • code를 발급받은 client_id가 일치하지 않는 경우
    • code가 만료되거나 이미 사용된 경우
  • refresh token을 사용해 토큰 발급을 요청할 경우
    • refresh token을 발급받은 client와 client_id가 일치하지 않는 경우
    • refresh token이 유효하지 않거나 만료된 경우

우리는 서비스에서 refresh token이 아니라 code를 사용해서 토큰을 발급받으려고 한다. 그리고 이 code는 실시간으로 앱에서 받아 요청했으므로 만료되거나 이미 사용한 경우도 아니었기 때문에 client_id와 문제가 있을 것으로 추측된다.

원인

결론부터 말하자면, 토큰 발급 시 App ID가 아닌 Service ID를 사용했기 때문에 발생한 문제였다.

client_id는 애플 개발자 계정에서 Certificates, Identifiers & Profiles - Identifiers에서 설정한 id이다. 그리고 우리는 App IDsService IDs 두 개를 설정했었다. 당시에는 그저 블로그에 나온 예제를 따라했었으나 여기가 문제였다.

Generate and validate tokens

https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens
Image

토큰을 발급받으려면 위와 같은 파라미터와 함께 요청하는데, 애플 로그인 기능 구현 시 client_id는 Service IDs에서 생성한 id로 설정했었다. 당시에는 App IDsService IDs의 차이에 대해 별 생각이 없기 때문에 그랬는데 이것이 문제였다.

Identifiers

Image

  • App IDs
    • 앱을 식별하는 고유한 식별자
    • Xcode에서 설정하는 Bundle Identifier와 연결되며, 배포 시 중요한 역할을 한다고 한다.
    • Sign in with Apple 구현 시 웹뷰 방식이 아닌 공식 라이브러리를 사용할 경우 자동으로 Xcode 등에서 설정한 이 ID를 사용하는 것으로 보인다.
    • 더 자세한 내용은 @QuaRang1225 에게 문의
  • Service IDs
    • 특정 서비스를 식별하는 식별자
    • 주로 앱에서 사용하는 특정 서비스들을 위한 식별자로 사용된다. 예를 들어, iCloud, In-App Purchase, Sign in with Apple 등의 서비스들은 각각의 Service ID를 필요로 한다.
    • 기존 모바일에서의 웹뷰 로그인 등에서 사용하고 있었다.

기존 방식처럼 모바일에서 웹뷰를 사용해 로그인을 할 때에는 서버 측에서 직접 code, id token 등을 발급받았기 때문에 문제가 없었다. 그러나 이번에 iOS 앱에서 직접 이를 발급받으면서, 앱에서 사용한 client_id와 서버에서 사용하는 client_id가 서로 달라 Invalid grant 에러가 발생한 것이었다.

해결

iOS 앱에서 요청을 했을 때에는 App ID를, 그 외의 서비스(Android, Web)에서 요청했을 때에는 Service IDclient_id로 사용하도록 구현했다.

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("grant_type", "authorization_code");
params.add("client_secret", createClientSecretKey());
params.add("code", code);
params.add("redirect_uri", appleProperties.getRedirectUrl());

// 애플 로그인 시 사용하는 clinet id는 app id(iOS 네이티브 앱 버전)와 service id(웹 서비스 버전)을 각각 사용함
if (isiOSApp) {
    params.add("client_id", appleProperties.getIOSClientId());
} else {
    params.add("client_id", appleProperties.getClientId());
}

마치며

사실 굉장히 간단한 문제였음에도, 문서나 글을 대충 읽고 넘어가 발생한 문제였다. 나는 iOS나 Mac OS 등의 사용 경험과 배경 지식이 거의 없다는 핑계를 댈 수도 있겠지만 회사였다면 의미 없는 행위였을 것이다... 앞으로는 이런 점들에 대해 주의 깊게 짚고 넘어가도록 하자

참고

profile
일단 해보자

0개의 댓글