Add Google Health API authorization support#332
Conversation
yatharthranjan
left a comment
There was a problem hiding this comment.
Thanks @this-Aditya, looks nice. Has this been tested working? If so, can we release this soon (so at least we can authorise new participants on this, we can always pull the data later)
| clientId: <GOOGLE_CLIENT_ID> | ||
| clientSecret: <GOOGLE_CLIENT_SECRET> | ||
| scope: https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly https://www.googleapis.com/auth/googlehealth.sleep.readonly https://www.googleapis.com/auth/googlehealth.profile.readonly | ||
| oauthVersion: oauth2 |
There was a problem hiding this comment.
is this required config? should it not be oauth2 by default?
There was a problem hiding this comment.
Yeah, it is OAuth 2.0 by default. I only kept it here to highlight it.
There was a problem hiding this comment.
likely remove it if that is the default and does not require configuration
There was a problem hiding this comment.
Should I do it now, or after the Garmin migration? We might be able to remove this configuration completely then, since we'll only be left with oauth 2.0.
There was a problem hiding this comment.
yes i think for garmin, it should still be configurable if needed (especially for legacy deployments and until Garmin forces use of OAuth2.0)
| tokenEndpoint: https://oauth2.googleapis.com/token | ||
| clientId: <GOOGLE_CLIENT_ID> | ||
| clientSecret: <GOOGLE_CLIENT_SECRET> | ||
| scope: https://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonly https://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonly https://www.googleapis.com/auth/googlehealth.sleep.readonly https://www.googleapis.com/auth/googlehealth.profile.readonly |
There was a problem hiding this comment.
what about other scopes like - nutrition, irn, ecg, location (some studies have been explicitly requesting location records for activities recently so would be good to include if possible)?
There was a problem hiding this comment.
Yeah, we can add these, but google docs says that we can only request the scopes for which we are collecting data. So, if we want to increase the number of data points, we can add them
There was a problem hiding this comment.
yes shoudl at least add nutrition, irn and ecg
Yeah, I've tested it. If you'd like, you can also verify it on staging.
I think that even if we release it soon, we still need to pass google's verification process and CASA, which I think will take some time. One more thing -- when participants authorize google, the current flow deregisters them from fitbit. If we initially add this to the rest sources only, I think it would be nice if they could choose a start date later, and the historical data would then be covered by backfill. Otherwise, we'll only receive data from the start date onward through push notifications. |
I think for new deployments it would work up to 100 users without verification?
If the updated push endpoint is not deployed yet (only authorise in updated rest-source-auth), then when we are ready and do deploy push-endpoint, should it not backfill from the start date? |
| if (sourceTypeOauthMap[GARMIN_AUTH].equals("oauth2", ignoreCase = true)) { | ||
| // Bind Garmin service based on configured oauthVersion: "oauth2" → PKCE flow, "oauth1" → legacy flow. | ||
| val garminUsesPkce = restSourceClients.clients.firstOrNull { it.sourceType == GARMIN_AUTH }?.usesPkce == true | ||
| if (garminUsesPkce) { |
There was a problem hiding this comment.
I think more readable to just use oauthVersion from config here
There was a problem hiding this comment.
I've updated this in PR #333. As this PR derives usesPkce from the RestSourceClient, I think that's a better place to handle it than doing it here.
|
|
||
| bind(OAuth2RestSourceAuthorizationService::class.java) | ||
| .to(RestSourceAuthorizationService::class.java) | ||
| .named(FITBIT_AUTH) |
There was a problem hiding this comment.
should we somehow mark this as deprecated?
There was a problem hiding this comment.
It would be nice if we could do this after september 2026, as they will still receive data from the fitbit app until september if they signed up using their google account.
There was a problem hiding this comment.
I think ok to mark as deprecated (not decomissioned), with details on when it will be non-functional (sept 2026)
Sorry, I meant that the push endpoint is also deployed. But this version explicitly handles the inconsistencies between the documentation and the actual responses. Based on the real responses, we are only rejecting some data that contains partial information, otherwise, it is working perfectly fine on stage. |
|
I think for the new deployments we can live with the warning as it will be better than asking participants to authorise again. But i will confirm with the study team what they prefer. how long does CASA review take? |
Yeah, but we can only recruit 100 participants, and we are now aiming for one client ID (I assume), so it would be across all projects. Is it sufficient before we get verified?
It depends on which third-party assessor lab we pick, and also varies by tier (we need at least Tier 2, or maybe Tier 3). But I think it is going to take substantial time. Some mention it takes 1-3 weeks once testing starts (or 2-4 weeks for Tier 3). And as we request restricted scopes, it can take longer (Google says this). |
yatharthranjan
left a comment
There was a problem hiding this comment.
LGTM, please merge the base branch (outdated atm)


A new authorization service handles Google's oauth2 flow.
Because the same participant may already have a Fitbit account from before the Google Health migration, the identity payload also carries an optional legacy Fitbit user ID, so we can keep both linked to the same RestSourceUser without losing history.
PKCE is enabled for Google as an extra security layer on top of the standard oauth2 flow. If it turns out Google's auth servers don't play nicely with the PKCE flow in , I'll drop it and fall back to the plain oauth2 path.