jwt_api 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -2
- data/README.md +1 -1
- data/jwt_api-0.1.0.gem +0 -0
- data/lib/generators/jwt_api/templates/api/base_controller.rb +16 -14
- data/lib/generators/jwt_api/templates/api/v1/authentication_controller.rb +5 -4
- data/lib/generators/jwt_api/templates/api/v1/passwords_controller.rb +16 -20
- data/lib/generators/jwt_api/templates/api/v1/users_controller.rb +1 -0
- data/lib/generators/jwt_api/templates/initializers/json_web_token.rb +12 -6
- data/lib/jwt_api/version.rb +1 -1
- data/lib/jwt_api.rb +0 -29
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b98af57b80db1d208e37fea555f8840b0ef28d975b450e3d4913e5b43b90e49c
|
4
|
+
data.tar.gz: 37ab658dbc48fcaf0dc6fa332f64f85a5a16a654a1b603855df72d4d00d049f1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 325cb78e50548492bf4537a0b89b59e2c8bf9541481b9fc75dad97174251b0e2a7697ef5b8183dc67461375614a8fe22f576a8262df63db63116c0a65be04a54
|
7
|
+
data.tar.gz: 32143ac809d4b48c0b0afdd0274c04061f4fd0b094c8e35179d59515a0aecbfa5eabd0bb4a0fbf259f95d3e75387bb789741ffd8cd809de412ada9b8fa78db27
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
jwt_api (0.1.
|
4
|
+
jwt_api (0.1.1)
|
5
5
|
jwt (~> 2.2, >= 2.2.3)
|
6
6
|
|
7
7
|
GEM
|
@@ -25,13 +25,14 @@ GEM
|
|
25
25
|
rspec-support (3.10.2)
|
26
26
|
|
27
27
|
PLATFORMS
|
28
|
+
arm64-darwin-21
|
28
29
|
x86_64-darwin-20
|
29
30
|
|
30
31
|
DEPENDENCIES
|
31
32
|
jwt (~> 2.2, >= 2.2.3)
|
32
33
|
jwt_api!
|
33
34
|
rake (~> 13.0)
|
34
|
-
rspec
|
35
|
+
rspec
|
35
36
|
|
36
37
|
BUNDLED WITH
|
37
38
|
2.2.25
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ Running via Spring preloader in process 56250
|
|
51
51
|
== 20210827123255 AddJtiToUsers: migrated (0.0259s) ===========================
|
52
52
|
```
|
53
53
|
|
54
|
-
|
54
|
+
|
55
55
|
## Usage
|
56
56
|
|
57
57
|
1. Make sure that each user that needs access to the API has a JTI generated.
|
data/jwt_api-0.1.0.gem
ADDED
Binary file
|
@@ -8,11 +8,7 @@ class Api::BaseController < ApplicationController
|
|
8
8
|
protected
|
9
9
|
|
10
10
|
def authenticate_request!
|
11
|
-
|
12
|
-
render json: { errors: ['Unauthorized'] }, status: :unauthorized
|
13
|
-
return
|
14
|
-
end
|
15
|
-
@current_user = User.find(auth_token[:user_id])
|
11
|
+
user_id_in_token?
|
16
12
|
rescue JWT::VerificationError, JWT::DecodeError
|
17
13
|
render json: { errors: ['Unauthorized'] }, status: :unauthorized
|
18
14
|
end
|
@@ -20,27 +16,33 @@ class Api::BaseController < ApplicationController
|
|
20
16
|
private
|
21
17
|
|
22
18
|
def http_token
|
23
|
-
@http_token ||= if request.headers['Authorization'].present?
|
24
|
-
request.headers['Authorization'].split.last
|
25
|
-
end
|
19
|
+
@http_token ||= (request.headers['Authorization'].split.last if request.headers['Authorization'].present?)
|
26
20
|
end
|
27
21
|
|
28
22
|
def auth_token
|
29
|
-
@auth_token ||=
|
30
|
-
|
31
|
-
|
23
|
+
@auth_token ||= jwt.decode(http_token)[0].to_h.symbolize_keys!
|
24
|
+
return nil if token_expired?
|
25
|
+
return @auth_token if @auth_token.present? && @auth_token[:user_id].present? && jti_matches?
|
26
|
+
end
|
27
|
+
|
28
|
+
def token_expired?
|
29
|
+
@auth_token[:exp] < Time.now.to_i
|
32
30
|
end
|
33
31
|
|
34
32
|
def jti_matches?
|
35
|
-
@current_user = User.find(auth_token[:user_id])
|
36
|
-
|
33
|
+
@current_user = User.find(@auth_token[:user_id])
|
34
|
+
@current_user&.jti == @auth_token[:jti]
|
37
35
|
end
|
38
36
|
|
39
37
|
def user_id_in_token?
|
40
|
-
http_token && auth_token
|
38
|
+
http_token && auth_token
|
41
39
|
end
|
42
40
|
|
43
41
|
def user_reset_token_in_params?
|
44
42
|
params[:reset_password_token]
|
45
43
|
end
|
44
|
+
|
45
|
+
def jwt
|
46
|
+
JsonWebToken.new
|
47
|
+
end
|
46
48
|
end
|
@@ -29,11 +29,12 @@ class Api::V1::AuthenticationController < Api::BaseController
|
|
29
29
|
|
30
30
|
iat = Time.now.to_i
|
31
31
|
exp = Time.now.to_i + 24 * 3600
|
32
|
+
|
32
33
|
{
|
33
|
-
token:
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
token: jwt.encode({ user_id: user.id,
|
35
|
+
jti: user.jti,
|
36
|
+
iat: iat,
|
37
|
+
exp: exp })
|
37
38
|
}
|
38
39
|
end
|
39
40
|
end
|
@@ -11,15 +11,14 @@ class Api::V1::PasswordsController < Api::BaseController
|
|
11
11
|
@user = User.find_by(email: password_params[:email])
|
12
12
|
if @user.nil?
|
13
13
|
render json: { message: 'email not found' }, status: :not_found
|
14
|
+
elsif @user.update(
|
15
|
+
reset_password_token: SecureRandom.uuid,
|
16
|
+
reset_password_sent_at: Time.now
|
17
|
+
)
|
18
|
+
JwtMailer.reset_password(@user.id, @user.reset_password_token).deliver
|
19
|
+
render json: { message: 'reset password instructions sent' }, status: :ok
|
14
20
|
else
|
15
|
-
@user.
|
16
|
-
@user.reset_password_sent_at = Time.now
|
17
|
-
if @user.save
|
18
|
-
JwtMailer.reset_password(@user.id, @user.reset_password_token).deliver
|
19
|
-
render json: { message: 'reset password instructions sent' }, status: :ok
|
20
|
-
else
|
21
|
-
render json: { message: @user.errors }, status: :not_found
|
22
|
-
end
|
21
|
+
render json: { message: @user.errors }, status: :not_found
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
@@ -27,25 +26,22 @@ class Api::V1::PasswordsController < Api::BaseController
|
|
27
26
|
# with a token in the params, if a succesful response is received, the client can
|
28
27
|
# store the newly issued JWT and redirect the user to the password reset form
|
29
28
|
def verify
|
30
|
-
@user = User.
|
29
|
+
@user = User.find_by(reset_password_token: params[:token])
|
31
30
|
if @user.nil?
|
32
31
|
render json: { message: 'reset password token not found' }, status: :not_found
|
33
|
-
elsif @user.reset_password_sent_at <
|
32
|
+
elsif @user.reset_password_sent_at < 10.minutes.ago
|
34
33
|
render json: { message: 'reset password token has expired' }, status: :not_found
|
35
34
|
else
|
36
|
-
@user.
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
iat = Time.now.to_i
|
42
|
-
exp = Time.now.to_i + 10 * 60
|
43
|
-
|
35
|
+
@user.update!(
|
36
|
+
reset_password_token: nil,
|
37
|
+
reset_password_sent_at: nil,
|
38
|
+
jti: SecureRandom.uuid
|
39
|
+
)
|
44
40
|
render json: {
|
45
41
|
token: JsonWebToken.encode({ user_id: @user.id,
|
46
42
|
jti: @user.jti,
|
47
|
-
iat:
|
48
|
-
exp:
|
43
|
+
iat: Time.now.to_i,
|
44
|
+
exp: Time.now.to_i + 10 * 60 })
|
49
45
|
}, status: :ok
|
50
46
|
end
|
51
47
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
# User controller
|
4
4
|
class Api::V1::UsersController < Api::BaseController
|
5
5
|
skip_before_action :authenticate_request!, only: %i[create]
|
6
|
+
|
6
7
|
def create
|
7
8
|
unless user_params[:password] == user_params[:password_confirmation]
|
8
9
|
return render json: { message: "passwords don't match" }, status: :unprocessable_entity
|
@@ -1,11 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# JSON Web Token class
|
1
4
|
class JsonWebToken
|
2
|
-
def
|
3
|
-
|
5
|
+
def initialize(key = Rails.application.credentials[:secret_key_base], algorithm = 'HS256')
|
6
|
+
@key = key
|
7
|
+
@algorithm = algorithm
|
8
|
+
end
|
9
|
+
|
10
|
+
def encode(payload)
|
11
|
+
JWT.encode(payload, @key, @algorithm)
|
4
12
|
end
|
5
13
|
|
6
|
-
def
|
7
|
-
|
8
|
-
rescue StandardError
|
9
|
-
nil
|
14
|
+
def decode(token)
|
15
|
+
JWT.decode(token, @key, @algorithm)
|
10
16
|
end
|
11
17
|
end
|
data/lib/jwt_api/version.rb
CHANGED
data/lib/jwt_api.rb
CHANGED
@@ -2,32 +2,3 @@
|
|
2
2
|
|
3
3
|
require 'jwt'
|
4
4
|
require_relative 'jwt_api/version'
|
5
|
-
|
6
|
-
module JwtApi
|
7
|
-
class Jwt
|
8
|
-
def initialize(key, algorithm = 'HS256')
|
9
|
-
@key = key
|
10
|
-
@algorithm = algorithm
|
11
|
-
end
|
12
|
-
|
13
|
-
def encode(payload)
|
14
|
-
JWT.encode(payload, @key, @algorithm)
|
15
|
-
end
|
16
|
-
|
17
|
-
def decode(token)
|
18
|
-
JWT.decode(token, @key, @algorithm)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class JsonWebToken
|
24
|
-
def self.encode(payload)
|
25
|
-
JWT.encode(payload, Rails.application.secrets.secret_key_base)
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.decode(token)
|
29
|
-
HashWithIndifferentAccess.new(JWT.decode(token, Rails.application.secrets.secret_key_base)[0])
|
30
|
-
rescue StandardError
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leo Policastro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- Rakefile
|
49
49
|
- bin/console
|
50
50
|
- bin/setup
|
51
|
+
- jwt_api-0.1.0.gem
|
51
52
|
- jwt_api.gemspec
|
52
53
|
- lib/generators/jwt_api/setup_generator.rb
|
53
54
|
- lib/generators/jwt_api/templates/api/base_controller.rb
|
@@ -83,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
83
84
|
- !ruby/object:Gem::Version
|
84
85
|
version: '0'
|
85
86
|
requirements: []
|
86
|
-
rubygems_version: 3.
|
87
|
+
rubygems_version: 3.3.3
|
87
88
|
signing_key:
|
88
89
|
specification_version: 4
|
89
90
|
summary: Write a short summary, because RubyGems requires one.
|