OAuth는 다른 앱이 사용자의 비밀번호를 몰라도, 사용자의 정보를 안전하게 가져올 수 있도록 만든 권한 위임(authorization delegation) 방식이에요.
OAuth를 이해하기 위해 먼저 핵심 용어들을 정리해보겠습니다:
(Before OAuth):
(After OAuth):
OAuth를 사용하면, 사용자 인증(Authentication) 과정은 OAuth 제공자(GitHub, Google 등)가 담당하게 됩니다.
이로 인해 클라이언트 애플리케이션(Client Application)은 사용자의 인증 자격 증명(Credentials, 예: ID/Password)을 직접 수집하거나 저장할 필요가 없습니다.
✅ 보안 효과:
OAuth 요청 시, 클라이언트는 권한 범위(Scope)를 명시하여 사용자의 자원(Resource)에 대해 세분화된 접근 제어를 요청합니다.
예시:
✅ 보안 효과:
OAuth 인증 후, 서버는 Access Token을 발급합니다.
이 토큰은 다음 특성을 가집니다:
✅ 보안 효과:
요약하면, OAuth를 도입함으로써 클라이언트 애플리케이션은 사용자 비밀번호를 직접 다루지 않고, 제한된 범위 내에서 단기 유효한 액세스 토큰을 통해 신뢰성 있는 인증 및 권한 위임 절차를 수행할 수 있습니다.
클라이언트 앱이 GitHub에게 "로그인 화면을 띄워줘"라고 요청합니다.
이때 다음 정보를 포함시켜야 합니다:
let authURL = "https://github.com/login/oauth/authorize?client_id=abc123&scope=read:user&redirect_uri=letsgitit://callback"
UIApplication.shared.open(URL(string: authURL)!)
→ 이제 사용자는 GitHub 로그인 화면을 보고 로그인합니다.
받은 code를 가지고 GitHub에게 토큰 발급을 요청합니다:
✅ 예: OAuth 인증 앱 연동 flow
이 과정에서 서버는 다음을 확인합니다:
✅ 즉, code가 탈취당해도 쓸모 없습니다 (비밀키, client_secret, state 모두 없으면 무용지물)
바로 그 "code → Access Token" 교환 과정이 OAuth 보안의 핵심입니다.
우리 앱이 code와 함께 돌아오고 그 code와 함께 앱에서:
POST https://github.com/login/oauth/access_token
Content-Type: application/json
{
"client_id": "내 앱의 ID",
"client_secret": "내 앱의 비밀키",
"code": "xyz123",
"redirect_uri": "myapp://callback"
}
이렇게 client app의 정보를 포함한 내용을 인증서버에서 검증합니다.
검증 항목
항목 | 검증 내용 |
code 유효성 | 아직 만료되지 않았는지, 이미 사용된 건 아닌지 |
client_id 일치 여부 | 이 code가 어떤 앱(client)에게 발급된 건지 확인 |
client_secret | 이 요청이 정말 등록된 앱이 맞는지 확인 |
redirect_uri | OAuth 요청 시 등록한 주소와 일치하는지 검증 |
state (옵션이지만 강력 추천) | 요청 시 보낸 값과 응답 시 받은 값이 일치하는지로 위조 공격 방지 (CSRF) |
모든 항목이 일치한다면 Access Token을 발급합니다:
{
"access_token": "gho_abcd1234567890",
"token_type": "Bearer",
"scope": "read:user"
}
이제 이 Access Token으로 진짜 API 호출이 진행됩니다.
그래서 code는 단지 "1회용 교환권"일 뿐, 진짜 자격증(Access Token)은 서버가 발급합니다.
OAuth 인증이란 결국 "Access Token을 안전하게 받아내는 절차"이고, 그 Token을 가지고만 API에 접근할 수 있는 구조입니다.
Redirect URI는 OAuth 인증이 끝난 후 사용자를 되돌려보낼 주소입니다.
악성 앱이 code를 자기 URI로 받아가게 설정한다면?
그래서 OAuth 앱 등록 시 redirect_uri를 미리 고정 등록해 두고, 실제 요청 시 받은 값과 완전 일치해야만 토큰 발급을 허용합니다.
쉽게 비유하면, 티켓을 받기 위해 줄을 서는데, 티켓이 발급되면 어디로 배달할지 주소를 적어야 하잖아요? 그 주소가 redirect_uri입니다.
앱에서 자동 로그인을 구현하려면:
👉 토큰 저장 = 로그인 상태 유지
UserDefaults는 보안이 취약한 이유로 Keychain을 사용합니다
간단한 비유:
사용자 입장에서는 Keychain이나 UserDefaults나 차이를 거의 느끼지 못하지만, 다만 내부 동작 구조와 보안 레벨은 완전히 다릅니다.
1. 사용자: "로그인" 버튼 클릭
2. 앱: Safari로 GitHub 로그인 페이지 열기
3. 사용자: GitHub에서 ID/PW 입력
4. GitHub: "LetsGitIt 앱이 접근해도 될까요?"
5. 사용자: "허용" 클릭
6. GitHub: 앱으로 돌아가기 (코드와 함께)
7. 앱: 받은 코드로 진짜 토큰 요청
8. GitHub: 토큰 발급
9. 앱: 토큰 저장하고 메인 화면으로
1. 프로필 화면 열림
2. 앱: "저장된 토큰으로 사용자 정보 주세요"
3. GitHub: JSON 데이터 응답
4. 앱: JSON → Swift 객체 변환
5. 앱: UI에 데이터 표시 (이름, 아바타 등)
사실 되게 간단하게 구현되어 있을것이라고 생각했습니다.
사실 이런부분은 실제 사용하면서 보였던 부분이라 좀더 재미있게 다가왔습니다.
평소에 아무생각없이 쓰던 소셜 로그인이나 인증 처리를 할때 이런처리가 있었구나 라는 느낌이 신선했습니다.
실제론 제가 정리 한것보다 더 디테일한 부분이 있을거라고는 생각합니다.
그래도 이런 과정이 있었다는것이 스스로 사고를 할수있는 힘을 길러주는것은 아닐까 싶습니다.
[Swift] URL Scheme: iOS 앱 간 연결의 핵심 기술 (0) | 2025.05.29 |
---|---|
[Swift] Data Race (0) | 2025.05.27 |
[Swift] CoreML (3) | 2024.12.25 |