Versions Compared

Key

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

Table of Contents

Use cases

...

View file
nameuse-case-b.pdf
height250

Use case C - Bob  Bob wants to create a Synapse account and accept Alice's invitation.

Sub use case C1 - Bob wants to create a Synapse account using the same email address to which Alice sent the email invitation.

Sub use case C2 - Bob wants to create a Synapse account using a different email address, not the one to which Alice sent the email invitation.

Goal

Bob wants to create a Synapse account and accept Alice's invitation.

Primary actor

Bob

Secondary actorAlice
Preconditions
  1. Alice has sent an email invitation to Bob.
  2. Bob doesn't have a Synapse account.
PostconditionBob is part of Alice's team.

Workflow

...

Sub use case C1

Success scenario

Step 1. Bob clicks on the invitation link in the email he received and is directed to the Synapse web client.

Step 2. The web client presents Bob with the option to create a Synapse account or sign in with an existing account.

Step 3. Bob creates his new Synapse account.

Step 4. The web client displays Alice's invitation to Bob.

Step 5. Bob accepts Alice's team invitation.

Step 6. System sends a notification email to Alice saying that Bob has joined her team.

Sub use case C2

Success scenario

Step 1. Bob clicks on the invitation link in the email he received and is directed to the Synapse web client.

Step 2. The web client presents Bob with the option to create a Synapse account or sign in with an existing account.

Step 3. Bob creates his new Synapse account.

Step 4. System sends a verification email to the address to which Alice sent the invitation.

Step 5. The web client prompts Bob to verify that he owns the above email address by clicking the link in the verification email.

Step 6. Bob clicks on the verification link and is directed to the Synapse web client.

Step 7. The web client displays Alice's invitation to Bob.

Step 8. Bob accepts Alice's team invitation.

Step 9. System sends a notification email to Alice saying that Bob has joined her team.

Mockups

View file
nameuse-case-c1.pdf
height250
View file
nameuse-case-cc2.pdf
height250

Use case D - Bob wants to sign in to his existing Synapse account and accept Alice's invitation.

Sub use case D1 - Bob wants to sign in to his existing Synapse account which is associated with the same email address to which Alice sent the invitation.

Sub use case D2 - Bob wants to sign in to his existing Synapse account which is not associated with the email address to which Alice sent the invitation.

Goal

Bob wants to sign in to his existing Synapse account and accept Alice's invitation.

Primary actor

Bob

Secondary actorAlice
Preconditions
  1. Alice has sent an email invitation to Bob.
  2. Bob has one or more Synapse accounts.
PostconditionBob is part of Alice's team.

Workflow

Main success Sub use case D1

Success scenario

Step 1. Bob clicks on the invitation link in the email he received and is directed to the Synapse web client.

Step 2. The web client presents Bob with the option to create a Synapse account or sign in with an existing account.

Step 3. Bob signs in with his existing Synapse account.

Step 4. The web client displays Alice's invitation to Bob.

Step 5. Bob accepts Alice's team invitation.

Step 6. System sends a notification email to Alice saying that Bob has joined her team.

Mockups

View file
nameuse-case-d.pdf
height250

Use case E - Bob wants to create a new Synapse account but doesn't want to accept Alice's invitation yet.

...

Bob wants to create a new Synapse account but doesn't want to accept Alice's invitation

...

Primary actor

...

Bob

...

  1. Alice has sent an email invitation to Bob.
  2. Bob doesn't have a Synapse account.

...

Workflow

Main success creates new

Sub use case D2

Success scenario

Step 1. Bob clicks on the invitation link in the email he received and is directed to the Synapse web client.

Step 2. The web client presents Bob with the option to create a Synapse account or sign in with an existing account.

Step 3. Bob

signs in with his

existing Synapse account.

Step 4. System sends a verification email to the address to which Alice sent the invitation.

Step 5. The web client prompts Bob to verify that he owns the above email address by clicking the link in the verification email.

Step 6. Bob clicks on the verification link and is directed to the Synapse web client.

Step 7. The web client displays Alice's invitation to Bob.

Step 8. Bob accepts Alice's team invitation.

Step 9. System sends a notification email to Alice saying that Bob has joined her team.

Mockups

...

