omniauth-auth0 2.0.0 → 2.4.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.

Potentially problematic release.


This version of omniauth-auth0 might be problematic. Click here for more details.

data/README.md CHANGED
@@ -1,57 +1,70 @@
1
- [![Build Status](https://travis-ci.org/auth0/omniauth-auth0.svg)](https://travis-ci.org/auth0/omniauth-auth0)
2
-
3
1
  # OmniAuth Auth0
4
2
 
5
- This is the official [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating to [Auth0](https://auth0.com).
3
+ An [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating with [Auth0](https://auth0.com). This strategy is based on the [OmniAuth OAuth2](https://github.com/omniauth/omniauth-oauth2) strategy.
6
4
 
7
- ## Installing
5
+ > :warning: **Important security note:** This solution uses a 3rd party library with an unresolved [security issue(s)](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-9284). Please review the details of the vulnerability, including [Auth0](https://github.com/auth0/omniauth-auth0/issues/82 ) and other recommended [mitigations](https://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284), before implementing the solution.
8
6
 
9
- Add to your `Gemfile`:
7
+ [![CircleCI](https://img.shields.io/circleci/project/github/auth0/omniauth-auth0/master.svg)](https://circleci.com/gh/auth0/omniauth-auth0)
8
+ [![codecov](https://codecov.io/gh/auth0/omniauth-auth0/branch/master/graph/badge.svg)](https://codecov.io/gh/auth0/omniauth-auth0)
9
+ [![Gem Version](https://badge.fury.io/rb/omniauth-auth0.svg)](https://badge.fury.io/rb/omniauth-auth0)
10
+ [![MIT licensed](https://img.shields.io/dub/l/vibe-d.svg?style=flat)](https://github.com/auth0/omniauth-auth0/blob/master/LICENSE)
11
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0?ref=badge_shield)
10
12
 
11
- ```ruby
12
- gem 'omniauth-auth0'
13
- ```
13
+ ## Table of Contents
14
14
 
15
- Then `bundle install`.
15
+ - [Documentation](#documentation)
16
+ - [Installation](#installation)
17
+ - [Getting Started](#getting-started)
18
+ - [Contribution](#contribution)
19
+ - [Support + Feedback](#support--feedback)
20
+ - [Vulnerability Reporting](#vulnerability-reporting)
21
+ - [What is Auth0](#what-is-auth0)
22
+ - [License](#license)
16
23
 
17
- ## Usage
24
+ ## Documentation
18
25
 
19
- ### Rails
26
+ - [Ruby on Rails Quickstart](https://auth0.com/docs/quickstart/webapp/rails)
27
+ - [Sample projects](https://github.com/auth0-samples/auth0-rubyonrails-sample)
20
28
 
21
- ```ruby
22
- Rails.application.config.middleware.use OmniAuth::Builder do
23
- provider :auth0, ENV['AUTH0_CLIENT_ID'], ENV['AUTH0_CLIENT_SECRET'], ENV['AUTH0_DOMAIN']
24
- end
25
- ```
29
+ ## Installation
26
30
 
27
- Then to redirect to your tenant's hosted login page:
31
+ Add the following line to your `Gemfile`:
28
32
 
29
33
  ```ruby
30
- redirect_to '/auth/auth0'
34
+ gem 'omniauth-auth0'
31
35
  ```
32
36
 
33
- ### Sinatra
37
+ If you're using this strategy with Rails, also add the following for CSRF protection:
34
38
 
35
39
  ```ruby
36
- use OmniAuth::Builder do
37
- provider :auth0, ENV['AUTH0_CLIENT_ID'], ENV['AUTH0_CLIENT_SECRET'], ENV['AUTH0_DOMAIN']
38
- end
40
+ gem 'omniauth-rails_csrf_protection'
39
41
  ```
40
42
 
41
- Then to redirect to your tenant's hosted login page:
43
+ Then install:
42
44
 
43
- ```ruby
44
- redirect to('/auth/auth0')
45
+ ```bash
46
+ $ bundle install
45
47
  ```
46
48
 
47
- > You can customize your hosted login page in your [Auth0 Dashboard](https://manage.auth0.com/#/login_page)
49
+ See our [contributing guide](CONTRIBUTING.md) for information on local installation for development.
50
+
51
+ ## Getting Started
52
+
53
+ To start processing authentication requests, the following steps must be performed:
48
54
 
49
- ### Auth parameters
55
+ 1. Initialize the strategy
56
+ 2. Configure the callback controller
57
+ 3. Add the required routes
58
+ 4. Trigger an authentication request
50
59
 
51
- To send additional parameters during login you can specify them when you register the provider
60
+ All of these tasks and more are covered in our [Ruby on Rails Quickstart](https://auth0.com/docs/quickstart/webapp/rails).
61
+
62
+ ### Additional authentication parameters
63
+
64
+ To send additional parameters during login, you can specify them when you register the provider:
52
65
 
53
66
  ```ruby
54
- provider
67
+ provider
55
68
  :auth0,
56
69
  ENV['AUTH0_CLIENT_ID'],
57
70
  ENV['AUTH0_CLIENT_SECRET'],
@@ -59,85 +72,101 @@ provider
59
72
  {
60
73
  authorize_params: {
61
74
  scope: 'openid read:users write:order',
62
- audience: 'https://mydomain/api'
75
+ audience: 'https://mydomain/api',
76
+ max_age: 3600 # time in seconds authentication is valid
63
77
  }
64
78
  }
65
79
  ```
66
80
 
67
- that will tell it to send those parameters on every Auth request.
81
+ ... which will tell the strategy to send those parameters on every authentication request.
82
+
83
+ ### Authentication hash
68
84
 
69
- Or you can do it for a specific Auth request by adding them in the query parameter of the redirect url:
85
+ The Auth0 strategy will provide the standard OmniAuth hash attributes:
86
+
87
+ - `:provider` - the name of the strategy, in this case `auth0`
88
+ - `:uid` - the user identifier
89
+ - `:info` - the result of the call to `/userinfo` using OmniAuth standard attributes
90
+ - `:credentials` - tokens requested and data
91
+ - `:extra` - Additional info obtained from calling `/userinfo` in the `:raw_info` property
70
92
 
71
93
  ```ruby
72
- redirect_to '/auth/auth0?connection=google-oauth2'
94
+ {
95
+ :provider => 'auth0',
96
+ :uid => 'auth0|USER_ID',
97
+ :info => {
98
+ :name => 'John Foo',
99
+ :email => 'johnfoo@example.org',
100
+ :nickname => 'john',
101
+ :image => 'https://example.org/john.jpg'
102
+ },
103
+ :credentials => {
104
+ :token => 'ACCESS_TOKEN',
105
+ :expires_at => 1485373937,
106
+ :expires => true,
107
+ :refresh_token => 'REFRESH_TOKEN',
108
+ :id_token => 'JWT_ID_TOKEN',
109
+ :token_type => 'bearer',
110
+ },
111
+ :extra => {
112
+ :raw_info => {
113
+ :email => 'johnfoo@example.org',
114
+ :email_verified => 'true',
115
+ :name => 'John Foo',
116
+ :picture => 'https://example.org/john.jpg',
117
+ :user_id => 'auth0|USER_ID',
118
+ :nickname => 'john',
119
+ :created_at => '2014-07-15T17:19:50.387Z'
120
+ }
121
+ }
122
+ }
73
123
  ```
74
124
 
75
- ### Auth Hash
125
+ ### Query Parameter Options
76
126
 
77
- Auth0 strategy will have the standard OmniAuth hash attributes:
127
+ In some scenarios, you may need to pass specific query parameters to `/authorize`. The following parameters are available to enable this:
78
128
 
79
- - provider: the name of the strategy, in this case `auth0`
80
- - uid: the user identifier
81
- - info: the result of the call to /userinfo using OmniAuth standard attributes
82
- - credentials: Auth0 tokens, at least will have an access_token but can eventually have refresh_token and/or id_token
83
- - extra: Additional info obtained from calling /userinfo in the attribute `raw_info`
129
+ - `connection`
130
+ - `connection_scope`
131
+ - `prompt`
132
+ - `screen_hint` (only relevant to New Universal Login Experience)
84
133
 
85
- ```ruby
86
- {
87
- :provider => 'auth0',
88
- :uid => 'google-oauth2|this-is-the-google-id',
89
- :info => {
90
- :name => 'John Foo',
91
- :email => 'johnfoo@example.org',
92
- :nickname => 'john',
93
- :image => 'https://example.org/john.jpg'
94
- },
95
- :credentials => {
96
- :token => 'XdDadllcas2134rdfdsI',
97
- :expires_at => 1485373937,
98
- :expires => true,
99
- :refresh_token => 'aKNajdjfj123nBasd',
100
- :id_token => 'eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJuYW1lIjoiSm9obiBGb28ifQ.lxAiy1rqve8ZHQEQVehUlP1sommPHVJDhgPgFPnDosg',
101
- :token_type => 'bearer',
102
- },
103
- :extra => {
104
- :raw_info => {
105
- :email => 'johnfoo@example.org',
106
- :email_verified => 'true',
107
- :name => 'John Foo',
108
- :picture => 'https://example.org/john.jpg',
109
- :user_id => 'google-oauth2|this-is-the-google-id',
110
- :nickname => 'john',
111
- :created_at: '2014-07-15T17:19:50.387Z'
112
- }
113
- }
114
- }
115
- ```
134
+ Simply pass these query parameters to your OmniAuth redirect endpoint to enable their behavior.
116
135
 
117
- ### ActionDispatch::Cookies::CookieOverflow issue
136
+ ## Contribution
118
137
 
119
- If you are getting this error it means that you are using Cookie sessions and since you are storing the whole profile it overflows the max-size of 4K.
138
+ We appreciate feedback and contribution to this repo! Before you get started, please see the following:
120
139
 
121
- You can change to use In-Memory store for development as follows:
140
+ - [Auth0's contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
141
+ - [Auth0's Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
142
+ - [This repo's contribution guide](CONTRIBUTING.md)
122
143
 
123
- # /config/initializers/session_store.rb
124
- CrazyApp::Application.config.session_store :cache_store
144
+ ## Support + Feedback
125
145
 
126
- # /config/environments/development.rb
127
- config.cache_store = :memory_store
146
+ - Use [Community](https://community.auth0.com/) for usage, questions, specific cases.
147
+ - Use [Issues](https://github.com/auth0/omniauth-auth0/issues) here for code-level support and bug reports.
148
+ - Paid customers can use [Support](https://support.auth0.com/) to submit a trouble ticket for production-affecting issues.
128
149
 
129
- ## Documentation
150
+ ## Vulnerability Reporting
130
151
 
131
- For more information about [auth0](http://auth0.com) contact our [documentation page](http://docs.auth0.com/).
152
+ Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
132
153
 
133
- ## Issue Reporting
154
+ ## What is Auth0?
134
155
 
135
- If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
156
+ Auth0 helps you to easily:
136
157
 
137
- ## Author
158
+ - implement authentication with multiple identity providers, including social (e.g., Google, Facebook, Microsoft, LinkedIn, GitHub, Twitter, etc), or enterprise (e.g., Windows Azure AD, Google Apps, Active Directory, ADFS, SAML, etc.)
159
+ - log in users with username/password databases, passwordless, or multi-factor authentication
160
+ - link multiple user accounts together
161
+ - generate signed JSON Web Tokens to authorize your API calls and flow the user identity securely
162
+ - access demographics and analytics detailing how, when, and where users are logging in
163
+ - enrich user profiles from other data sources using customizable JavaScript rules
138
164
 
139
- [Auth0](https://auth0.com)
165
+ [Why Auth0?](https://auth0.com/why-auth0)
140
166
 
141
167
  ## License
142
168
 
143
- This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.
169
+ The OmniAuth Auth0 strategy is licensed under MIT - [LICENSE](LICENSE)
170
+
171
+
172
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0?ref=badge_large)
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  RuboCop::RakeTask.new
11
11
  rescue LoadError
12
12
  task :rubocop do
13
- $stderr.puts 'Rubocop is disabled'
13
+ warn 'Rubocop is disabled'
14
14
  end
15
15
  end
16
16
 
@@ -23,7 +23,7 @@ namespace :sinatra do
23
23
  end
24
24
 
25
25
  desc 'Run specs'
26
- task default: [:spec, :rubocop]
26
+ task default: %i[spec rubocop]
27
27
  task test: :spec
28
28
  task :guard do
29
29
  system 'bundle exec guard'
@@ -0,0 +1,22 @@
1
+ coverage:
2
+ precision: 2
3
+ round: down
4
+ range: "60...100"
5
+ status:
6
+ project:
7
+ default:
8
+ enabled: true
9
+ target: auto
10
+ threshold: 5%
11
+ if_no_uploads: error
12
+ patch:
13
+ default:
14
+ enabled: true
15
+ target: 80%
16
+ threshold: 30%
17
+ if_no_uploads: error
18
+ changes:
19
+ default:
20
+ enabled: true
21
+ if_no_uploads: error
22
+ comment: false
@@ -1,2 +1,2 @@
1
- require 'omniauth-auth0/version' # rubocop:disable Style/FileName
1
+ require 'omniauth-auth0/version'
2
2
  require 'omniauth/strategies/auth0'
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Auth0
3
- VERSION = '2.0.0'.freeze
3
+ VERSION = '2.4.0'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,11 @@
1
+ module OmniAuth
2
+ module Auth0
3
+ class TokenValidationError < StandardError
4
+ attr_reader :error_reason
5
+ def initialize(msg)
6
+ @error_reason = msg
7
+ super(msg)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,228 @@
1
+ require 'base64'
2
+ require 'uri'
3
+ require 'json'
4
+ require 'omniauth'
5
+ require 'omniauth/auth0/errors'
6
+
7
+ module OmniAuth
8
+ module Auth0
9
+ # JWT Validator class
10
+ class JWTValidator
11
+ attr_accessor :issuer, :domain
12
+
13
+ # Initializer
14
+ # @param options object
15
+ # options.domain - Application domain.
16
+ # options.issuer - Application issuer (optional).
17
+ # options.client_id - Application Client ID.
18
+ # options.client_secret - Application Client Secret.
19
+
20
+ def initialize(options, authorize_params = {})
21
+ @domain = uri_string(options.domain)
22
+
23
+ # Use custom issuer if provided, otherwise use domain
24
+ @issuer = @domain
25
+ @issuer = uri_string(options.issuer) if options.respond_to?(:issuer)
26
+
27
+ @client_id = options.client_id
28
+ @client_secret = options.client_secret
29
+ end
30
+
31
+ def verify_signature(jwt)
32
+ head = token_head(jwt)
33
+
34
+ # Make sure the algorithm is supported and get the decode key.
35
+ if head[:alg] == 'RS256'
36
+ [rs256_decode_key(head[:kid]), head[:alg]]
37
+ elsif head[:alg] == 'HS256'
38
+ [@client_secret, head[:alg]]
39
+ else
40
+ raise OmniAuth::Auth0::TokenValidationError.new("Signature algorithm of #{head[:alg]} is not supported. Expected the ID token to be signed with RS256 or HS256")
41
+ end
42
+ end
43
+
44
+ # Verify a JWT.
45
+ # @param jwt string - JWT to verify.
46
+ # @param authorize_params hash - Authorization params to verify on the JWT
47
+ # @return hash - The verified token, if there were no exceptions.
48
+ def verify(jwt, authorize_params = {})
49
+ if !jwt
50
+ raise OmniAuth::Auth0::TokenValidationError.new('ID token is required but missing')
51
+ end
52
+
53
+ parts = jwt.split('.')
54
+ if parts.length != 3
55
+ raise OmniAuth::Auth0::TokenValidationError.new('ID token could not be decoded')
56
+ end
57
+
58
+ key, alg = verify_signature(jwt)
59
+ id_token, header = JWT.decode(jwt, key, false)
60
+ verify_claims(id_token, authorize_params)
61
+
62
+ return id_token
63
+ end
64
+
65
+ # Get the decoded head segment from a JWT.
66
+ # @return hash - The parsed head of the JWT passed, empty hash if not.
67
+ def token_head(jwt)
68
+ jwt_parts = jwt.split('.')
69
+ return {} if blank?(jwt_parts) || blank?(jwt_parts[0])
70
+
71
+ json_parse(Base64.decode64(jwt_parts[0]))
72
+ end
73
+
74
+ # Get the JWKS from the issuer and return a public key.
75
+ # @param x5c string - X.509 certificate chain from a JWKS.
76
+ # @return key - The X.509 certificate public key.
77
+ def jwks_public_cert(x5c)
78
+ x5c = Base64.decode64(x5c)
79
+
80
+ # https://docs.ruby-lang.org/en/2.4.0/OpenSSL/X509/Certificate.html
81
+ OpenSSL::X509::Certificate.new(x5c).public_key
82
+ end
83
+
84
+ # Return a specific key from a JWKS object.
85
+ # @param key string - Key to find in the JWKS.
86
+ # @param kid string - Key ID to identify the right JWK.
87
+ # @return nil|string
88
+ def jwks_key(key, kid)
89
+ return nil if blank?(jwks[:keys])
90
+
91
+ matching_jwk = jwks[:keys].find { |jwk| jwk[:kid] == kid }
92
+ matching_jwk[key] if matching_jwk
93
+ end
94
+
95
+ private
96
+ def rs256_decode_key(kid)
97
+ jwks_x5c = jwks_key(:x5c, kid)
98
+
99
+ if jwks_x5c.nil?
100
+ raise OmniAuth::Auth0::TokenValidationError.new("Could not find a public key for Key ID (kid) '#{kid}''")
101
+ end
102
+
103
+ jwks_public_cert(jwks_x5c.first)
104
+ end
105
+
106
+ # Get a JWKS from the domain
107
+ # @return void
108
+ def jwks
109
+ jwks_uri = URI(@domain + '.well-known/jwks.json')
110
+ @jwks ||= json_parse(Net::HTTP.get(jwks_uri))
111
+ end
112
+
113
+ # Rails Active Support blank method.
114
+ # @param obj object - Object to check for blankness.
115
+ # @return boolean
116
+ def blank?(obj)
117
+ obj.respond_to?(:empty?) ? obj.empty? : !obj
118
+ end
119
+
120
+ # Parse JSON with symbolized names.
121
+ # @param json string - JSON to parse.
122
+ # @return hash
123
+ def json_parse(json)
124
+ JSON.parse(json, symbolize_names: true)
125
+ end
126
+
127
+ # Parse a URI into the desired string format
128
+ # @param uri - the URI to parse
129
+ # @return string
130
+ def uri_string(uri)
131
+ temp_domain = URI(uri)
132
+ temp_domain = URI("https://#{uri}") unless temp_domain.scheme
133
+ "#{temp_domain}/"
134
+ end
135
+
136
+ def verify_claims(id_token, authorize_params)
137
+ leeway = authorize_params[:leeway] || 60
138
+ max_age = authorize_params[:max_age]
139
+ nonce = authorize_params[:nonce]
140
+
141
+ verify_iss(id_token)
142
+ verify_sub(id_token)
143
+ verify_aud(id_token)
144
+ verify_expiration(id_token, leeway)
145
+ verify_iat(id_token)
146
+ verify_nonce(id_token, nonce)
147
+ verify_azp(id_token)
148
+ verify_auth_time(id_token, leeway, max_age)
149
+ end
150
+
151
+ def verify_iss(id_token)
152
+ issuer = id_token['iss']
153
+ if !issuer
154
+ raise OmniAuth::Auth0::TokenValidationError.new("Issuer (iss) claim must be a string present in the ID token")
155
+ elsif @issuer != issuer
156
+ raise OmniAuth::Auth0::TokenValidationError.new("Issuer (iss) claim mismatch in the ID token, expected (#{@issuer}), found (#{id_token['iss']})")
157
+ end
158
+ end
159
+
160
+ def verify_sub(id_token)
161
+ subject = id_token['sub']
162
+ if !subject || !subject.is_a?(String) || subject.empty?
163
+ raise OmniAuth::Auth0::TokenValidationError.new('Subject (sub) claim must be a string present in the ID token')
164
+ end
165
+ end
166
+
167
+ def verify_aud(id_token)
168
+ audience = id_token['aud']
169
+ if !audience || !(audience.is_a?(String) || audience.is_a?(Array))
170
+ raise OmniAuth::Auth0::TokenValidationError.new("Audience (aud) claim must be a string or array of strings present in the ID token")
171
+ elsif audience.is_a?(Array) && !audience.include?(@client_id)
172
+ raise OmniAuth::Auth0::TokenValidationError.new("Audience (aud) claim mismatch in the ID token; expected #{@client_id} but was not one of #{audience.join(', ')}")
173
+ elsif audience.is_a?(String) && audience != @client_id
174
+ raise OmniAuth::Auth0::TokenValidationError.new("Audience (aud) claim mismatch in the ID token; expected #{@client_id} but found #{audience}")
175
+ end
176
+ end
177
+
178
+ def verify_expiration(id_token, leeway)
179
+ expiration = id_token['exp']
180
+ if !expiration || !expiration.is_a?(Integer)
181
+ raise OmniAuth::Auth0::TokenValidationError.new("Expiration time (exp) claim must be a number present in the ID token")
182
+ elsif expiration <= Time.now.to_i - leeway
183
+ raise OmniAuth::Auth0::TokenValidationError.new("Expiration time (exp) claim error in the ID token; current time (#{Time.now}) is after expiration time (#{Time.at(expiration + leeway)})")
184
+ end
185
+ end
186
+
187
+ def verify_iat(id_token)
188
+ if !id_token['iat']
189
+ raise OmniAuth::Auth0::TokenValidationError.new("Issued At (iat) claim must be a number present in the ID token")
190
+ end
191
+ end
192
+
193
+ def verify_nonce(id_token, nonce)
194
+ if nonce
195
+ received_nonce = id_token['nonce']
196
+ if !received_nonce
197
+ raise OmniAuth::Auth0::TokenValidationError.new("Nonce (nonce) claim must be a string present in the ID token")
198
+ elsif nonce != received_nonce
199
+ raise OmniAuth::Auth0::TokenValidationError.new("Nonce (nonce) claim value mismatch in the ID token; expected (#{nonce}), found (#{received_nonce})")
200
+ end
201
+ end
202
+ end
203
+
204
+ def verify_azp(id_token)
205
+ audience = id_token['aud']
206
+ if audience.is_a?(Array) && audience.length > 1
207
+ azp = id_token['azp']
208
+ if !azp || !azp.is_a?(String)
209
+ raise OmniAuth::Auth0::TokenValidationError.new("Authorized Party (azp) claim must be a string present in the ID token when Audience (aud) claim has multiple values")
210
+ elsif azp != @client_id
211
+ raise OmniAuth::Auth0::TokenValidationError.new("Authorized Party (azp) claim mismatch in the ID token; expected (#{@client_id}), found (#{azp})")
212
+ end
213
+ end
214
+ end
215
+
216
+ def verify_auth_time(id_token, leeway, max_age)
217
+ if max_age
218
+ auth_time = id_token['auth_time']
219
+ if !auth_time || !auth_time.is_a?(Integer)
220
+ raise OmniAuth::Auth0::TokenValidationError.new("Authentication Time (auth_time) claim must be a number present in the ID token when Max Age (max_age) is specified")
221
+ elsif Time.now.to_i > auth_time + max_age + leeway;
222
+ raise OmniAuth::Auth0::TokenValidationError.new("Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (#{Time.now}) is after last auth time (#{Time.at(auth_time + max_age + leeway)})")
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end