Document toolboxDocument toolbox

OAuth 2.0 Authorization Code Grant Workflow

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

API

authenticated usersPOST /v3/oauth/: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/:vendorId?pageSize=x&offsetKey=y
200{"items":["healthCode1","healthCode2"], "requestParams": {...}, "type":"ForwardOnlyCursorPagedList"}


workersGET /v3/studies/:studyIdentifier/oauth/:vendorId/:healthCode
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)retrieves the access token, making the necessary requests to the OAuth provider to refresh or whatever
ForwardCursorPagedResourceList<String> getHealthCodesGrantingAccess(StudyIdentifier studyId, String vendorIdentifier, int pageSize, String offsetKey)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)retrieves an access token for the individual health code, making the necessary requests to the OAuth provider to refresh or whatever.

There'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"
}