firebase-authentication 0.2.0 → 0.3.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/.rubocop.yml +3 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +6 -1
- data/lib/firebase/authentication/version.rb +1 -1
- data/lib/firebase/authentication.rb +116 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52f63a09db5325c16fef42a13e248799767c1b9378af29a029e4ed5e7532b004
|
4
|
+
data.tar.gz: da4d219fc4d98dabf25e86ec4944188dc8e45f00bb9182fb2dabd03866db797a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7051a16c7a466845d33617a9cf0b9ea1f9413d66fa0da1eb57d8a574e9d4360838ad4e976484862f9f377fcfdb761047a657236e7e66badc4545ba7b1fbc6c88
|
7
|
+
data.tar.gz: b4f2ba99ba8758e6e056df2f42787e211e230d25aedde1a76548b852e2ba336416c74bd9ae42e26c0eb92e73243d6b301c5c8fb2d478139e11e68243fc95d3e0
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
firebase-authentication (0.
|
4
|
+
firebase-authentication (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -70,6 +70,10 @@ GEM
|
|
70
70
|
concurrent-ruby (1.1.9)
|
71
71
|
crass (1.0.6)
|
72
72
|
diff-lcs (1.4.4)
|
73
|
+
dotenv (2.7.6)
|
74
|
+
dotenv-rails (2.7.6)
|
75
|
+
dotenv (= 2.7.6)
|
76
|
+
railties (>= 3.2)
|
73
77
|
erubi (1.10.0)
|
74
78
|
globalid (0.5.2)
|
75
79
|
activesupport (>= 5.0)
|
@@ -172,6 +176,7 @@ PLATFORMS
|
|
172
176
|
ruby
|
173
177
|
|
174
178
|
DEPENDENCIES
|
179
|
+
dotenv-rails
|
175
180
|
firebase-authentication!
|
176
181
|
jwt
|
177
182
|
rails (~> 6.1.4)
|
@@ -1,10 +1,123 @@
|
|
1
1
|
require_relative "authentication/version"
|
2
|
-
require_relative "authentication/config"
|
3
2
|
require_relative "authentication/service"
|
4
3
|
|
5
4
|
module Firebase
|
6
5
|
module Authentication
|
7
|
-
|
8
|
-
|
6
|
+
ALGORITHM = "RS256".freeze
|
7
|
+
ISSUER_BASE_URL = "https://securetoken.google.com/".freeze
|
8
|
+
CLIENT_CERT_URL = "https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com".freeze
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def verify(token)
|
12
|
+
Rails.logger.info "#{self.class.name}\##{__method__} called."
|
13
|
+
Rails.logger.info token
|
14
|
+
raise "id token must be a String" unless token.is_a?(String)
|
15
|
+
|
16
|
+
full_decoded_token = _decode_token(token)
|
17
|
+
|
18
|
+
err_msg = _validate_jwt(full_decoded_token)
|
19
|
+
raise err_msg if err_msg
|
20
|
+
|
21
|
+
public_key = _fetch_public_keys[full_decoded_token[:header]["kid"]]
|
22
|
+
unless public_key
|
23
|
+
raise 'Firebase ID token has "kid" claim which does not correspond to a known public key.'\
|
24
|
+
"Most likely the ID token is expired, so get a fresh token from your client app and try again."
|
25
|
+
end
|
26
|
+
|
27
|
+
certificate = OpenSSL::X509::Certificate.new(public_key)
|
28
|
+
decoded_token = _decode_token(token, certificate.public_key, verify: true, options: { algorithm: ALGORITHM, verify_iat: true })
|
29
|
+
|
30
|
+
{
|
31
|
+
"uid" => decoded_token[:payload]["sub"],
|
32
|
+
"decoded_token" => decoded_token
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_custom_token(uid, claims = {})
|
37
|
+
private_key = OpenSSL::PKey::RSA.new Global.firebase.private_key.gsub('\\n', "\n")
|
38
|
+
service_account_email = Global.firebase.client_email
|
39
|
+
now_seconds = Time.now.to_i
|
40
|
+
payload = { iss: service_account_email,
|
41
|
+
sub: service_account_email,
|
42
|
+
aud: "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
|
43
|
+
iat: now_seconds,
|
44
|
+
exp: now_seconds + (60 * 60),
|
45
|
+
uid: uid,
|
46
|
+
claims: claims }
|
47
|
+
JWT.encode payload, private_key, "RS256"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def _decode_token(token, key = nil, verify: false, options: {})
|
53
|
+
Rails.logger.info "#{self.class.name}\##{__method__} called."
|
54
|
+
begin
|
55
|
+
decoded_token = JWT.decode(token, key, verify, options)
|
56
|
+
rescue JWT::ExpiredSignature => e
|
57
|
+
raise "Firebase ID token has expired. Get a fresh token from your client app and try again. #{e.message}"
|
58
|
+
rescue JWT::InvalidAudError, JWT::DecodeError, JWT::VerificationError => e
|
59
|
+
raise "Firebase JWT Error. #{e.message}"
|
60
|
+
rescue StandardError => e
|
61
|
+
raise "Firebase ID token has invalid signature. #{e.message}"
|
62
|
+
end
|
63
|
+
|
64
|
+
{
|
65
|
+
payload: decoded_token[0],
|
66
|
+
header: decoded_token[1]
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def _fetch_public_keys
|
71
|
+
Rails.logger.info "#{self.class.name}\##{__method__} called."
|
72
|
+
uri = URI.parse(CLIENT_CERT_URL)
|
73
|
+
https = Net::HTTP.new(uri.host, uri.port)
|
74
|
+
https.use_ssl = true
|
75
|
+
|
76
|
+
res = https.start do
|
77
|
+
https.get(uri.request_uri)
|
78
|
+
end
|
79
|
+
data = JSON.parse(res.body)
|
80
|
+
|
81
|
+
if data["error"]
|
82
|
+
msg = "Error fetching public keys for Google certs: #{data["error"]}"
|
83
|
+
msg += " (#{res["error_description"]})" if data["error_description"]
|
84
|
+
|
85
|
+
raise msg
|
86
|
+
end
|
87
|
+
|
88
|
+
data
|
89
|
+
end
|
90
|
+
|
91
|
+
def _validate_jwt(json)
|
92
|
+
Rails.logger.info "#{self.class.name}\##{__method__} called."
|
93
|
+
error = _validate_jwt_header(json[:header])
|
94
|
+
error || _validate_jwt_payload(json[:payload])
|
95
|
+
end
|
96
|
+
|
97
|
+
def _validate_jwt_header(header)
|
98
|
+
Rails.logger.info "#{self.class.name}\##{__method__} called."
|
99
|
+
return 'Firebase ID token has no "kid" claim.' unless header["kid"]
|
100
|
+
|
101
|
+
return "Firebase ID token has incorrect algorithm. Expected \"#{ALGORITHM}\" but got \"#{header["alg"]}\"."\
|
102
|
+
unless header["alg"] == ALGORITHM
|
103
|
+
end
|
104
|
+
|
105
|
+
def _validate_jwt_payload(payload)
|
106
|
+
Rails.logger.info "#{self.class.name}\##{__method__} called."
|
107
|
+
project_id = ENV.fetch("FIREBASE_PROJECT_ID")
|
108
|
+
unless payload["aud"] == project_id
|
109
|
+
return "Firebase ID token has incorrect \'aud\' (audience) claim. Expected \"#{project_id}\" but got \"#{payload["aud"]}\"."
|
110
|
+
end
|
111
|
+
|
112
|
+
issuer = ISSUER_BASE_URL + project_id
|
113
|
+
unless payload["iss"] == issuer
|
114
|
+
return "Firebase ID token has incorrect \'iss\' (issuer) claim. Expected \"#{issuer}\" but got \"#{payload["iss"]}\"."
|
115
|
+
end
|
116
|
+
|
117
|
+
return 'Firebase ID token has no "sub" (subject) claim.' unless payload["sub"].is_a?(String)
|
118
|
+
return 'Firebase ID token has an empty string "sub" (subject) claim.' if payload["sub"].empty?
|
119
|
+
return 'Firebase ID token has "sub" (subject) claim longer than 128 characters.' if payload["sub"].size > 128
|
120
|
+
end
|
121
|
+
end
|
9
122
|
end
|
10
123
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: firebase-authentication
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- shuntagami
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|