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/6222 - Endpoint /api/v1/users/sign_out revokes access token and refresh token on request #6241

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

xihai01
Copy link
Collaborator

@xihai01 xihai01 commented Feb 24, 2025

WIP WIP WIP WIP WIP

What github issue is this PR for, if any?

Resolves #6222

What changed, and why?

Added /api/v1/users/sign_out endpoint so both the access and refresh tokens for that user is cleared from the api_credentials table and set to nil.

  • Added request and model specs for the sign out route
  • Generated and updated swagger file
  • Added helper function to api credential model to clear tokens
  • Added sign out to routes and session controller
  • Added seed data for populating tokens in api credential table in dev environment

Why?: for added security - tokens should be removed from api_credentials table because user is no longer signed in.

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

Token Destroyer Helper Function tests (2 in total) → spec/models/api_credential_spec.rb
Sign Out Request Test for 200 and 401 Response Cases → spec/requests/api/v1/users/sessions_spec.rb

Screenshots please :)

Testing sign out with postman on localhost

Steps:
First we sign in to fetch the refresh token
Lastly we sign out and pass in refresh token in the request authorization header
Screenshot 2025-02-26 at 12 30 58 PM

Feelings gif (optional)

very strange

@xihai01 xihai01 added the codethechange for codethechange developers label Feb 24, 2025
@xihai01 xihai01 requested a review from 7riumph February 24, 2025 20:47
@xihai01 xihai01 self-assigned this Feb 24, 2025
@github-actions github-actions bot added ruby Pull requests that update Ruby code Tests! 🎉💖👏 labels Feb 24, 2025
@compwron
Copy link
Collaborator

👀

@@ -37,6 +37,19 @@ def is_refresh_token_expired?
refresh_token_expires_at < Time.current
end

# clear tokens
# token argument takes in two strings: api_token and refresh_token
def revoke_token(token)
Copy link
Collaborator

@7riumph 7riumph Feb 26, 2025

Choose a reason for hiding this comment

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

Mind separating these out like a revoke_api_token and revoke_refresh_token function, stylistic to go with the other functions.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Initially this is what I wanted to do but then I thought of avoiding duplication
Let me know if you still want to keep them separate.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have separated it into two functions.

@@ -100,4 +100,24 @@
expect(api_credential.refresh_token_digest).to eq(Digest::SHA256.hexdigest(refresh_token))
end
end

describe "#revoke_token" do
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same thing as above here. So would make 2 tests or one for each function.

@@ -42,6 +42,12 @@
properties: {
message: {type: :string}
}
},
sign_out: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

@@ -19,7 +19,7 @@ components:
type: string
email:
type: string
api_token_expires_at:
token_expires_at:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks 👍👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

no problem. Just in case you weren't aware, we shouldn't edit this yaml file. It is automatically generated by the bin/rails rswag:swaggerize command.

So in the future whenever we add swagger request specs or make edits to the swagger_helper.rb
then make sure to run the above swaggerize command to update the yaml. 😎

@@ -28,6 +28,11 @@ components:
properties:
message:
type: string
sign_out:
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

@@ -61,6 +66,30 @@ paths:
required:
- email
- password
"/api/v1/users/sign_out":
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

let(:casa_org) { create(:casa_org) }
let(:volunteer) { create(:volunteer, casa_org: casa_org) }
let(:api_credential) { create(:api_credential, user: volunteer) }
let(:refresh_token) { api_credential.return_new_refresh_token![: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.

Er, is this regenerating a refresh token a 2nd time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think when you create the api credential table for the first time, the token digest fields are nil - at least in dev environment and so that is why I created the seed file to populate them.

I also need the plain text refresh token to be passed in the authorization header for the sign out.

Copy link
Collaborator

@7riumph 7riumph left a comment

Choose a reason for hiding this comment

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

Looks good so far, as mentioned on the issues acceptance criteria and in our discussions. Still need to...

  1. Add the sign_in route to routes.rb ( session#destroy )
  2. Add a destroy function to the sessions_controller.rb using the revocation function(s) helper you made
  3. Address comments, test route with whatever you'd like to use though my preference is curl, then should lgtm 😎

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

Successfully merging this pull request may close these issues.

Endpoint /api/v1/users/sign_out revokes access token and refresh token on request
3 participants