View file
nameuse-case-ed1.pdf
height250

Flow Diagram

Image Removed

Discussion about the rationale behind some design decisions

We always want to allow Bob to choose the account he joins Alice's team with. This led to the following design decisions:

  • In earlier versions of the design, if the email entered by Alice was already associated with an existing Synapse account, a membership invitation to that account would be created instead of sending an email invitation. The current design changes this behavior and instead, the system always sends an email invitation to Bob and the membership invitation to the Synapse account isn't created.
  • Even if Bob is already signed in to Synapse in his browser, clicking on the invitation link should always ask Bob to sign in again. This avoids the case where Bob accidentally joins the team with the account with which he is currently signed in.

Bob should not be automatically added to the team after registering a new account / signing in to his account, but instead he should need to manually accept the membership invitation. This separates the process of registering for a Synapse account and joining the team, giving Bob the chance to explore Synapse without committing to join Alice's team.

Proposal

Use cases to support

I propose to support all the use cases except use case B. After multiple discussions about the necessity of use case B, I have come to the conclusion that it's an edge case that would incur significant development cost for little benefit. Supporting it would require our system to keep track of the invitation sent by Alice in some form, which is a requirement that none of the other use cases impose on us.

Models to implement

...

emailAddress

teamId

...

emailAddress

inviteeId

inviterId

teamId

hmac

Related models: AccountSetupInfoMembershipInvtnSubmission

Services to implement

View file
nameuse-case-d2.pdf
height250

Use case E - Bob wants to create a new Synapse account but doesn't want to accept Alice's invitation yet.

This use case is covered by use case C.

Complete workflow diagram

Image Added


Security concerns

Guaranteeing the security of our users' data is a top priority. Inviting a person to join your team is effectively giving that person access to all the data contained in all the projects your team has access to. This means that inviting someone through email inherently carries some risk.

Consider the following scenarios that could result in data breaches:

  • Alice sends an email invitation to join her team to Bob, granting him access to the data accessible by Alice's team. However, Bob forwards his invitation to Claire. Now Claire has access to all the data Bob was supposed to have access to. Alice may not have intended for this to happen.
  • Alice makes a typo when typing Bob's email address, sending it to some other (existent) email address.

In order to protect our users from these types of situations, we could make the following design decisions:

  • Inform our users of the risks in the email invitation widget.
  • Require the user to type the recipient email address a second time for confirmation.
  • Allow the user to invalidate pending invitations.
  • Make all invitation links single-use. Also, make them expire after a certain period of time. This prevents a malicious person from using an invitation link they found in an email inbox they hacked.
  • Require the consumer of the invitation link to prove that they are the owner of the email address to which Alice sent the email invitation, i.e. prove that they are Bob.
    We can do this by sending a verification email to Bob's email address when the invitation link is used.

Proposal

Models to implement or modify

New models
MembershipInvtnSignedTokenEmailValidationSignedTokenInviteeVerificationSignedTokenAccountCreationToken

membershipInvitationId

expiresOn

timestamp

hmac

email

timestamp

hmac

inviteeId

membershipInvitationId

expiresOn

timestamp

hmac

emailValidationSignedToken

encodedMembershipInvtnSignedToken (optional)


Existing models (modified)
MembershipInvitationAccountSetupInfoNewUser

createdOn

message

id

createdBy

expiresOn

inviteeId

teamId

inviteeEmail

firstName

lastName

emailValidationToken

emailValidationSignedToken

username

password

email

lastName

firstName

userName

encodedMembershipInvtnSignedToken (optional)

Services to implement or modify

...

Alternative implementations

DescriptionProsCons1

POST /emailInvitation and POST /tokenMembershipInvitation

(Proposal described above)

+ Supports most use cases (all but B)

+ Simple -> less development time

- Not RESTful2

Same as option 1, but store EmailInvitation in the database and implement REST methods for it.

I.e. GET /emailInvitation, GET /emailInvitation/{id}, DELETE /emailInvitation/{id}, etc.

+ Supports use case B

+ RESTful

- More complex -> more development time3

User precursor

+ Supports use case B

+ More easily extensible (future support for operations other than inviting to a team)

+ RESTful

- Even more complex -> more development time

