Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Portal Prototype #3732

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open

Portal Prototype #3732

wants to merge 42 commits into from

Conversation

rahafjrw
Copy link
Collaborator

As part of the Swift Mentorship Program, I prototyped an authentication feature for the site. This PR is progress towards #3384.

This system uses AWS Cognito, accessed via the Soto gem. It adds 13 new routes:

  • GET /portal/: The logged-in portal page, currently containing only a logout button and delete account button.
  • GET /login/: Display the login page, where a user inputs their email and password
  • POST /login/: Logs in the user
  • GET /signup/: Displays the sign up page, where a user inputs their email and password
  • POST /signup/: Registers the user in the Cognito pool. At this point, the user is uncomfirmed and will need to verify their registration to be fully registered.
  • GET /verify/: Displays the verify page, where a user can input the confirmation code sent to their email. Note that a user can only login once they have verified their account. If you sign up and lose/don't recieve the code for whatever reason/don't complete the verification step and you attempt to sign up again, an error will be thrown. If you try to login, you will get a "user already exists" error. Ways to combat this will need to be researched.
  • POST /verify/: Verifies the users sign up
  • POST /login/: Logs out the user, which entails destroying the session/cookie
  • POST /delete/: Deletes the user from the Cognito pool
  • GET /forgot/: Displays the forgot password page, which allows user to input the email of the account to reset password
  • POST /forgot/: Sends an email to the user with a reset code
  • GET /reset-password/: Displays the reset password change, which allows to user to input the reset code sent to their email, their email, and a new password
  • POST /reset/: Resets the user's password

These pages are intentionally unstyled as this is just a prototype. However, it can be deployed as all additional code paths are gated to the staging/dev environment.

As mentioned in the issue, a key issue is to avoid storing personally identifying information (PII) in the database. Cognito stores all PII (only an email address) in its own database, leaving the SPI database only responsible for storing the unique identifier.

All core Cognito functionality is in Cognito.swift so that it can be easily tested or replaced in the future if a different system is needed. It also utilizes the dependencies library for testing, which are in PortalTests.swift.
Note: At this time, the tests use XCTest, and SPI has since fully adopted swift testing. This branch will not be merged until tests are converted to swift testing.

To persist user authentication post-login between requests, I used Vapor’s Session API with secure cookies. See Vapor’s Session and Website Authentication documentation for more information.

Note: In Cognito.swift, the awsClient is created and shutdown at the function level in Cognito because the aws client requires a manual shutdown. It can error if it is globally declared in configure.swifts and not shutdown.

This PR does not address:

  • Persistence of cookies on the server: Currently, when the server reboots, all cookies are lost. This will also affect a production environment where a client may hit a different server with each request.
  • Refreshing token: Currently, the access token is not refreshed, so once the access token expires, the user is unauthenticated and will have to log in again. Upon successful login, the access token and refresh token are returned (see the enum CognitoAuthenticateResponse, which is returned by Soto's authenticate()). The refresh token will need to be securely stored, then, in the UserSessionAuthenticator in SessionAuthentication, it can be used to attempt to refresh the token with .refresh() if Soto throws an unauthorized error with reason "invalid token" (see line 24 of SessionAuthentication).

Lastly, a huuuuuge thank you to Dave for being so supportive and the best mentor!!!

@rahafjrw rahafjrw requested a review from daveverwer March 17, 2025 04:39
@cla-bot cla-bot bot added the cla-signed label Mar 17, 2025
@rahafjrw rahafjrw changed the title Portal Portal Prototype Mar 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants