Authentication through Synapse
It will be possible shortly to sign into the Bridge server using credentials held in Synapse. This is how it will work.
First, we’ll create a client on Synapse for Bridge as a whole. Our needs are simple so it may be sufficient to have one client, or one client per environment.
TODO: fill out values. We actually need to create our privacy page first.
New users are directed to create an account on Synapse, and then to send us their profile name (found on the profile page as PROFILE_NAME@synapse.org. We can use this to find their Synapse user ID:
POST https://repo-prod.prod.sagebase.org/repo/v1/principal/alias
{"alias": "<ALIAS>", "type": "USER_NAME"}
=> {"principalId":<Number>}
Note that the ID is here represented as a number (in other APIs, it is a string, and we’ll store it as such in the account record we create for them in Bridge). We create a Bridge account that can contain as little as this Synapse User ID and the user’s roles in Bridge (we’ll probably also mark it as a test account). The Synapse user ID can be added on or after Account creation, but once added, it cannot be changed (we have specific APIs and rules for changing credentials like email and phone number, the Synapse user ID should follow the same rules). [NOTE: I’m not sure about this, I’m open to other options. Assignment is similar to external IDs as proposed here.]
When the user selects “Sign in with your Synapse account”:
The BSM opens an authentication link at the sage sign in server (SSS):
https://signin.synapse.org/?
response_type=code&
client_id=bridge_client_id&
redirect_uri=https://research.sagebridge.org/!oauth&
scope=openid&
nonce=RANDOM&
claims={"id_token":{"userid":null}} // url encoded
If successful, Synapse redirects back to the BSM:
https://research.sagebridge.org/!oauth?
code=AUTH_CODE_HERE&
nonce=RANDOM
The BSM verifies the nonce is identical to the nonce that was sent, then sends the authorization grant to the Bridge server to sign in:
The Bridge server contacts Synapse to retrieve an access token and identifiers:
Synapse returns a JSON document that includes an access_token and id_token property, and the id_token property will include the Synapse User ID (because we asked for it in the claims we sent and they aren’t optional when the user signs in via Synapse).
We retrieve an account using the synapse ID and study ID, proceeding from this point on to create a session in the normal manner if we find an account. If not… they authenticated as the wrong person, authenticated in the wrong study, etc.
As of October 2019, Synapse does not implement the refresh token, the access token lasts 24 hours, and there’s no way to revoke the access token before then. So we can safely let the Bridge Session expire and let the user sign in via Synapse again using the above workflow. As a result, we do not need to store the information returned by Synapse when requesting an access token. In later iterations, to implement full SSO, we’ll need to create and propagate a Synapse session or implement a refresh token when available.
Accessing all Bridge studies a Synapse User is assigned to
GET /v3/studies?format=self
We can do a query for all the studies in which an authenticated user has their synapse user ID:
This endpoint should throw an UnauthenticatedException if the user is not authenticated. It should return the summary view of studies, sufficient to provide a UI to select a new study, if the user is authenticated.
Alternatively, we could put this in the user’s session.
POST /v3/auth/study
A user can submit a new study to which they wish to bind their session. If the user’s Synapse user ID exists for an account in that study (it should, if they picked the study from the list returned in the prior API), then we recreate their session in the new study and return it in the response. A user’s permissions can be different on a study-by-study basis.