- ACL management is out of scope
Existing or newDescriptionIntended UserURIMethodRequest ParametersRequest BodyResponse BodySuccess Response CodeNotification Sent to NotesSend email invitation with link to join a teamauthorized user/emailInvitationPOSTEmailInvitation200 OKEmail address providedThe invitation link will contain a serialized MembershipInvtnSignedToken with inviteeId set to nullCreate MembershipInvitation using a signed tokenpublic/tokenMembershipInvitation POSTMembershipInvtnSignedTokenMembershipInvtnSubmission201 CreatedSimilar to POST /membershipInvitation, but using a signed token for authorization. Also, doesn't send any email notifications.

Related services: POST /principal/availablePOST /accountPOST /sessionPOST /membershipInvitation

Example implementation with Synapse web client

As the use cases above, the inviter is Alice and the invitee is Bob.

  1. Alice invites Bob to her team by entering his email address.
  2. Web client constructs an EmailInvitation using Bob's email address and Alice's team's id, then uses it to send a POST /emailInvitation request to the backend.
  3. Backend constructs a signed MembershipInvtnSignedToken with Bob's email address, Alice's team's id, Alice's id and a null inviteeId (because we don't know Bob's account's id yet).
  4. Backend serializes the MembershipInvtnSignedToken, embeds it into an invitation link to the web client and sends the link to Bob's email address.
  5. Bob clicks on the link and does one of the following:
    1. Registers a new Synapse account. [1]
      1. Web client checks that Bob's email address is a valid account alias through POST /principal/available.
      2. Web client constructs an AccountSetupInfo [2], then uses it to create Bob's account through POST /account and receives a session token.
    2. Signs in to his existing Synapse account.
      1. Web client retrieves a session token through POST /session.
  6. Web client deserializes and validates the MembershipInvtnSignedToken in the link, then sets the inviteeId to the id of the account Bob used (extracted from the session token).
  7. Web client re-signs the MembershipInvtnSignedToken, then uses it to send a POST /tokenMembershipInvitation request to the backend.
  8. Backend validates the MembershipInvtnSignedToken and uses it to create a MembershipInvitation from Alice's team to Bob's account.
  9. Web client receives backend's 201 response, then directs Bob to his profile's Team tab, where he has a pending MembershipInvitation to Alice's team
  10. Bob accepts Alice's invitation (using the existing MembershipInvitation services).

...

Existing

Create a membership invitation. The team must be specified. Either an inviteeId or an inviteeEmail must be specified.

If an inviteeEmail is specified, send an email containing an invitation link to the invitee. The link will contain a serialized MembershipInvtnSignedToken.

team administrator/membershipInvitationPOST

acceptInvitationEndpoint (optional)

notificationUnsubscribeEndpoint (optional)

MembershipInvitationMembershipInvitation
NewRetrieve a membership invitation.signed token holder/membershipInvitation/{id}POST--MembershipInvtnSignedTokenMembershipInvitation

Existing

Start the process of creating a new account, and optionally also the process of associating a membership invitation to the new account.

Send a 'validation email' message to the provided email address. The email will contain a link to complete the registration process.

The link will contain a serialized AccountCreationToken.

Intended to be used in conjunction with POST /account.

public

/account/emailValidation

POST

portalEndpoint

NewUser--
New

Verify whether the inviteeEmail of the indicated MembershipInvitation is associated with the authenticated user.

If it is, the response body will contain an InviteeVerificationSignedToken.

If it is not, (in phase 1 the server just responds with a 403) the response body will be null and an identity verification email containing a link will be sent to the inviteeEmail of the indicated MembershipInvitation. The link will contain a serialized InviteeVerificationSignedToken.

This call will only succeed if the indicated MembershipInvitation has a null inviteeId and a non null inviteeEmail.

authenticated user/membershipInvitation/{id}/inviteeVerificationSignedTokenGETportalEndpoint
InviteeVerificationSignedToken

New

Set the inviteeId of a MembershipInvitation.

A valid InviteeVerificationSignedToken must have an inviteeId equal to the id of the authenticated user and a membershipInvitationId equal to the id in the URI.

This call will only succeed if the indicated MembershipInvitation has a null inviteeId and a non null inviteeEmail.

authenticated signed token holder/membershipInvitation/{id}/inviteeIdPUT--


InviteeVerificationSignedToken--

Related services: POST /accountPOST /session

Statistics to track

  • Which users create invitations, when they create them, and from what teams they create them.
    • These statistics are captured by the MembershipInvitation (formerly MembershipInvtnSubmission) model, which is stored in the database.
  • How many invitations are accepted and when they are accepted.
    • There is no easy way to track when the invitation to the team is accepted, but we can know how many times the invitee will use the email link to create a new account or sign in to their existing account. This is essentially the number of times that PUT /membershipInvitation/{id}/inviteeId is called.
  • How many invitees choose to register a new account and how many choose to sign in.
    • We know the total number of membership invitations created from the number of POST /emailMembershipInvitation/{id}/membershipInvitation requests.
    • We know the total number of invitees who chose to register a new account from the number of POST /emailMembershipInvitation/{id}/account/emailValidation requests.
    • We can derive the total number of invitees who chose to sign in with an existing account from the above two numbers.
  • We can know how often invitees attempt to sign in using an email address that is not associated with the inviteeEmail of the MembershipInvitation by looking at how often GET /membershipInvitation/{id}/inviteeVerificationSignedToken calls respond with 403 status.

Implementation outline

Phase 1

I expect that in most cases, invitees will choose to sign in or register with the invited email address. I'll refer to this as the "happy" case.

In phase 1 I will implement use cases A, B, C1, D1 and E. These use cases represent the happy case.

Phase 2

There will be some invitees that want to sign in or register with a different email address. I expect that the number of users who choose this path will be low enough that this will be an edge case.

In phase 2 I will implement use cases C2 and D2. These use cases represent the edge case described above.

Progress

Phase 1

Create new models

  •  MembershipInvtnSignedToken
  •  EmailValidationSignedToken
  •  InviteeVerificationSignedToken
  •  AccountCreationToken

Update existing models

  •  MembershipInvtnSubmission
  •  AccountSetupInfo
  •  NewUser

Update existing services

  •  POST /membershipInvitation
  •  POST /account/emailValidation

Create new services

  •  POST /membershipInvitation/{id}
  •  POST /membershipInvitation/{id}/verification
  •  PUT /membershipInvitation/{id}/inviteeId

Update web client

  •  Make everything work


Sequence of events

Image Added

Made on https://sequencediagram.org/ with the following markup:

Code Block
entryspacing 0.9
Frontend->Backend:Invite the new user (POST membershipInvitation)
Backend->OUT OF BAND: Send email that contains MembershipInvtnSignedToken
OUT OF BAND->Frontend: User clicks Join link in email
Frontend->Backend:Get corresponding membershipInvitation (POST membershipInvitation/id)
Backend-->Frontend:Membership Invitation
note over Frontend,Backend:Already has an account
Frontend->Frontend:User clicks "Already have an Account?"
Backend->OUT OF BAND
OUT OF BAND->Frontend
Frontend->Backend: Login
Backend-->Frontend:Successful Login
Frontend->Backend:GET membershipInvitation/id/inviteeVerificationSignedToken
Backend-->Frontend:Return InviteeVerificationSignedToken
Frontend->Backend: Update invitation with user id: PUT /membershipInvitation/{id}/inviteeId
Backend-->Frontend:
Frontend->Frontend: User sent back to the Team page. Single click Join (since there's an open invitation)
note over Frontend,Backend:New account
Frontend->Frontend:User click "Send Registration Info"
Frontend->Backend:POST/account/emailValidation
Backend->OUT OF BAND: Send validation email
OUT OF BAND->Frontend: User clicks create account link
Frontend->Backend:Standard account creation (sign ToU...)
Backend-->Frontend:Standard account creation
Frontend->Frontend: User sent to associated Team page. Single click Join (since there's an open invitation)



Related JIRA issues

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keyPLFM-2073

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keyPLFM-3381

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keyPLFM-3385

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keyPLFM-4615

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keyPLFM-4614

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keySWC-3836

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keySWC-3918

Jira Legacy
serverSystem JIRA
serverIdba6fb084-9827-3160-8067-8ac7470f78b2
keyPLFM-4739