Versions Compared

Key

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

Table of Contents

...

This use case is covered by use case C.

...

Complete workflow diagram


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.

...

  • 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

emailMembershipInvitationId
New modelsExisting models (modified)
EmailMembershipInvitationEmailMembershipInvitationIdMembershipInvtnSignedTokenEmailValidationSignedTokenInviteeVerificationSignedTokenAccountSetupInfoAccountCreationTokenNewUser

membershipInvitationId

teamIdexpiresOn

createdBytimestamp

idhmac

emailMembershipInvitationId

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

EmailValidationSignedTokenemailValidationSignedToken

username

password

email

lastName

firstName

userName

...

encodedMembershipInvtnSignedToken (optional)

Services to implement or modify

Create and send email membership invitation EmailMembershipInvitationIdemailMembershipInvitation/emailMembershipInvitation similarly to POST /account/emailValidation, but Sends contains EmailValidationSignedToken (used for new account registration) and a serialized EmailMembershipInvitationId (used to create membership invitation)emailMembershipInvitation/{id}/

Create a MembershipInvitation. The invitation is created from the team associated with the given email membership invitation to the currently authenticated user.

At least one of the following conditions must be met in order for this service to succeed:

  • One of the authorized user's email addresses is the same as the email address in the given EmailMembershipInvitation.
  • A valid InviteeVerificationSignedToken (IVST) was passed in as a parameter. (IVST.inviteeId == authenticated user's ID && IVST.emailInvitationId == resource URL {id})

    Doesn't send any email notifications.

    Existing or newDescriptionIntended UserURIMethodRequest ParametersRequest BodyResponse Body
    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/membershipInvitationPOSTportalEndpointEmailMembershipInvitationEmailMembershipInvitation
    Retrieve pending email membership invitation by ID.authenticated user/emailMembershipInvitation/{id}GET----EmailMembershipInvitation
    Retrieve pending email membership invitations from a Team.team administrator/team/{id}/emailMembershipInvitationsGETlimit, offset--PaginatedResults<EmailMembershipInvitation>
    Delete and invalidate pending email membership invitation.team administrator

    acceptInvitationEndpoint (optional)

    notificationUnsubscribeEndpoint (optional)

    MembershipInvitationMembershipInvitation
    NewRetrieve a membership invitation.signed token holder/membershipInvitation/{id}DELETEPOST--MembershipInvtnSignedToken----Starts MembershipInvitation

    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--
    Send 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 address associated with the provided EmailMembershipInvitationinviteeEmail of the indicated MembershipInvitation. The link contains 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/emailMembershipInvitationmembershipInvitation/{id}/verificationinviteeVerificationSignedTokenPOSTportalEndpoint----authenticated user/emailMembershipInvitation/{id}/membershipInvitationPOST

    InviteeVerificationSignedToken

    (optional)

    --MembershipInvtnSubmission

    ...

    GETportalEndpoint
    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

    Additional notes

    Tracking request and acceptance counts

    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