Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions authorizer-app-backend/authorizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ restSourceClients:
- sourceType: FitBit
authorizationEndpoint: https://www.fitbit.com/oauth2/authorize
tokenEndpoint: https://api.fitbit.com/oauth2/token
deregistrationEndpoint: https://api.fitbit.com/oauth2/revoke
clientId: <CLIENT_ID>
clientSecret: <CLIENT_SECRET>
scope: activity heartrate sleep profile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ data class RestOauth2AccessToken(
val tokenType: String? = null,
@SerialName("user_id")
val externalUserId: String? = null,
@SerialName("scope")
val scope: String? = null,
)

@Serializable
Expand Down Expand Up @@ -101,6 +103,7 @@ data class RequestTokenPayload(
val oauth_token: String? = null,
val oauth_verifier: String? = null,
val oauth_token_secret: String? = null,
val scope: String? = null,
)

data class ShareableClientDetail(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class RestSourceUserRepositoryImpl(
this.refreshToken = token.refreshToken
this.expiresIn = token.expiresIn
this.expiresAt = Instant.now().plusSeconds(token.expiresIn.toLong()) - expiryTimeMargin
this.scope = token.scope
} else {
this.externalUserId = null
this.authorized = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ class RestSourceUser(
@Column(name = "times_reset")
var timesReset: Long = 0,

@Column(name = "scope")
var scope: String? = null,

@OneToMany(
fetch = FetchType.EAGER,
targetEntity = RegistrationState::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,47 @@ open class OAuth2RestSourceAuthorizationService(
}
}

override suspend fun revokeToken(user: RestSourceUser): Boolean = withContext(Dispatchers.IO) {
override suspend fun revokeToken(user: RestSourceUser): Boolean {
val accessToken = user.accessToken ?: run {
logger.error("Cannot revoke token of user {} without an access token", user.userId)
return@withContext false
return false
}
logger.info("Requesting to revoke access token")
val response = submitForm(user.sourceType) {
append("token", accessToken)
// revoke token using the deregistrationEndpoint token endpoint
val authConfig = clients.forSourceType(user.sourceType)
val deregistrationEndpoint = checkNotNull(authConfig.deregistrationEndpoint) { "Missing deregistration endpoint configuration" }

val isSuccess = try {
withContext(Dispatchers.IO) {
val response = httpClient.submitForm {
url {
takeFrom(deregistrationEndpoint)
parameters.append("token", accessToken)
parameters.append("client_id", authConfig.clientId!!)
}
}
if (response.status.isSuccess()) {
true
} else {
logger.error(
"Failed to revoke token for user {}: {}",
user.userId,
response.bodyAsText().take(512),
)
false
}
}
} catch (ex: Exception) {
logger.warn("Revoke endpoint error: {}", ex.toString())
false
}

return if (isSuccess) {
logger.info("Successfully revoked token for user {}", user.userId)
true
} else {
logger.error("Failed to revoke token for user {}", user.userId)
false
}
response.status.isSuccess()
}

override suspend fun revokeToken(externalId: String, sourceType: String, token: String): Boolean =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.10.xsd">

<changeSet author="pauline" id="addScope">
<addColumn tableName="rest_source_user">
<column name="scope" type="varchar(200)" defaultValue="null" value="null">
<constraints nullable="true" />
</column>
</addColumn>
</changeSet>
</databaseChangeLog>
1 change: 1 addition & 0 deletions docker/etc/rest-source-authorizer/authorizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ restSourceClients:
- sourceType: FitBit
authorizationEndpoint: https://www.fitbit.com/oauth2/authorize
tokenEndpoint: https://api.fitbit.com/oauth2/token
deregistrationEndpoint: https://api.fitbit.com/oauth2/revoke
clientId: Fitbit-clientid
clientSecret: Fitbit-clientsecret
scope: activity heartrate sleep profile
Expand Down
1 change: 1 addition & 0 deletions docker/etc/rest-source-authorizer/authorizer.yml.template
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ restSourceClients:
- sourceType: FitBit
authorizationEndpoint: https://www.fitbit.com/oauth2/authorize
tokenEndpoint: https://api.fitbit.com/oauth2/token
deregistrationEndpoint: https://api.fitbit.com/oauth2/revoke
clientId: Fitbit-clientid
clientSecret: Fitbit-clientsecret
scope: activity heartrate sleep profile
Expand Down
Loading