Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

This design would allow us to support other OAuth "Authorization Code Grant" providers in the future.

API

authenticated usersPOST /v3/oauth/:
vendorIdentifier
vendorId
body{"authCode":"<authCode>"}
if auth code provided in postget access and refresh tokens
no authCode provided, accessToken exists, not expiredreturn access token
no authCode provided, accessToken exists, expiredrefresh access token, return new access token
401no authCode, no accessToken, or an error
200{"vendorId":"vendorId","accessToken":"<accessToken>","expiresOn":"<ISO 8601 timestamp>"}


Get method that returns health codes for accounts that have given Fitbit authorization (at some point). These might be some kind of minimal grant object as well (OAuthGrant[healthCode, accessToken, expiresOn]).

workersGET /v3/studies/:studyIdentifier/oauth/:
vendorIdentifier
vendorId?pageSize=x&offsetKey=y
200{"items":["healthCode1","healthCode2"], "
offsetKey"
requestParams": {...}, "type":"ForwardOnlyCursorPagedList"}


workers
POST
GET /v3/studies
/oath
/:studyIdentifier/oauth/:vendorId/:
vendorIdentifierbody{"
healthCode
":"<health code>"}
if access token exists and is not expiredreturn access token
if access token exists and is expiredrefresh token and return refreshed token
401anything else (should only be an error from Fitbit)
200{"vendorId":"vendorId","accessToken":"<accessToken>","expiresOn":"<ISO 8601 timestamp>"}

OAuthService

MethodDescription
OAuthAccessToken requestAccessToken(OAuthAuthorizationToken authToken)
: OAuthAccessToken
retrieves the access token, making the necessary requests to the OAuth provider to refresh or whatever
getHealthCodesGrantingVendorAccess
ForwardCursorPagedResourceList<String> getHealthCodesGrantingAccess(StudyIdentifier studyId, String vendorIdentifier, int pageSize, String offsetKey)
: ForwardCursorPagedResourceList<String>
retrieve all the health codes for accounts that have granted access to the OAuth provider at some point. They should all have refresh tokens and access tokens.
OAuthAccessToken getAccessToken(StudyIdentifier studyId, String vendorIdentifier, String healthCode)
: OAuthAccessToken
retrieves an access token for the individual health code, making the necessary requests to the OAuth provider to refresh or whatever.

There will be a DynamoOAuthProviderDao that takes the OAuthProvider and uses that data to make what is in theory a standard OAuth request. There will be a DynamoOAuthAccessGrantDao to manage access to that table. 's going to be some other classes that aren't that interesting:

  • OAuthProvider
  • OAuthAccessGrant
  • DynamOAuthAccessGrant
  • OAuthAccessGrantDao
  • DynamoOAuthAccessGrantDao

These are pretty standard design-wise.

DynamoDB Tables

Study
Map<String,OauthProvider> oauthProviders (mapped to their vendor identifier

Seems trivial enough to include in study.

OAuthProvider
String clientId
String secret
String endpoint
String redirectUrl (maybe)
String state (maybe)

RedirectUrl and state... Fitbit documentation says that if these are provided by the client in the authorization step they have to be provided in this step and they have to match exactly. Or maybe they only have to match exactly if they are provided. We'll sort it out.

OAuthAccessGrant
String studyId:vendor (hashKey)
String healthCode (rangeKey)
String accessToken
String refreshToken
Long createdOn
Long expiresOn


OAuthAccessToken
String vendorId
String accessToken
DateTime expiresOn


OAuthAuthorizationToken

String vendorId
String authToken


UserSessionInfo
Map<String,OAuthAccessToken> accessTokens

Fitbit access token response


This is the JSON returned by Fitbit... not sure if this is defined by the OAuth specification or not, but seems like it would have to be and can be standardized in code for the Authorization Code Grant workflow.

{
    "access_token": "eyJhbGciOTnSWz_qlqoEpUlpc",
    "expires_in": 3600,
    "refresh_token": "c643a63c072f0f05478e9d18b991db80ef6061e4f8e6c822d83fed53e5fafdd7",
    "token_type": "Bearer",
    "user_id": "26FWFL"
}