안녕하세요, まさきん입니다.
스마트폰을 iPhone에서 Android로 바꿨습니다. 그 김에 건강 데이터가 지나가는 길을 하나로 모으고 있어요. 그런데 수면만은 매일 아침 알림에 “기록 출처 없음”인 채였습니다. 원인은 OAuth 스코프와 동의 다시 받기였기에, 공식 정보와 함께 남겨 둡니다.
※ 글 공개 시점의 정보입니다. 최신 조건은 공식 사이트에서 확인해 주세요.
- Google Health API의 수면은 걸음 수와는 다른 스코프
sleep.readonly로 읽습니다 - 스코프를 나중에 추가해도 가지고 있는 토큰의 권한은 늘어나지 않습니다. 동의를 다시 받아야 합니다
- 인가 URL에
include_granted_scopes=true를 붙이면 이전에 허용한 스코프도 한꺼번에 이어받을 수 있습니다 - 고쳐졌는지는 운영 데이터에 쓰지 않는 드라이런으로 먼저 확인할 수 있습니다
- 권한을 추가하기 전의 약 1주일 치는, 제 경우 거슬러 올라가 채워지지 않았습니다
일어나고 있던 증상
제 건강 데이터는 지금 이런 경로로 흐르고 있습니다. 활동량계에서 Google의 건강 앱(Google Health)으로. 거기서 API를 거쳐 직접 만든 기록(건강 로그)으로. 이 한 줄기입니다.
걸음 수 등은 먼저 가져올 수 있었습니다. 그런데 수면 칸만 채워지지 않았어요. 매일 아침 도착하는 알림에는 수면 부분에 “기록 출처 없음”이라고 나와 있었습니다.
원인은 나중에 추가한 스코프
원인은 단순했습니다. 수면용 권한을 나중에 추가했던 거예요.
처음 동의했을 때 요청한 것은 걸음 수 등의 스코프였습니다. 그 뒤에 코드 쪽에 수면 스코프를 덧붙여 썼습니다. 다만 동의는 다시 받지 않았습니다.
Google Health API의 공식 문서에는 이렇게 적혀 있습니다. 발급되는 액세스 토큰에 포함되는 것은 동의한 사용자가 허용한 스코프뿐. 즉 코드에 덧붙여 쓴 것만으로는 아무것도 바뀌지 않는 것입니다.
Google Health API라는 이름
Google Health API는 공식적으로 “Fitbit Web API의 차세대 버전”이라고 설명되어 있습니다. Fitbit이나 Pixel Watch 등의 데이터를 Google의 OAuth 2.0 위에서 다루는 구조입니다.
기존의 Fitbit Web API에는 종료 일정이 나와 있습니다. 지원 종료가 2026년 9월 30일. API 자체의 중단이 2026년 10월 30일입니다. 데이터를 계속 가져오려면 Google Health API로 이전하라고 안내되어 있습니다.
다만 같은 안내에는 주의 문구도 있습니다. 현시점에서는 새 프로젝트를 받지 않고 있다는 취지입니다. 이제부터 시작하는 경우에는 공식의 최신 안내를 먼저 봐 두면 안심일지도 모릅니다.
증상과 원인 구분하기
“수면만 가져올 수 없을” 때 생각할 수 있는 원인을 표로 정리해 둡니다.
| 증상 | 생각할 수 있는 원인 | 확인할 곳 |
|---|---|---|
| 수면만 비어 있다 | 수면 스코프에 동의하지 않았다 | 토큰에 포함된 스코프 |
| 모든 항목을 갑자기 가져올 수 없다 | 토큰 만료(401) | 게시 상태와 만료 조건 |
| 동의는 됐는데 호출에서 실패한다 | 계정이 Google Health에 연결되지 않았다 | Google Health 앱의 설정 |
| 특정 날짜만 비어 있다 | 그날의 기록이 Google 쪽에 없다 | Google Health 앱의 표시 |
제 경우는 맨 윗줄이었습니다. 걸음 수는 가져올 수 있었으니 토큰 자체는 살아 있었던 셈입니다.
전부 멈추는 쪽의 이야기는 다른 글에 정리해 두었습니다.
Google 리프레시 토큰이 7일 만에 끊기는 원인은 “테스트 중”. 프로덕션 환경으로 게시하는 절차
게시 상태가 원인인 경우에는 그쪽이 더 가까울 거라고 생각합니다.
수면 데이터의 스코프와 데이터 유형
Google Health API의 스코프는 모두 같은 문자열로 시작합니다. https://www.googleapis.com/auth/googlehealth 입니다. 이 뒤에 데이터 묶음별 이름이 붙습니다.
공식 스코프 목록과 데이터 유형 페이지에서 이번에 관련된 것을 뽑아냈습니다.
| 스코프(끝부분) | 공식 설명 | 읽을 수 있는 데이터의 예 |
|---|---|---|
.activity_and_fitness.readonly | 활동과 피트니스 데이터를 본다 | 걸음 수 등의 활동 데이터 |
.sleep.readonly | 수면 데이터를 본다 | 수면 세션과 수면 단계 |
.health_metrics_and_measurements.readonly | 건강 지표와 측정 데이터를 본다 | 수면 중의 심박 변이도나 호흡수 등 |
수면의 데이터 유형은 sleep 이고, 기록의 단위는 세션입니다. 한 번의 수면 안에 단계별 구간이 늘어섭니다. 단계는 LIGHT / DEEP / REM / AWAKE 4종류입니다.
제가 건강 로그에 넣고 있는 것은 수면 시간과 깊은 수면, 렘수면입니다. 모두 .sleep.readonly 범위에서 읽을 수 있는 데이터였습니다.
반면 수면 중의 심박 변이도와 혈중 산소는 다릅니다. 이쪽은 건강 지표 스코프에 들어 있어요. “수면”이라는 말로 한데 묶으면 여기를 혼동할지도 모릅니다.
공식 문서는 필요한 스코프만 요청하도록 안내하고 있습니다. 쓰기 스코프는 데이터를 보낼 때만 설정하는 형태입니다. 읽기만 하는 용도라면 readonly 로 충분해 보입니다.
스코프를 추가할 때의 OAuth 사양
가지고 있는 리프레시 토큰을 갱신해도 권한은 늘어나지 않습니다. 갱신으로 얻을 수 있는 것은 이미 허용된 범위의 액세스 토큰입니다.
새 스코프를 쓰는 길은 하나입니다. 그 스코프를 포함한 인가 요청을 다시 보낸다. 사용자가 동의 화면에서 허용한다. 그제야 새 권한이 붙습니다.
증분 인가와 include_granted_scopes
스코프를 나중에 추가하는 방식에는 공식 명칭이 있습니다. 증분 인가(incremental authorization)입니다. 필요해진 시점에 추가 스코프를 요청한다는 사고방식이죠.
이때 쓰는 것이 include_granted_scopes 라는 파라미터입니다. 값을 true 로 하고 동의가 통과되면 새 액세스 토큰은 이전 스코프도 포함합니다. 공식 문서에서는 모범 사례로 권장되고 있습니다.
공식 문서에는 합쳐진 인가의 규칙도 적혀 있습니다. 그 리프레시 토큰을 쓰면 전체 스코프분의 액세스 토큰을 얻을 수 있습니다. 한편 취소하면 포함된 스코프가 동시에 모두 빠집니다.
즉 수면만 추가할 때도 걸음 수 권한을 잃지 않고 끝낼 수 있는 것입니다.
리프레시 토큰 다루기
자동으로 돌리는 도구라면 리프레시 토큰이 필요합니다. 인가 URL의 access_type 을 offline 으로 하는 것이 그것을 위한 지정입니다.
공식 문서에는 또 하나 중요한 기재가 있습니다. 리프레시 토큰이 반환되는 것은 처음에 인가 코드를 교환했을 때뿐입니다. 두 번째 이후의 동의에서는 반환되지 않을 수 있습니다.
확실히 새것을 받고 싶을 때는 prompt=consent 를 붙입니다. 동의 화면을 매번 띄우는 지정입니다. 동의를 다시 받는 상황에서는 붙여 두는 편이 덜 헷갈릴지도 모릅니다.
동의를 다시 받는 절차
일반적인 흐름을 번호로 정리합니다. 웹 서버용 OAuth 2.0의 공식 절차에 따른 형태입니다.
- Google Cloud 콘솔에서 목적한 프로젝트를 열고 있는지 확인한다
- 도구 쪽의 스코프 목록에
.sleep.readonly를 덧붙여 쓴다 - 인가 URL을 조립한다.
scope에 필요한 스코프를 나열한다 - 같은 URL에
access_type=offline과include_granted_scopes=true를 붙인다 - 리프레시 토큰을 다시 받으려면
prompt=consent도 붙인다 - 본인이 브라우저에서 그 URL을 열고, 동의 화면에서 내용을 읽고 허용한다
- 돌아온 인가 코드를 토큰으로 교환한다
- 응답의
scope에 수면 스코프가 들어 있는지 확인한다 - 새 리프레시 토큰을 저장하고, 오래된 것은 쓰지 않도록 한다
8번은 눈에 띄지 않지만 중요한 단계입니다. 동의 화면에서는 사용자가 스코프별로 허용 여부를 고를 수 있습니다.
AI에게 맡긴 작업과 직접 한 조작
이번 사전 준비는 AI(Claude)에게 Mac에서 해 달라고 했습니다. 스코프를 추가한 인가 URL 준비 등입니다. 제가 한 것은 동의 화면을 열고 허용을 누르는 부분이었습니다.
| 작업 | 담당 | 이유 |
|---|---|---|
| 스코프를 추가한 인가 URL 준비 | AI(Claude) | 문자열 조립이라 틀리기 쉽다 |
| 동의 화면을 열고 허용을 누른다 | 저 | 본인의 의사 표시 그 자체이기 때문 |
| 다음 날 아침 알림을 본다 | 저 | 마지막은 내 눈으로 확인하고 싶다 |
동의는 데이터의 주인이 “넘겨도 좋다”고 나타내는 조작입니다. 그래서 허용을 누르는 부분만은 직접 하는 형태로 하고 있습니다.
매일 아침 알림의 구조는 다른 글에 썼습니다.
아침에 준비하는 동안 AI에게 한 장짜리 “오늘의 브리핑”을 만들게 하고 있는 이야기
스마트폰을 바꾸면 이런 연동을 하나씩 다시 살펴보게 되네요. 같은 타이밍에 매달 통신비도 점검해 보시면 어떨까요.
드라이런으로 확인한다
동의를 다시 받은 뒤 곧바로 운영 처리에 흘려보내지는 않았습니다. 먼저 드라이런입니다. 운영 기록에는 쓰지 않고 가져오기만 시험하는 실행이죠.
드라이런으로 수면 데이터가 돌아오는 것을 확인했습니다. 그런 다음 운영 처리를 통과시켰습니다. 건강 로그의 그날 행에 세 가지 값이 들어갔습니다. 수면 시간과 깊은 수면, 그리고 렘수면입니다. 여기까지 보고 완료로 했습니다.
드라이런이라면 실패해도 아무것도 더럽혀지지 않습니다. 빈 값으로 기존 행을 덮어쓰는 사고를 미리 막을 수 있어요.
확인 순서는 가져오기만 하는 시험 실행이 먼저, 실제 기록에 쓰는 것이 나중입니다. 이 순서를 뒤집지 않겠다는 것만 정해 두면, 동의를 다시 받은 직후에도 차분하게 진행할 수 있을 것 같습니다.
거슬러 올라갈 수 없었던 약 1주일
하나만, 돌아오지 않은 것이 있습니다. 권한을 추가하기 전의 약 1주일 치 수면입니다.
이 기간은 Google 쪽에도 기록이 없었습니다. 그래서 동의를 다시 받아도 채워지지 않습니다. 건강 로그의 그 행은 비워 둔 채로 두었습니다.
빈 행에 추측한 값을 넣는 일은 하지 않았습니다. 나중에 다시 봤을 때 진짜 기록과 구별이 되지 않게 되기 때문입니다. “없는 것은 없다”고 남기는 편이 로그로서는 정직하지 않을까 생각합니다.
권한이 통과되어도 원래 기록이 없으면 아무것도 돌아오지 않습니다. 원인을 구분할 때는 먼저 앱 쪽의 표시를 보는 것이 빠르다고 생각합니다.
스코프를 추가할 예정이라면 추가한 날짜를 메모해 두는 것도 좋을 것 같습니다. 나중에 비어 있는 기간을 봤을 때 이유를 바로 떠올릴 수 있습니다.
건강 데이터의 스코프는 다루는 무게가 다르다
건강 데이터는 민감한 정보입니다. Google 쪽에서도 무겁게 다루고 있습니다.
공식 문서에는 Google Health API 스코프의 대부분이 “제한됨”이라고 되어 있습니다. 일반에 공개하는 앱은 심사를 통과해야 합니다. 심사는 2단계로, OAuth 앱 확인과 제3자에 의한 보안 평가입니다.
심사를 통과하지 않은 앱은 사용자가 100명까지로 제한됩니다. 혼자서만 쓰는 도구라면 이 상한에 닿을 일은 거의 없어 보입니다. 다만 동의 전에 확인되지 않은 앱이라는 경고가 나오는 경우는 있습니다.
흔한 실수·함정
| 실수 | 일어나는 일 | 막는 방법 |
|---|---|---|
| 코드에 스코프를 추가하고 만족한다 | 토큰의 권한은 바뀌지 않는다 | 추가했다면 동의를 다시 받는다 |
| 리프레시 토큰이 반환되지 않는다 | 오래된 토큰을 계속 쓴다 | prompt=consent 를 붙여서 다시 받는다 |
| 곧바로 운영 환경에서 시험한다 | 빈 값으로 기록을 덮어쓴다 | 먼저 드라이런을 통과시킨다 |
| 빈 기간을 추측으로 채운다 | 진짜 기록과 구별할 수 없게 된다 | 비워 둔 채로 남긴다 |
알림에 “기록 출처 없음”이라고 나오도록 만들어 둔 것은 도움이 된 점이었습니다.
시작하기 전에 확인할 것
- 쓰고 있는 API가 Google Health API인지 기존의 Fitbit Web API인지
- 콘솔에서 열고 있는 것이 목적한 프로젝트인지
- 추가하려는 데이터가 어느 스코프에 들어 있는지
- 지금의 토큰에 어떤 스코프가 포함되어 있는지
- 게시 상태가 테스트 중인지 프로덕션 환경인지
- 인가 URL에 include_granted_scopes와 access_type을 붙였는지
- 동의 화면을 본인이 열 수 있는 시간을 낼 수 있는지
- 운영 데이터에 쓰지 않는 드라이런 수단이 있는지
게시 상태가 “테스트 중”인 채로 있으면 리프레시 토큰은 7일 만에 만료됩니다. 스코프를 추가해서 동의를 다시 받아도 이 기한은 별도로 적용됩니다. 먼저 게시 상태를 봐 두면 같은 일을 두 번 하는 수고를 피할 수 있을지도 모릅니다.
자주 묻는 질문
Q. 스코프를 추가하면 반드시 동의를 다시 받아야 하나요?
네, 필요합니다. 토큰에 포함되는 것은 사용자가 허용한 스코프뿐이기 때문입니다. 코드나 설정에 추가한 것만으로는 권한이 늘어나지 않습니다.
Q. 리프레시 토큰을 갱신하면 새 스코프도 붙나요?
붙지 않습니다. 갱신으로 얻을 수 있는 것은 이미 허용된 범위의 액세스 토큰입니다. 새 스코프는 동의 화면에서 허용해야 비로소 붙습니다.
Q. 수면 데이터는 어느 스코프로 읽을 수 있나요?
Google Health API에서는 .sleep.readonly 입니다. 수면 세션과 그 안의 단계를 읽을 수 있습니다. 수면 중의 심박 변이도 등은 건강 지표 스코프가 따로 필요합니다.
Q. 깊은 수면이나 렘수면은 가져올 수 있나요?
공식 데이터 유형에는 단계가 4종류 있습니다. LIGHT / DEEP / REM / AWAKE 입니다. 기종에 따라 지원 여부가 다르므로 공식의 지원 기종 표도 봐 두면 확실합니다.
Q. 동의하기 전 날짜의 수면은 거슬러 올라가 가져올 수 있나요?
원래 기록이 Google 쪽에 있느냐에 달려 있다고 생각합니다. 제 경우에는 약 1주일 치의 기록이 Google 쪽에도 없었습니다. 그래서 그 기간은 비어 있는 채입니다.
Q. 동의 조작까지 AI에게 맡겨도 되나요?
저는 맡기지 않습니다. 동의는 데이터 주인 본인의 의사 표시라고 생각하기 때문입니다. 인가 URL 준비 같은 사전 준비까지를 AI에게 부탁하는 형태로 하고 있습니다.
Q. Fitbit Web API 그대로도 쓸 수 있나요?
공식적으로는 2026년 10월 30일에 중단된다고 안내되어 있습니다. 데이터를 계속 가져오려면 Google Health API로 이전해야 합니다. 신규 프로젝트를 받는지 여부는 공식 안내에서 확인해 주세요.
참고한 공식 정보
- Google Health API(Google for Developers)
- Google Health API의 스코프(Google for Developers)
- Sleep and recovery 데이터 유형(Google for Developers)
- App verification(Google Health API)
- Troubleshooting(Google Health API)
- 웹 서버 애플리케이션에 OAuth 2.0 사용하기(Google for Developers)
- Google API 액세스에 OAuth 2.0 사용하기(Google for Developers)
정리
수면만 “기록 출처 없음”이 되는 원인은 나중에 추가한 스코프였습니다. 추가했다면 동의를 다시 받는다. 알고 나면 그뿐인 이야기입니다.
사전 준비는 AI에게 맡기고, 허용을 누르는 부분은 직접 했습니다. 드라이런으로 확인한 다음 운영 처리에 흘려보냈어요. 고쳐졌는지의 최종 확인은 다음 날 아침의 알림입니다. 이제부터 볼 참이네요.
스마트폰을 막 바꿨다면 연동해 둔 앱의 권한을 한 번만 훑어봐 주세요.
회선 갈아타기도 생각하고 있다면 MNP 갈아타기 절차를 정리한 글도 있습니다.
이 글에는 제휴 광고가 포함되어 있습니다. 이 사이트의 링크를 통해 상품·서비스에 신청하시면 제휴사로부터 보상을 받을 수 있습니다. 또한 운영자는 라쿠텐 그룹 소속 직원으로, 사원 추천 프로그램을 통해 보상을 받는 경우가 있습니다. 기사 내용과 평가는 광고 유무와 관계없이 운영자의 실제 경험과 조사를 바탕으로 작성했지만, 위 관계를 이해하신 후 읽어 주시기 바랍니다. 자세한 내용은 면책조항·제휴 링크 안내를 참고해 주세요. 면책조항·제휴 링크 안내
이 글에는 기계 번역이 포함되어 있습니다. 정확한 조건은 라쿠텐 모바일 공식 사이트의 다국어 페이지에서 확인해 주세요.
라쿠텐 모바일의 통신 지역·전파 상황이 궁금하신 분은, 공식 전파 개선·조사 요청 양식 을 통해 문의하실 수 있습니다.