Android Credential Manager, 패스키·비밀번호·복원 데이터를 한 흐름으로 설계하는 법
AI를 활용하여 생성한 이미지입니다.
Android 앱에서 로그인 기능을 만들 때 패스키만 붙이면 끝난다고 생각하기 쉽지만, 실제 흐름에는 앱, 서버, 자격 증명 제공자가 모두 관여해요. Credential Manager는 패스키·비밀번호·Google 같은 연합 로그인·디지털 자격 증명을 한 API 흐름에서 다루도록 설계됐고, 제공자는 사용자의 자격 증명을 저장하고 제시하는 역할을 맡습니다.[1]
세 주체를 먼저 나누기
| 주체 | 담당하는 일 | 실패했을 때 볼 곳 |
|---|---|---|
| Android 앱 | 로그인 UI를 열고 Credential Manager를 호출 | 요청 옵션·예외·사용자 취소 처리 |
| 앱 서버 | challenge를 만들고 자격 증명 결과를 검증 | challenge 저장·만료·서명 검증 |
| Credential provider | 패스키나 비밀번호를 보관하고 선택지로 제공 | Google Password Manager 등 제공자 설정 |
앱이 로그인 성공 화면을 보여줬다고 해서 서버 검증이 끝난 것은 아니에요. 반대로 서버에서 공개 키를 정상적으로 확인해도 사용자가 제공자를 선택하거나 생체 인증을 취소하면 앱에는 실패 흐름이 돌아옵니다. 세 구간의 로그와 오류 처리를 분리해야 원인을 빠르게 찾을 수 있어요.[1]
패스키의 등록과 로그인을 구분하기
패스키를 등록할 때 앱은 서버가 준 옵션으로 Credential Manager에 공개·개인 키 쌍 생성을 요청합니다. 공개 키는 앱 서버에 저장하고 개인 키는 사용자의 기기 또는 자격 증명 제공자가 안전하게 보관하는 구조예요. 앱 서버가 개인 키를 받거나 저장하도록 설계하면 패스키의 핵심 모델에서 벗어납니다.[2]
로그인에서는 서버가 challenge를 만들고 앱에 전달합니다. 사용자가 패스키 사용을 승인하면 기기가 서명 결과를 만들고, 서버는 저장한 challenge와 공개 키로 검증합니다. challenge가 일치하고 서명이 공개 키로 확인될 때만 세션을 발급해야 합니다.[2]
- 서버에서 짧은 수명의 challenge를 생성합니다.
- 앱이 Credential Manager에 로그인 요청을 보냅니다.
- 사용자가 패스키·비밀번호·다른 제공자 중 하나를 선택합니다.
- 앱이 결과를 서버로 전달합니다.
- 서버가 challenge·origin·서명·사용자 계정을 검증한 뒤 세션을 만듭니다.
비밀번호와 패스키를 함께 제공할 때
Credential Manager는 여러 인증 방법을 한 흐름에서 지원하지만, 앱이 모든 선택지를 같은 우선순위로 보여줘야 한다는 뜻은 아니에요. 신규 사용자는 패스키를 먼저 제안하되, 기존 계정에는 비밀번호 로그인과 계정 복구 경로가 남아 있어야 합니다. 사용자가 제공자를 선택하지 않았거나 저장된 자격 증명이 없을 때도 빈 화면 대신 다음 행동을 안내하세요.[1]
비밀번호를 앱 서버가 직접 저장한다면 해시·비밀번호 재설정·로그인 시도 제한을 별도로 운영해야 해요. Credential Manager를 쓴다고 서버 인증 정책이 자동으로 안전해지는 것은 아닙니다. 패스키 사용자는 공개 키 검증으로, 비밀번호 사용자는 기존 비밀번호 검증으로 분리해 기록하세요.
복원과 기기 변경을 같은 것으로 보지 않기
Android 문서에는 자격 증명 제공자와 기기 간 복원을 연결하는 흐름이 안내돼요. 하지만 앱 데이터 복원, 패스키 복원, 사용자가 새 기기에서 다시 인증하는 과정은 서로 다른 상태입니다.[1] 새 기기에서 앱이 설치됐다는 이유만으로 로그인 세션을 자동 복구한다고 가정하지 말고, 서버에서 세션 만료·기기 등록·추가 인증 조건을 확인하세요.
| 상태 | 앱이 확인할 것 | 잘못된 가정 |
|---|---|---|
| 앱만 복원됨 | 서버 세션과 자격 증명 존재 여부 | 앱 데이터가 있으면 자동 로그인 |
| 패스키가 제공됨 | 서버의 공개 키와 계정 연결 | 기기 이름만 같으면 같은 사용자 |
| 제공자가 비어 있음 | 대체 로그인·복구 절차 | 항상 Google Password Manager가 있음 |
계정 연결과 복구를 따로 설계하기
패스키의 공개 키는 특정 사용자 계정과 연결되어야 해요. 같은 기기에서 여러 계정을 쓰는 경우에도 계정 식별자, 자격 증명 식별자, 등록 시각과 폐기 상태를 서버에서 관리해야 합니다. 사용자가 패스키를 잃어버렸다고 해서 서버의 공개 키를 지우는 것만으로 복구가 끝나는 것은 아니고, 기존 비밀번호·이메일 인증·관리자 확인처럼 별도의 복구 경로가 필요합니다.
사용자 취소와 제공자 오류도 실패로만 합치지 마세요. 생체 인증 화면을 닫은 사용자는 다시 시도할 수 있지만, challenge가 만료됐거나 이미 사용됐다면 새 요청을 만들어야 합니다. 앱 화면에는 같은 “로그인 실패”로 보여도 서버 로그에는 원인을 구분해 남겨야 재시도 루프와 계정 잠금을 잘못 작동시키지 않습니다.
검증 실패를 기록하는 항목
- 등록과 로그인 중 어느 흐름인지 기록하기
- 앱이 받은 예외와 사용자가 취소한 상황을 구분하기
- challenge 생성·만료·재사용 여부 확인하기
- 서버가 공개 키와 서명을 검증했는지 확인하기
- 제공자 없음·계정 없음·네트워크 실패를 각각 안내하기
클라이언트에서 제공자 목록이 예상과 다를 때는 앱의 Credential Manager 호출만 수정하지 말고 기기의 계정·제공자 설정, Android 버전, 설치된 비밀번호 관리자 상태를 함께 확인하세요. 제공자가 바뀌면 같은 계정에서 보여주는 선택지와 복원 결과도 달라질 수 있습니다. 이 상태를 테스트 케이스로 남겨야 특정 기기에서만 로그인 화면이 비는 문제를 재현할 수 있어요.
Credential Manager를 도입할 때 가장 먼저 정할 것은 화면이 아니라 경계예요. 앱은 요청과 결과를 전달하고, 서버는 challenge와 서명을 검증하며, 제공자는 자격 증명을 보관합니다. 이 역할을 섞지 않으면 패스키와 비밀번호를 함께 지원하면서도 복원·실패·계정 복구를 별도로 설계할 수 있어요.
[…] 안드로이드 자격 증명 관리자와 패스키 복원 설정도 계정 접근 권한을 점검할 때 참고할 수 있어요. […]