sign with apple 사용 시 redirect URI로 localhost를 사용할 수 없다
따라서 ngrok을 사용한다
ngrok을 사용하여 로컬 서버를 공개적으로 접근할 수 있는 URL로 만들어 테스트할 수 있다.
로컬 개발 환경에서 HTTPS를 통해 접근할 수 있는 URL을 생성할 수 있음.
이후 명령어대로 실행
ngrok http http://localhost:5173 // vite는 5173 port에 있음

해당주소로 접근할 수 있음

이후 redirectURI에 추가

그리고 RedirectURI 가 localhost, vercel에 따라 달라지기 때문에 이렇게 관리
const REDIRECT_URI = window.location.protocol + '//' + window.location.host + '/callback/apple';
localhost에서 정상 작동한다..!
OAuth 성공 시 주는 값

Apple 서버에서 제공하는 단기 사용 인증 코드
백엔드 서버에서 Apple 서버로 교환하여 사용자 액세스 토큰이나 ID 토큰을 받을 때 사용
jwt으로 인코딩된 사용자 정보
이 토큰을 디코딩하면 사용자 ID, 이메일, 인증 시간 등 여러 정보를 확인할 수 있음
redirect URI로 /callback/apple 로 설정해주었다.
하지만, 지정된 URI로 이동하지 않고 현재페이지에서 authroization 받았음
이유: usePopup:true , 이 경우 수동으로 리디렉션을 설정해야한다
따라서 팝업설정을 false로 변경
usePopup:false // 앱에서 활용될 때 팝업이 잘 되지 않을수도 있음
무슨 이유인지 ngrok에서는 리디렉션을 제대로 해주어도 404에러가 발생하였다. (배포된 vercel에서는 리디렉션이 성공적으로 되었음.)

또한 vercel에서 리디렉션이 되어도 아무값도 받지 못한 상태였기 때문에 작업을 할 수 없는 상태였음.
해당문서 참고하여 진행
원인: responseMode:"form_post" 였기 때문
기본 모드가 from_post인데, 이것은 네이버나 카카오 로그인처럼 원래 페이지로 리다이렉션 되는 것이 아닌, 해당 redirect-uri 로 POST 요청이 날아갔던 것
실제로 log를 보면 post 요청을 보낸 것을 알 수 있음

responseMode: fragment 로 변경
apple 공식문서를 참고하여 코드 수정
export const appleLogin = async () => {
const RESPONSE_TYPE = 'code id_token'; // 요청하는 응답 타입
const RESPONSE_MODE = 'fragment';
const AUTH_URL =
`https://appleid.apple.com/auth/authorize?` +
`client_id=${encodeURIComponent(APPLE_CLIENT_ID)}` +
`&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
`&response_type=${encodeURIComponent(RESPONSE_TYPE)}` +
`&response_mode=${encodeURIComponent(RESPONSE_MODE)}` +
`&scope=${encodeURIComponent('')}` +
`&state=${encodeURIComponent('previewInsure')}` +
`&nonce=${encodeURIComponent('821')}`;
// 브라우저에서 Apple 로그인 페이지로 리디렉션
window.location.href = AUTH_URL;
};
잘 동작한다! ( 해결하는데 하루종일 걸렸......)

import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
function AppleLoginCallback() {
const navigate = useNavigate(); // 이후 callback에서 나올 때 사용
const [idToken, setIdToken] = useState(null);
const [code, setCode] = useState(null);
const [state, setState] = useState(null);
useEffect(() => {
const hash = window.location.hash.substring(1);
const queryParams: any = new URLSearchParams(hash);
setIdToken(queryParams.get('id_token'));
setCode(queryParams.get('code'));
setState(queryParams.get('state'));
}, []);
const handleSign = () => {
const data = {
id_token: idToken,
code: code,
state: state,
};
console.log(data);
};
useEffect(() => {
if (state && idToken && code) {
handleSign();
}
}, [state, idToken, code]);
return (
...
);
}
export default AppleLoginCallback;

서버에서 apple로 요청을 보낼 때 사용

키 파일 다운로드하기 (.p8)
