-
Notifications
You must be signed in to change notification settings - Fork 229
JWT authentication #70
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
Conversation
@wilddima I'll try to take a look at this soon. THings got away from me over the summer, and I'm trying to catch up. |
Thank you for great work! @wilddima
The response is like this:
Then, access to a limited page with @athix and @Ch4s3: This PR seems good, having looked over this PR and RFC and jwt-ruby, and used it in a sandbox SPA rails app. The function has great advance in an API authentication if it's merged. |
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 missed some potential improvements.
The 'no new line at end of file' must be fixed, but I would like to discuss the error response design.
end | ||
end | ||
end | ||
end |
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.
Need to set the new line.
end | ||
end | ||
end | ||
end |
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.
Need to set the new line.
def jwt_not_authenticated | ||
respond_to do |format| | ||
format.html { not_authenticated } | ||
format.json { render json: { status: 401 }, status: 401 } |
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.
IMO the message should not be the status code because it's verbose.
It would be better if the api response is like this (just an example)
format.json {
render json: {
"error": {
"message": "Need to login first.",
}
},
status: 401
}
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 also suggest you use status: :unauthorized
to make it more explicit.
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.
How about making this changeable, instead of hardcoding the return message
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's difficult to make an error message changeable because of the design. The cases are different when this method is called.
I use ruby-jwt error messages and I want it to be overridden if someone wants to change the message.
See this commit for details: ebihara99999@9e02135
@wilddima |
I'm interested in this as well. Please let me know if I can help. |
@Spone Thank you for saying that! I would appreciate it if you could review or give us feedbacks using this feature. |
I should be able to set aside time very soon to work on JWT, I'll take a look at this when I do. @Ch4s3 if you can set aside some time for this as well, I would like to get multiple eyes on something as big as this before releasing. |
I prepared for a request and system spec helper to login. Should I open a PR to the master or this branch? |
|
||
# This method creating JWT token by payload | ||
def jwt_encode(payload) | ||
JWT.encode(payload, Config.jwt_secret_key) |
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 should specify an algorithm to use, else the created JWT is unsigned!
See here: https://github.com/jwt/ruby-jwt#algorithms-and-usage
I think it should be a config option, with "HS256"
as its default value.
The same algorithm parameter has to be passed to JWT.decode
as well.
About the claims, I suggest adding by default:
Also, as I understand it, the user ID could be added as the See https://tools.ietf.org/html/rfc7519#section-4.1 for the full list and https://github.com/jwt/ruby-jwt#add-custom-header-fields for details about the |
Thanks for the review. I make it enable to configure claims in this commit: ebihara99999@4dde3c1 As for specifying an algorithm I will implement and open a PR if this PR keeps inactive. |
acc[val] = user.public_send(val) | ||
end | ||
{ Config.jwt_user_data_key => user_params, | ||
Config.jwt_auth_token_key => jwt_encode(user_params) } |
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 it's an idea to replace user_id with a jti (SecureRandom.uuid) and implement a whitelisting strategy to support login from multiple devices and independent logout. This implies that on login, a record is created in the whitelists table and that on logout this record gets deleted.
Also i'm missing expiration from this implementation. The generated jwt keys are valid indefinitely. The duration a key is persisted could be set from the config for instance.
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.
@jovanmaric I don't know why user_id
is here though the token includes user_id as the subject claim ( of course, it's needed to decode to acquire it ) .
I'd like to remove and only returns a token like eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjQyLCJleHAiOjE1NDc3MTkyMDAsImlhdCI6MTU0NzQ2MDAwMH0.QM5mTkYiDwI-10cEOq4b_bfrwe99BRuef6pnIB-jqIk
.
What do you think about it?
And I would appreciate it if @wilddima could answer why Config.jwt_user_data_key => user_params
is needed.
JWT.decode(token, Config.jwt_secret_key)[0] | ||
) | ||
rescue JWT::DecodeError | ||
nil |
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.
Shouldn't this be removed, considering that def jwt_require_auth
catches JWT::DecodeError, and omits an unauthorized_error?
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.
@jovanmaric
I agree with that and changed like this:
9e02135
def jwt_not_authenticated | ||
respond_to do |format| | ||
format.html { not_authenticated } | ||
format.json { render json: { status: 401 }, status: 401 } |
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.
How about making this changeable, instead of hardcoding the return message
@@ -23,6 +23,7 @@ Gem::Specification.new do |s| | |||
s.add_dependency 'oauth', '~> 0.4', '>= 0.4.4' | |||
s.add_dependency 'oauth2', '~> 1.0', '>= 0.8.0' | |||
s.add_dependency 'bcrypt', '~> 3.1' | |||
s.add_dependency 'jwt', '~> 1.5' |
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.
The latest is 2.1.0
Is there any eta on when this will be implemented? Considering that there is no defacto authentication gem which supports JWT. |
I went about combing Sorcery and Knock to accomplish SPA and SSR authentication. I'd like to take a stab at this. It looks like Knock is not being very actively developed. I have a PR open against that gem to be able to support rails in API mode but it's been stale for months. |
@andrewhood125 any help would be greatly appreciated! |
@andrewhood125 any luck? |
See the discussion here: Sorcery#70 (comment)
There is a suggestion that a message in the case not authenticated could be changeable in the discussion: Sorcery#70 (comment) But I decide to make use of a message sent from `JWT::DecodeError` because it's difficult to make the message flexible because of the design. Changes: - `#jwt_require_auth` only rescues `JWT::DecodeError` because JWT::VerificationError is a subclass. - `#jwt_decode` raises `JWT::DecodeError` or the error of the subclasses, and does not rescue in it. - `#jwt_not_authenticated` receives an argument `JWT::DecodeError` are from here: https://github.com/jwt/ruby-jwt/blob/master/lib/jwt/error.rb
`JWT::ExpiredSignature: Signature has expired` is expected when a token is expired. Review comment is: Sorcery#70 (comment)
the review comment is: Sorcery#70 (comment)
@athix Any updates? |
@TolichP Not at the moment unfortunately. If anyone from the community could help drive this effort, I would greatly appreciate the assistance. JWT would be a great addition, I just don't have time at the moment to drive it forward. |
Closing this out to reduce noise, see #239 and Sorcery/sorcery-rework#9 for the latest on JWT in Sorcery. |
Hi!
I implemented JWT authentication as module and tested it works capacity in my pet project(SPA with React). Maybe, configurations is looking complex, but i tried to give more flexibility for customization authentication. I also tried to write some documentation, but my english is not good enough for it.