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

Feature/6207 Endpoint api/v1/sign_in now outputs randomized tokens in response upon sign-in #6216

Merged
merged 12 commits into from
Feb 19, 2025

Conversation

7riumph
Copy link
Collaborator

@7riumph 7riumph commented Feb 6, 2025

What github issue is this PR for, if any?

Resolves #6207

What changed, and why?

Volunteers api/v1/sign_in endpoint now outputs secured randomized tokens upon sign-in.

  • Dropped token column from users table
  • Added api_credentials table to be used for users model for greater separation of concerns (SoC)
  • Utilized SHA-256 hash to ensure raw tokens are never stored in db ( api_token_digest & refresh_token_digest )
  • Created models/api_credentials and concern/api.rb for further api concern separation and utility

Why?: To ensure compliance with apples review process, and enhance security with an applicable industry standard.

How is this tested? (please write tests!) 💖💪

New tests:

Authentication Helper Function tests (14 in total) → spec/models/api_credential_spec.rb
Credentials Factory Definition → spec/factories/api_credential.rb

Updated tests ( no more token column ):

BaseController test → spec/requests/api/v1/base_spec.rb
SessionController test → spec/requests/api/v1/users/sessions_spec.rb
Users Factory Definition → spec/factories/users.rb

Deployment & Documentation:

Deployment task → lib/tasks/deployment/20230822145532_populate_api_tokens.rake
Swagger Documentation → swagger/v1/swagger.yaml
More Swagger→ spec/swagger_helper.rb

Screenshots please :)

Example output with updated api/v1/sign_in endpoint blueprint

example_output_sign_in_success

Feelings gif (optional)

very strange

@github-actions github-actions bot added ruby Pull requests that update Ruby code Tests! 🎉💖👏 labels Feb 6, 2025
@7riumph 7riumph changed the title Feature/6207 Feature/6207 Endpoint api/v1/sign_in now outputs randomized tokens in response upon sign-in Feb 6, 2025
@7riumph 7riumph marked this pull request as draft February 6, 2025 23:17
@7riumph 7riumph changed the title Feature/6207 Endpoint api/v1/sign_in now outputs randomized tokens in response upon sign-in Feature/6207 Endpoint api/v1/sign_in now secured via randomized tokens in response upon sign-in Feb 6, 2025
@7riumph 7riumph changed the title Feature/6207 Endpoint api/v1/sign_in now secured via randomized tokens in response upon sign-in Feature/6207 Endpoint api/v1/sign_in now secured with randomized tokens in response upon sign-in Feb 6, 2025
@7riumph 7riumph changed the title Feature/6207 Endpoint api/v1/sign_in now secured with randomized tokens in response upon sign-in Feature/6207 Endpoint api/v1/sign_in now outputs randomized tokens in response upon sign-in Feb 6, 2025
@7riumph 7riumph requested a review from xihai01 February 6, 2025 23:27
@xihai01
Copy link
Collaborator

xihai01 commented Feb 7, 2025

looks good to me so far 🔥

I think instead of storing the token and refresh token as plaintext in the db, we can store it as a hash
like what shen suggested

Then the client would be provided the plaintext versions of the tokens and whenever they call the api, the hash versions will be compared

@@ -2,6 +2,10 @@ class Api::V1::Users::SessionsController < Api::V1::BaseController
def create
load_resource
if @user

@user.regenerate_session_token!
@user.regenerate_refresh_token!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't do this twice?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is actually for two separate tokens. The plan is the session_token expires quickly and is repeatedly replaced for as long as the refresh_token is valid to maintain access.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token regeneration is now handled in the blueprint before being passed to the session controller.

@@ -81,10 +81,13 @@ def recently_unassigned_volunteers
# receive_email_notifications :boolean default(TRUE)
# receive_reimbursement_email :boolean default(FALSE)
# receive_sms_notifications :boolean default(FALSE), not null
# refresh_token :string
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe make a new type of user, ApiUser?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into this, may complicate authorization. I'll just create a completely new table for api/v1 credentials so the user model and roles inheriting from it aren't overloaded.

Additionally, will attempt to do more compartmentalizing this PR through a concern :)

Copy link
Collaborator Author

@7riumph 7riumph Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created the concern and imported into models/user.rb

after_create :skip_email_confirmation_upon_creation
after_create :create_preference_set
before_update :record_previous_email
has_secure_token :token, length: 36
has_secure_token :refresh_token, length: 36
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

36 what? seconds, minutes, days, weeks?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vague syntax refers to token length, in this case. The token is 36 characters long.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tokens are now in a credentials table

@7riumph 7riumph marked this pull request as ready for review February 11, 2025 22:41
@7riumph 7riumph requested review from xihai01 and compwron February 11, 2025 23:06
@7riumph 7riumph requested a review from harsohailB February 12, 2025 04:18
before_save :generate_refresh_token

# Securely confirm/deny that Hash in db is same as current users token Hash
def authenticate_api_token(api_token)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does these functions return boolean value?
if so, the naming should be consistent with other similar functions starting with the is_....

Copy link
Collaborator Author

@7riumph 7riumph Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, returns a boolean. How's Something like "is_api_token_valid"?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that would be perfect
also follows ruby conventions too

def change
create_table :api_credentials do |t|
t.references :user, null: false, foreign_key: true
t.string :api_token
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're also storing the plain text tokens in the table?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm I think you created a migration to remove them right?

Copy link
Collaborator Author

@7riumph 7riumph Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, originally added 2 unneeded token columns then created a migration to remove them.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool

@@ -4,9 +4,9 @@ namespace :after_party do
puts "Running deploy task 'populate_api_tokens'" unless Rails.env.test?

# Put your task implementation HERE.
User.where(token: nil).each do |user|
User.find_each do |user|
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to create a separate deployment task for populating the api tokens?
so we don't touch the sms stuff

Copy link
Collaborator Author

@7riumph 7riumph Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get the concern, but this task was not made as part of the original SMS epic. History is you originally created the file here then Sam Williams or schoork added our sms and your token addition to it here

I've edited the task because tokens are in a api_credentials table now.

Copy link
Collaborator

@xihai01 xihai01 Feb 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see I see
I forgot I originally created this
yea, just leave it then

Copy link
Collaborator

@xihai01 xihai01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ruby Pull requests that update Ruby code Tests! 🎉💖👏
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enhance endpoint security for /api/v1/users/sign_in with randomization
4 participants