anycable-rails-jwt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7e38b60305bc5b61376f47a37f89c09e1abb328e9c8df059cce318db9442f8e2
4
+ data.tar.gz: 077eadd6f914cfa06076dbf8b58ae7884ca24d760a4184b8433301ba7e453cc4
5
+ SHA512:
6
+ metadata.gz: b12e6a72e8fa9564922875b30df8842a4d46d5609c19ebbe74d85ce95dac9d05f127c29ebdea32fd818c20b26b31b80de32b5c18384f4265dcd50a87ee6d893f
7
+ data.tar.gz: 2f2475a62ffd70990edd0e9936c39a883285a77582804f7a15a02fcb38add534320e4245ed894b62994b272f5db0fd77a3706ec1dcc502f31532632a96b25fe2
data/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Change log
2
+
3
+ ## master
4
+
5
+ ## 0.1.0 (2020-09-23)
6
+
7
+ - Initial version.
8
+
9
+ [@palkan]: https://github.com/palkan
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2021 Vladimir Dementyev
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ [![Gem Version](https://badge.fury.io/rb/anycable-rails-jwt.svg)](https://rubygems.org/gems/anycable-rails-jwt)
2
+ [![Build](https://github.com/anycable/anycable-rails-jwt/workflows/Build/badge.svg)](https://github.com/anycable/anycable-rails-jwt/actions)
3
+
4
+ # Anycable Rails JWT
5
+
6
+ AnyCable Rails helpers for [JWT-based identification](https://docs.anycable.io/anycable-go/jwt_identification) from [AnyCable PRO][pro].
7
+
8
+ ## Installation
9
+
10
+ Add gem to your project:
11
+
12
+ ```ruby
13
+ # Gemfile
14
+ gem "anycable-rails-jwt"
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Configuration
20
+
21
+ This gem extends AnyCable configuration and adds the following new parameters:
22
+
23
+ - `jwt_id_key`: JWT encryption key used to sign tokens (required).
24
+ - `jwt_id_param`: the name of the query string parameter to carry tokens (defaults to `jid`).
25
+ - `jwt_id_ttl`: the number of seconds for a token to live (defaults to 3600, one hour).
26
+
27
+ You can specify these parameters in `config/anycable.yml`, credentials, ENV or whatever source of configuration you use for AnyCable.
28
+
29
+ ### `action_cable_with_jwt_meta_tag`
30
+
31
+ In order to generate a token and pass it to a client, you can use an HTML meta tag similar to the built-in `#action_cable_meta_tag`:
32
+
33
+ ```erb
34
+ <%= action_cable_with_jwt_meta_tag(current_user: current_user) %> would render:
35
+ # => <meta name="action-cable-url" content="ws://demo.anycable.io/cable?token=eyJhbGciOiJIUzI1NiJ9....EWCEzziOx3sKyMoNzBt20a3QvhEdxJXCXaZsA-f-UzU" />
36
+ ```
37
+
38
+ You must pass all the required identifiers you have in your `ApplicationCable::Connection` class.
39
+
40
+ ### `AnyCable::Rails::JWT.encode`
41
+
42
+ Alternatively, you can generate a token and deliver it to a client the way you prefer. For that, you can use `AnyCable::Rails::JWT.encode` method:
43
+
44
+ ```ruby
45
+ AnyCable::Rails::JWT.encode(current_user: current_user) #=> <token>
46
+
47
+ # you can also override the global TTL setting via expires_at option
48
+ AnyCable::Rails::JWT.encode(current_user: current_user, expires_at: 10.minutes.from_now)
49
+ ```
50
+
51
+ ### Decoding tokens and using without AnyCable
52
+
53
+ Although the main purpose of this library is to add AnyCable PRO identification support, it's possible to use JWT-based authentication without AnyCable at all. For that, you can do something like this in your `ApplicationCable::Connection` class:
54
+
55
+ ```ruby
56
+ module ApplicationCable
57
+ class Connection < ActionCable::Connection::Base
58
+ identified_by :current_user
59
+
60
+ def connect
61
+ token = request.params[:token]
62
+
63
+ identifiers = AnyCable::Rails::JWT.decode(token)
64
+ identifiers.each do |k, v|
65
+ public_send("#{k}=", v)
66
+ end
67
+ rescue JWT::DecodeError
68
+ reject_unauthorized_connection
69
+ end
70
+ end
71
+ end
72
+ ```
73
+
74
+ ## Contributing
75
+
76
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/anycable/anycable-rails-jwt](https://github.com/anycable/anycable-rails-jwt).
77
+
78
+ ## License
79
+
80
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
81
+
82
+ [pro]: https://anycable.io/#pro
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "anycable/config"
4
+ # Make sure Rails extensions for Anyway Config are loaded
5
+ # See https://github.com/anycable/anycable-rails/issues/63
6
+ require "anyway/rails"
7
+
8
+ # Extend AnyCable configuration with jwt_id_key, jwt_id_param, jwt_id_ttl.
9
+ AnyCable::Config.attr_config(
10
+ :jwt_id_key,
11
+ jwt_id_param: "jid",
12
+ jwt_id_ttl: 3600
13
+ )
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module AnyCable
6
+ module Rails
7
+ module JWT # :nodoc:
8
+ module Helper
9
+ def action_cable_with_jwt_meta_tag(**identifiers)
10
+ # From: https://github.com/rails/rails/blob/main/actioncable/lib/action_cable/helpers/action_cable_helper.rb
11
+ base_url = ActionCable.server.config.url ||
12
+ ActionCable.server.config.mount_path ||
13
+ raise("No Action Cable URL configured -- please configure this at config.action_cable.url")
14
+
15
+ token = JWT.encode(**identifiers)
16
+
17
+ parts = [base_url, "#{AnyCable.config.jwt_id_param}=#{token}"]
18
+
19
+ uri = URI.parse(base_url)
20
+
21
+ url = parts.join(uri.query ? "&" : "?")
22
+
23
+ tag "meta", name: "action-cable-url", content: url
24
+ end
25
+
26
+ def any_cable_jwt_meta_tag(**identifiers)
27
+ token = JWT.encode(**identifiers)
28
+
29
+ tag "meta", name: "any-cable-jwt", content: token
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "anycable/rails/jwt/helper"
4
+
5
+ module AnyCable
6
+ module Rails
7
+ module JWT # :nodoc:
8
+ class Railtie < ::Rails::Railtie # :nodoc:
9
+ initializer "anycable_rails_jwt.helpers" do
10
+ ActiveSupport.on_load(:action_view) do
11
+ include AnyCable::Rails::JWT::Helper
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCable
4
+ module Rails
5
+ module JWT # :nodoc:
6
+ VERSION = "0.1.0"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jwt"
4
+ require "json"
5
+ require "anycable-rails"
6
+
7
+ require "anycable/rails/jwt/version"
8
+ require "anycable/rails/jwt/config"
9
+
10
+ module AnyCable
11
+ module Rails
12
+ module JWT
13
+ ALGORITHM = "HS256"
14
+
15
+ class << self
16
+ def encode(expires_at: nil, **identifiers)
17
+ key = AnyCable.config.jwt_id_key
18
+ raise ArgumentError, "JWT encryption key is not specified. Add it via `jwt_id_key` option" if key.blank?
19
+
20
+ expires_at ||= AnyCable.config.jwt_id_ttl.seconds.from_now
21
+
22
+ serialized_ids = identifiers.transform_values { |v| AnyCable::Rails.serialize(v) }
23
+
24
+ payload = {ext: serialized_ids.to_json, exp: expires_at.to_i}
25
+
26
+ ::JWT.encode(payload, key, ALGORITHM)
27
+ end
28
+
29
+ def decode(token)
30
+ key = AnyCable.config.jwt_id_key
31
+ raise ArgumentError, "JWT encryption key is not specified. Add it via `jwt_id_key` option" if key.blank?
32
+
33
+ ::JWT.decode(token, key, true, {algorithm: ALGORITHM}).then do |decoded|
34
+ JSON.parse(decoded.first.fetch("ext"))
35
+ end.then do |serialized_ids|
36
+ serialized_ids.transform_values! { |v| AnyCable::Rails.deserialize(v) }
37
+ serialized_ids
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ require "anycable/rails/jwt/railtie" if defined?(Rails::Railtie)
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: anycable-rails-jwt
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Vladimir Dementyev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-09-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: anycable-rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: jwt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '1.15'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '1.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: combustion
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '4.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '4.0'
97
+ description: AnyCable Rails helpers for JWT-based authentication
98
+ email:
99
+ - dementiev.vm@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - CHANGELOG.md
105
+ - LICENSE.txt
106
+ - README.md
107
+ - lib/anycable-rails-jwt.rb
108
+ - lib/anycable/rails/jwt/config.rb
109
+ - lib/anycable/rails/jwt/helper.rb
110
+ - lib/anycable/rails/jwt/railtie.rb
111
+ - lib/anycable/rails/jwt/version.rb
112
+ homepage: http://github.com/anycable/anycable-rails-jwt
113
+ licenses:
114
+ - MIT
115
+ metadata:
116
+ bug_tracker_uri: http://github.com/anycable/anycable-rails-jwt/issues
117
+ changelog_uri: https://github.com/anycable/anycable-rails-jwt/blob/master/CHANGELOG.md
118
+ documentation_uri: http://github.com/anycable/anycable-rails-jwt
119
+ homepage_uri: http://github.com/anycable/anycable-rails-jwt
120
+ source_code_uri: http://github.com/anycable/anycable-rails-jwt
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '2.6'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubygems_version: 3.2.15
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: AnyCable Rails helpers for JWT-based authentication
140
+ test_files: []