devise-jwt-cookie2 0.6.0 → 0.7.0
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/README.md +15 -1
- data/lib/devise/jwt/cookie/middleware.rb +4 -0
- data/lib/devise/jwt/cookie/refresher.rb +42 -0
- data/lib/devise/jwt/cookie/strategy.rb +18 -1
- data/lib/devise/jwt/cookie/version.rb +1 -1
- data/lib/devise/jwt/cookie2.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 580f1a06dbf4da8cca7f50a859e03bbbc7694068fe378ab35a0c7b936d148581
|
|
4
|
+
data.tar.gz: 50a30ab8297ca621423dc54e0eebb103fc9c4d766f1af7a8c73f9bbbd96d234b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3f40e189895d93d6dea89dea6b663a3b488ffa20af27d171cb6e2f83e8fbd3e76e05da844a142a0bf80426078022ae6dd8431413064538e6b1554aba31df67f8
|
|
7
|
+
data.tar.gz: a59ad9854285ba3380bec8b0a1c9337c8b3c17dab4f66554a3b0843c9a11e270ee3f5ac30adc5541d7d43daa981175a405947c68e9b5f5229156463d07c506c8
|
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
Add this line to your application's Gemfile:
|
|
8
8
|
|
|
9
9
|
```ruby
|
|
10
|
-
gem 'devise-jwt-cookie2', '~> 0.
|
|
10
|
+
gem 'devise-jwt-cookie2', '~> 0.7.0'
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
And then execute:
|
|
@@ -66,3 +66,17 @@ The domain the cookie should be issued to. Will be omitted if not set.
|
|
|
66
66
|
#### same_site ([MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/Cookies#samesite))
|
|
67
67
|
|
|
68
68
|
Set's the SameSite attribute on the cookie. Defaults to `none`.
|
|
69
|
+
|
|
70
|
+
#### refresher
|
|
71
|
+
|
|
72
|
+
An object that renews the JWT while the cookie strategy authenticates a request. Defaults to `nil`, which never renews a token.
|
|
73
|
+
|
|
74
|
+
Set it to `Devise::JWT::Cookie::Refresher.new` to re-issue a still-valid token once it is past half its lifetime, so an active user's cookie slides forward instead of expiring:
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
config.jwt_cookie do |jwt_cookie|
|
|
78
|
+
jwt_cookie.refresher = Devise::JWT::Cookie::Refresher.new
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
A refresher responds to `call(token, scope, env)`, where `token` is the cookie's JWT (`nil` when the request has none), and returns a new JWT or `nil` to keep the current one. The strategy authenticates the request with the returned token and the middleware writes it to the cookie, unless the request revokes the token. Subclass `Refresher` to supply your own rules, such as recovering a session from a separate refresh credential after the JWT has expired, or capping a session's total lifetime. The private `issue(user, scope, aud)` helper encodes a token and calls the model's `on_jwt_dispatch`, so revocation strategies such as `Allowlist` record it.
|
|
@@ -6,6 +6,7 @@ module Devise
|
|
|
6
6
|
# Rack middleware to handle JWT token in cookies
|
|
7
7
|
class Middleware
|
|
8
8
|
ENV_KEY = 'warden-jwt_auth.token'
|
|
9
|
+
REFRESHED_TOKEN_KEY = 'devise-jwt-cookie.refreshed_token'
|
|
9
10
|
|
|
10
11
|
attr_reader :app, :config
|
|
11
12
|
|
|
@@ -30,6 +31,9 @@ module Devise
|
|
|
30
31
|
elsif token_should_be_revoked
|
|
31
32
|
name, cookie = CookieHelper.new.build(nil)
|
|
32
33
|
Rack::Utils.set_cookie_header!(headers, name, cookie)
|
|
34
|
+
elsif env[REFRESHED_TOKEN_KEY]
|
|
35
|
+
name, cookie = CookieHelper.new.build(env[REFRESHED_TOKEN_KEY])
|
|
36
|
+
Rack::Utils.set_cookie_header!(headers, name, cookie)
|
|
33
37
|
end
|
|
34
38
|
[status, headers, response]
|
|
35
39
|
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Devise
|
|
4
|
+
module JWT
|
|
5
|
+
module Cookie
|
|
6
|
+
# Default refresher: re-issues a still-valid JWT once it is past half its lifetime, so a user who
|
|
7
|
+
# keeps making requests never sees the cookie expire. Subclass it to apply your own session
|
|
8
|
+
# rules, such as recovering a session after the JWT has expired or capping its total lifetime.
|
|
9
|
+
#
|
|
10
|
+
# A refresher receives the cookie's token (nil when there is none), the Warden scope and the
|
|
11
|
+
# Rack env, and returns a new token to authenticate the request with, or nil to keep the
|
|
12
|
+
# current one. The middleware writes a returned token to the cookie.
|
|
13
|
+
class Refresher
|
|
14
|
+
def call(token, scope, env)
|
|
15
|
+
return if token.nil?
|
|
16
|
+
return unless renew?(Warden::JWTAuth::TokenDecoder.new.call(token))
|
|
17
|
+
|
|
18
|
+
aud = Warden::JWTAuth::EnvHelper.aud_header(env)
|
|
19
|
+
issue(Warden::JWTAuth::UserDecoder.new.call(token, scope, aud), scope, aud)
|
|
20
|
+
rescue ::JWT::DecodeError
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def renew?(payload)
|
|
27
|
+
issued_at, expires_at = payload.values_at('iat', 'exp')
|
|
28
|
+
return false unless issued_at && expires_at
|
|
29
|
+
|
|
30
|
+
Time.now.to_i >= issued_at + ((expires_at - issued_at) / 2)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Mirrors devise-jwt's dispatch hook, so revocation strategies such as Allowlist record the token.
|
|
34
|
+
def issue(user, scope, aud)
|
|
35
|
+
token, payload = Warden::JWTAuth::UserEncoder.new.call(user, scope, aud)
|
|
36
|
+
user.on_jwt_dispatch(token, payload) if user.respond_to?(:on_jwt_dispatch)
|
|
37
|
+
token
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -9,7 +9,7 @@ module Devise
|
|
|
9
9
|
# an http-only cookie
|
|
10
10
|
class Strategy < Warden::Strategies::Base
|
|
11
11
|
def valid?
|
|
12
|
-
!token.nil?
|
|
12
|
+
!token.nil? || !refresher.nil?
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def store?
|
|
@@ -17,6 +17,10 @@ module Devise
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def authenticate!
|
|
20
|
+
refresh
|
|
21
|
+
# Without a token there is nothing to reject, so other strategies still get a turn.
|
|
22
|
+
return if token.nil?
|
|
23
|
+
|
|
20
24
|
aud = Warden::JWTAuth::EnvHelper.aud_header(env)
|
|
21
25
|
user = Warden::JWTAuth::UserDecoder.new.call(token, scope, aud)
|
|
22
26
|
success!(user)
|
|
@@ -29,6 +33,19 @@ module Devise
|
|
|
29
33
|
def token
|
|
30
34
|
@token ||= CookieHelper.new.read_from(cookies)
|
|
31
35
|
end
|
|
36
|
+
|
|
37
|
+
def refresher
|
|
38
|
+
Cookie.config.refresher
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Warden re-runs a strategy that did not succeed or fail, so only ask the refresher once.
|
|
42
|
+
def refresh
|
|
43
|
+
return if @refreshed
|
|
44
|
+
|
|
45
|
+
@refreshed = true
|
|
46
|
+
refreshed_token = refresher&.call(token, scope, env)
|
|
47
|
+
env[Middleware::REFRESHED_TOKEN_KEY] = @token = refreshed_token if refreshed_token
|
|
48
|
+
end
|
|
32
49
|
end
|
|
33
50
|
end
|
|
34
51
|
end
|
data/lib/devise/jwt/cookie2.rb
CHANGED
|
@@ -24,6 +24,7 @@ module Devise
|
|
|
24
24
|
setting :httponly, default: true
|
|
25
25
|
setting :same_site, default: :none
|
|
26
26
|
setting :domain
|
|
27
|
+
setting :refresher
|
|
27
28
|
|
|
28
29
|
Import = Dry::AutoInject(config)
|
|
29
30
|
end
|
|
@@ -34,4 +35,5 @@ require 'devise/jwt/cookie/version'
|
|
|
34
35
|
require 'devise/jwt/cookie/railtie'
|
|
35
36
|
require 'devise/jwt/cookie/cookie_helper'
|
|
36
37
|
require 'devise/jwt/cookie/middleware'
|
|
38
|
+
require 'devise/jwt/cookie/refresher'
|
|
37
39
|
require 'devise/jwt/cookie/models'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: devise-jwt-cookie2
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Major League Hacking
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-10-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: devise-jwt
|
|
@@ -193,6 +193,7 @@ files:
|
|
|
193
193
|
- lib/devise/jwt/cookie/models.rb
|
|
194
194
|
- lib/devise/jwt/cookie/models/jwt_cookie_authenticatable.rb
|
|
195
195
|
- lib/devise/jwt/cookie/railtie.rb
|
|
196
|
+
- lib/devise/jwt/cookie/refresher.rb
|
|
196
197
|
- lib/devise/jwt/cookie/strategy.rb
|
|
197
198
|
- lib/devise/jwt/cookie/version.rb
|
|
198
199
|
- lib/devise/jwt/cookie2.rb
|