Skip to content

Commit 6a261aa

Browse files
authored
Merge pull request #333 from RADAR-base/derive-pkce
Make usesPkce a derived property on RestSourceClient
2 parents 5cde94b + ba4b1d3 commit 6a261aa

5 files changed

Lines changed: 30 additions & 24 deletions

File tree

authorizer-app-backend/authorizer.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@ restSourceClients:
2727
clientSecret: <CLIENT_SECRET>
2828
scope: activity heartrate sleep profile
2929
# Garmin OAuth2 PKCE configuration.
30-
# oauthVersion: "oauth2" selects the GarminOAuth2AuthorizationService;
31-
# "oauth1" selects the legacy GarminOAuth1AuthorizationService.
30+
# oauthVersion: OAUTH2 selects the GarminOAuth2AuthorizationService;
31+
# OAUTH1 selects the legacy GarminOAuth1AuthorizationService.
3232
- sourceType: Garmin
3333
authorizationEndpoint: https://connect.garmin.com/oauth2Confirm
3434
tokenEndpoint: https://diauth.garmin.com/di-oauth2-service/oauth/token
3535
deregistrationEndpoint: https://apis.garmin.com/wellness-api/rest/user/registration
3636
clientId: <GARMIN_CLIENT_ID>
3737
clientSecret: <GARMIN_CLIENT_SECRET>
38-
oauthVersion: oauth2
38+
oauthVersion: OAUTH2
3939
# Google Health API
4040
- sourceType: GoogleHealth
4141
authorizationEndpoint: https://accounts.google.com/o/oauth2/v2/auth
4242
tokenEndpoint: https://oauth2.googleapis.com/token
4343
clientId: <GOOGLE_CLIENT_ID>
4444
clientSecret: <GOOGLE_CLIENT_SECRET>
45-
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 https://www.googleapis.com/auth/googlehealth.nutrition.readonly https://www.googleapis.com/auth/googlehealth.irn.readonly https://www.googleapis.com/auth/googlehealth.ecg.readonly
46-
oauthVersion: oauth2
45+
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 https://www.googleapis.com/auth/googlehealth.irn.readonly https://www.googleapis.com/auth/googlehealth.ecg.readonly https://www.googleapis.com/auth/googlehealth.settings.readonly https://www.googleapis.com/auth/googlehealth.location.readonly
46+
oauthVersion: OAUTH2
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.radarbase.authorizer.config
2+
3+
/** OAuth protocol version configured for a [RestSourceClient]. */
4+
enum class OAuthVersion {
5+
OAUTH1,
6+
OAUTH2,
7+
}

authorizer-app-backend/src/main/java/org/radarbase/authorizer/config/RestSourceClient.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.radarbase.authorizer.config
22

3+
import org.radarbase.authorizer.service.DelegatedRestSourceAuthorizationService.Companion.GARMIN_AUTH
4+
import org.radarbase.authorizer.service.DelegatedRestSourceAuthorizationService.Companion.GOOGLE_AUTH
35
import org.radarbase.jersey.config.ConfigLoader.copyEnv
46
import java.util.Locale
57

