Skip to content

Latest commit

 

History

History
209 lines (196 loc) · 6.28 KB

MAGIC-LINKS.md

File metadata and controls

209 lines (196 loc) · 6.28 KB

Magic Links

This solution includes components to support signing-in with a Magic Link:

  • AWS Lambda functions that implement the Amazon Cognito Custom Authentication flow, using Amazon Simple E-Mail Service (SES) to send the e-mails to users.
  • Magic Links are signed using an Amazon Key Management Service (KMS) assymmetric key. Using AWS KMS enables the feature that Magic Links might be requested in one browser, but will still work when actually opened in another browser (e.g. when a mobile e-mail app opens the link in its integrated browser). Even though the auth session would re-initialize in that case, the KMS signature can be verified to make sure it was us who created the Magic Link.
  • For each Magic Link, cryptographic hashes are stored in an Amazon DynamoDB table, so that (1) we can ensure that a Magic Link can only be used once, (2) that a user can have maximally 1 unused Magic Link outstanding, and (3) that a user must wait minimally one minute before allowing him/her to request a new Magic Link. These cryptographic hashes cannot be traced to its corresponding user, except by our Lambda functions (who know the seed).
  • Front End library functions, to work with this Custom Auth flow––can be used in Web, React, React Native.

Magic Link example

Customizing Auth - e.g. to use your own e-mail template

If you want to do customization of this solution that goes beyond the parameters of the Passwordless construct, e.g. to use your own e-mail content for magic links, see CUSTOMIZE-AUTH.md

AWS Architecture

Magic Link Architecture

Request Magic Link

sequenceDiagram
    autonumber
    actor User
    participant BJS as Browser JavaScript
    participant BLS as Browser Storage
    participant C as Cognito
    participant DA as DefineAuth
    participant CA as CreateAuthChallenge
    participant VA as VerifyAnswer
    participant KMS as AWS KMS
    participant SES as Amazon SES
    participant DDB as DynamoDB
    User->>BJS: Enter username + click sign-in
    activate User
    activate BJS
    BJS->>C: Initiate Auth (CUSTOM_AUTH)
    Activate C
    C->>DA: Invoke
    Activate DA
    DA->>C: Next: CUSTOM_CHALLENGE
    Deactivate DA
    C->>CA: Invoke
    Activate CA
    CA->>C: Challenge: PROVIDE_AUTH_PARAMETERS
    Deactivate CA
    C->>BJS: Session, Challenge
    Deactivate C
    BJS->>C: Respond to Auth Challenge: send link
    Activate C
    C->>VA: Invoke
    Activate VA
    VA->>C: null
    Deactivate VA
    C->>DA: Invoke
    Activate DA
    DA->>C: Next: CUSTOM_CHALLENGE
    Deactivate DA
    C->>CA: Invoke
    Activate CA
    CA->>DDB: Check prior magic link metadata
    Activate DDB
    DDB->>CA: issued-at or null
    Deactivate DDB
    CA->>CA: Check null, or issued-at is sufficiently old
    CA->>KMS: Sign message
    Activate KMS
    KMS->>CA: Signature
    Deactivate KMS
    CA->>DDB: Store magic link metadata
    Activate DDB
    DDB->>CA: OK
    Deactivate DDB
    CA->>SES: Invoke
    Activate SES
    SES->>User: Email with magic link
    SES->>CA: OK
    Deactivate SES
    CA->>C: Challenge: MAGIC_LINK
    Deactivate CA
    C->>BJS: Session, Challenge
    Deactivate C
    BJS->>BLS: Store Session
    Activate BLS
    BLS->>BJS: Ok
    Deactivate BLS
    BJS->>User: "We've emailed you a magic link"
    deactivate BJS
    deactivate User
Loading

Complete Sign-in: same browser, new tab

sequenceDiagram
    actor User
    participant BJS as Browser JavaScript
    participant BLS as Browser Storage
    participant C as Cognito
    participant DA as DefineAuth
    participant VA as VerifyAnswer
    participant KMS as AWS KMS
    participant DDB as DynamoDB
    User->>BJS: Open magic link
    activate User
    activate BJS
    BJS->>BLS: Load session
    Activate BLS
    BLS->>BJS: Session
    Deactivate BLS
    BJS->>BLS: Delete session
    Activate BLS
    BLS->>BJS: Ok
    Deactivate BLS
    BJS->>C: Respond to Auth Challenge: secret hash
    Activate C
    C->>VA: Invoke
    Activate VA
    VA->>DDB: Delete magic-link metadata w/ condition
    Activate DDB
    DDB->>VA: Deleted record (w/ KMS Key ID), exception, or null
    Deactivate DDB
    VA->>KMS: Download public key
    Activate KMS
    KMS->>VA: Public key
    Deactivate KMS
    VA->>VA: Verify Signature
    VA->>VA: Check magic link username, expiry, issuedAt
    VA->>C: Answer correct
    Deactivate VA
    C->>DA: Invoke
    Activate DA
    DA->>C: Succeed Auth
    Deactivate DA
    C->>BJS: JWTs
    Deactivate C
    BJS->>BLS: Store JWTs
    Activate BLS
    BLS->>BJS: Ok
    Deactivate BLS
    BJS->>User: "You are signed in!"
    Deactivate User
    Deactivate BJS
Loading

Complete Sign-in: different browser

sequenceDiagram
    autonumber
    actor User
    participant BJS as Browser JavaScript
    participant BLS as Browser Storage
    participant C as Cognito
    participant DA as DefineAuth
    participant CA as CreateAuthChallenge
    participant VA as VerifyAnswer
    participant KMS as AWS KMS
    participant DDB as DynamoDB
    User->>BJS: Open magic link
    activate BJS
    activate User
    BJS->>BLS: Load session
    Activate BLS
    BLS->>BJS: null
    Deactivate BLS
    BJS->>C: Initiate Auth (CUSTOM_AUTH)
    Activate C
    C->>DA: Invoke
    Activate DA
    DA->>C: Next: CUSTOM_CHALLENGE
    Deactivate DA
    C->>CA: Invoke
    Activate CA
    CA->>C: Challenge: PROVIDE_AUTH_PARAMETERS
    Deactivate CA
    C->>BJS: Session, Challenge
    Deactivate C
    BJS->>C: Respond to Auth Challenge: secret hash
    Activate C
    C->>VA: Invoke
    Activate VA
    VA->>DDB: Delete magic-link metadata w/ condition
    Activate DDB
    DDB->>VA: Deleted record (w/ KMS Key ID), exception, or null
    Deactivate DDB
    VA->>KMS: Download public key
    Activate KMS
    KMS->>VA: Public key
    Deactivate KMS
    VA->>VA: Verify Signature
    VA->>VA: Check magic link username, expiry, issuedAt
    VA->>C: Answer correct
    Deactivate VA
    C->>DA: Invoke
    Activate DA
    DA->>C: Succeed Auth
    Deactivate DA
    C->>BJS: JWTs
    Deactivate C
    BJS->>BLS: Store JWTs
    Activate BLS
    BLS->>BJS: Ok
    Deactivate BLS
    BJS->>User: "You are signed in!"
    Deactivate User
    Deactivate BJS
Loading