-
-
Notifications
You must be signed in to change notification settings - Fork 487
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
Conversation
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 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! |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
app/models/supervisor.rb
Outdated
@@ -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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 :)
There was a problem hiding this comment.
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
app/models/user.rb
Outdated
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
…or greater separation of concerns (SoC)
…ctions (randomization)
…ement and test BaseController for signed-in user endpoints)
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) |
There was a problem hiding this comment.
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_....
There was a problem hiding this comment.
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"
?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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| |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
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.
token
column fromusers
tableapi_credentials
table to be used forusers
model for greaterseparation of concerns
(SoC)SHA-256
hash to ensureraw tokens
are never stored indb
(api_token_digest
&refresh_token_digest
)models/api_credentials
andconcern/api.rb
for furtherapi
concern separation andutility
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.rbCredentials Factory Definition
→ spec/factories/api_credential.rbUpdated tests ( no more token column ):
BaseController test
→ spec/requests/api/v1/base_spec.rbSessionController test
→ spec/requests/api/v1/users/sessions_spec.rbUsers Factory Definition
→ spec/factories/users.rbDeployment & Documentation:
Deployment task
→ lib/tasks/deployment/20230822145532_populate_api_tokens.rakeSwagger Documentation
→ swagger/v1/swagger.yamlMore Swagger
→ spec/swagger_helper.rbScreenshots please :)
Example output with updated api/v1/sign_in endpoint blueprint
Feelings gif (optional)