@@ -14,9 +16,15 @@ data class RestSourceClient(
1416
val grantType: String? = null,
1517
val scope: String? = null,
1618
val state: String? = null,
17-
val usesPkce: Boolean = false,
18-
val oauthVersion: String = "oauth2",
19+
val oauthVersion: OAuthVersion = OAuthVersion.OAUTH2,
1920
) {
21+
val usesPkce: Boolean
22+
get() = when {
23+
sourceType == GARMIN_AUTH && oauthVersion == OAuthVersion.OAUTH2 -> true
24+
sourceType == GOOGLE_AUTH -> true
25+
else -> false
26+
}
27+
2028
fun withEnv(): RestSourceClient =
2129
this.copyEnv("${sourceType.uppercase(Locale.US)}_CLIENT_ID") { copy(clientId = it) }
2230
.copyEnv("${sourceType.uppercase(Locale.US)}_CLIENT_SECRET") { copy(clientSecret = it) }

authorizer-app-backend/src/main/java/org/radarbase/authorizer/enhancer/AuthorizerResourceEnhancer.kt

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import org.glassfish.jersey.internal.inject.AbstractBinder
2121
import org.radarbase.authorizer.api.RestSourceClientMapper
2222
import org.radarbase.authorizer.api.RestSourceUserMapper
2323
import org.radarbase.authorizer.config.AuthorizerConfig
24+
import org.radarbase.authorizer.config.OAuthVersion
2425
import org.radarbase.authorizer.config.RestSourceClients
2526
import org.radarbase.authorizer.doa.RegistrationRepository
2627
import org.radarbase.authorizer.doa.RestSourceUserRepository
@@ -48,21 +49,15 @@ class AuthorizerResourceEnhancer(
4849
private val restSourceClients = RestSourceClients(
4950
config.restSourceClients
5051
.map { it.withEnv() }
51-
.map {
52-
when {
53-
it.sourceType == GARMIN_AUTH && it.oauthVersion.equals("oauth2", ignoreCase = true) ->
54-
it.copy(usesPkce = true)
55-
it.sourceType == GOOGLE_AUTH ->
56-
it.copy(usesPkce = true)
57-
else -> it
58-
}
59-
}
6052
.onEach {
6153
requireNotNull(it.clientId) { "Client ID of ${it.sourceType} is missing" }
6254
requireNotNull(it.clientSecret) { "Client secret of ${it.sourceType} is missing" }
6355
},
6456
)
6557

58+
private val garminUsesOauth2 = restSourceClients.clients
59+
.firstOrNull { it.sourceType == GARMIN_AUTH }?.oauthVersion == OAuthVersion.OAUTH2
60+
6661
override val classes: Array<Class<*>>
6762
get() = listOfNotNull(
6863
Filters.cache,
@@ -114,9 +109,7 @@ class AuthorizerResourceEnhancer(
114109
bind(DelegatedRestSourceAuthorizationService::class.java)
115110
.to(RestSourceAuthorizationService::class.java)
116111

117-
// Bind Garmin service based on configured oauthVersion: "oauth2" → PKCE flow, "oauth1" → legacy flow.
118-
val garminUsesPkce = restSourceClients.clients.firstOrNull { it.sourceType == GARMIN_AUTH }?.usesPkce == true
119-
if (garminUsesPkce) {
112+
if (garminUsesOauth2) {
120113
bind(GarminOAuth2AuthorizationService::class.java)
121114
.to(RestSourceAuthorizationService::class.java)
122115
.named(GARMIN_AUTH)

docker/etc/rest-source-authorizer/authorizer.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,12 @@ restSourceClients:
3737
clientSecret: Oura-clinetsecret
3838
scope: daily session heartrate workout tag personal email spo2 ring_configuration
3939
# Garmin OAuth2 PKCE configuration.
40-
# oauthVersion: "oauth2" selects the GarminOAuth2AuthorizationService;
41-
# "oauth1" selects the legacy GarminOAuth1AuthorizationService.
42-
# usesPkce: must be true for Garmin OAuth2 (Garmin requires PKCE).
40+
# oauthVersion: OAUTH2 selects the GarminOAuth2AuthorizationService;
41+
# OAUTH1 selects the legacy GarminOAuth1AuthorizationService.
4342
- sourceType: Garmin
4443
authorizationEndpoint: https://connect.garmin.com/oauth2Confirm
4544
tokenEndpoint: https://diauth.garmin.com/di-oauth2-service/oauth/token
4645
deregistrationEndpoint: https://apis.garmin.com/wellness-api/rest/user/registration
4746
clientId: Garmin-clientid
4847
clientSecret: Garmin-clientsecret
49-
oauthVersion: oauth2
50-
usesPkce: true
48+
oauthVersion: OAUTH2

0 commit comments

Comments
 (0)