omniauth-apple 1.0.2 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5e32b1f9b3dfe8859855b86ffdb6da18d238c0f065d2aa83fd8494ae49a3dc5
4
- data.tar.gz: bab7b98074c2a989120b1a7d3188a9ba85037c55956efc5e2e462373ed9d0d4f
3
+ metadata.gz: b0a0049edf786737a4acc4af68aeff8b8323a020822dfd530a01c0f8925cc1f1
4
+ data.tar.gz: 44d8cf583c85cb198f6dd5a9f7e593d5109335a78cc01ec7b32feaa69b449df0
5
5
  SHA512:
6
- metadata.gz: bce3e4e1a4feb3df68f3d2d5361a56e6977dfe765068b2bee6cef743a41f59212d1b533a1cdefbeb1eaebf8a7cf832dd0f53dbd080f4efa1311bd30942b7ea86
7
- data.tar.gz: c67ff848f44f6061c6f319db5a708e0e407977446252bea63af9e94799df2ce140c93dd7a5be5c1afbbdf3fdcdeafaeb7650cad4de199749d8edb436f21896e8
6
+ metadata.gz: ecc115718bb19ab99e6b15c05432b19ae73499a8b76f98e05e5cb0b45d61b61549a283709180d0df60b188e3c5db789a5d4c0cfe79d147014ca798df5ecc511a
7
+ data.tar.gz: eaa439dee2483186d09f0aa24e6e653118ca37545f01d074c098366c24daa8b355c8e24df1e0138e0fcd93efa0946a7ae9141c21e6cee7c3629941dbe59b2a65
@@ -6,21 +6,22 @@ on:
6
6
  - master
7
7
  pull_request:
8
8
 
9
+ permissions:
10
+ contents: read
11
+
9
12
  jobs:
10
- build:
13
+ spec:
11
14
  runs-on: ubuntu-latest
12
15
  strategy:
13
16
  fail-fast: false
14
17
  matrix:
15
- ruby: ['2.5', '2.6', '2.7']
18
+ ruby: ['2.6', '2.7', '3.0', '3.1']
16
19
  steps:
17
- - uses: actions/checkout@v2
18
- - name: Set up Ruby ${{ matrix.ruby }}
19
- uses: actions/setup-ruby@v1
20
+ - uses: actions/checkout@v3
21
+ - name: Set up Ruby
22
+ uses: ruby/setup-ruby@v1
20
23
  with:
21
24
  ruby-version: ${{ matrix.ruby }}
22
- - name: Build and test with Rake on Ruby ${{ matrix.ruby }}
23
- run: |
24
- gem install bundler
25
- bundle install --jobs 4 --retry 3
26
- bundle exec rake spec
25
+ bundler-cache: true
26
+ - name: Run Specs
27
+ run: bundle exec rake spec
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.2.2] - 2022-10-31
4
+
5
+ ### Fixed
6
+
7
+ - [#94](https://github.com/nhosoya/omniauth-apple/pull/98) handle fail! in correct way
8
+
9
+ ## [1.2.1] - 2022-10-25
10
+
11
+ ### Fixed
12
+
13
+ - [#94](https://github.com/nhosoya/omniauth-apple/pull/94) rack-protection.rb is back in rack-protection v3.0.1
14
+ - [#96](https://github.com/nhosoya/omniauth-apple/pull/96) handle JWKS fetch failures
15
+
16
+ ## [1.2.0] - 2022-09-27
17
+
18
+ ### Fixed
19
+
20
+ - [#91](https://github.com/nhosoya/omniauth-apple/pull/91) explicitly specify auth_scheme for oauth2 v2+ support
21
+
22
+ ## [1.1.0] - 2022-09-26
23
+
24
+ ### Added
25
+
26
+ - [#67](https://github.com/nhosoya/omniauth-apple/pull/67) Add email_verified and is_private_email
27
+
28
+ ### Fixed
29
+
30
+ - [#74](https://github.com/nhosoya/omniauth-apple/pull/74) rspec failure - callback_path null pointer
31
+ - [#81](https://github.com/nhosoya/omniauth-apple/pull/81) Allow for omniauth 2.0 series
32
+ - [#88](https://github.com/nhosoya/omniauth-apple/pull/88) update github actions config
33
+
3
34
  ## [1.0.2] - 2021-05-19
4
35
 
5
36
  ### Fixed
@@ -33,7 +64,7 @@
33
64
 
34
65
  ### Changed
35
66
 
36
- - [#27](https://github.com/nhosoya/omniauth-apple/pull/27) Update development dependency
67
+ - [#27](https://github.com/nhosoya/omniauth-apple/pull/27) Update development dependency
37
68
  - [#28](https://github.com/nhosoya/omniauth-apple/pull/28) Update README.md
38
69
  - [#38](https://github.com/nhosoya/omniauth-apple/pull/38) Refine AuthHash
39
70
  - [#39](https://github.com/nhosoya/omniauth-apple/pull/39) Set the default scope to 'email name'
@@ -44,7 +75,9 @@
44
75
 
45
76
  ## [0.0.1] - 2019-06-07
46
77
 
47
- [Unreleased]: https://github.com/nhosoya/omniauth-apple/compare/v1.0.2...master
48
- [1.0.0]: https://github.com/nhosoya/omniauth-apple/compare/v0.0.3...v1.0.0
49
- [1.0.1]: https://github.com/nhosoya/omniauth-apple/compare/v1.0.0...v1.0.1
78
+ [Unreleased]: https://github.com/nhosoya/omniauth-apple/compare/v1.2.0...master
79
+ [1.2.0]: https://github.com/nhosoya/omniauth-apple/compare/v1.1.0...v1.2.0
80
+ [1.1.0]: https://github.com/nhosoya/omniauth-apple/compare/v1.0.2...v1.1.0
50
81
  [1.0.2]: https://github.com/nhosoya/omniauth-apple/compare/v1.0.1...v1.0.2
82
+ [1.0.1]: https://github.com/nhosoya/omniauth-apple/compare/v1.0.0...v1.0.1
83
+ [1.0.0]: https://github.com/nhosoya/omniauth-apple/compare/v0.0.3...v1.0.0
data/README.md CHANGED
@@ -34,6 +34,77 @@ Rails.application.config.middleware.use OmniAuth::Builder do
34
34
  end
35
35
  ```
36
36
 
37
+ ## Configuring "Sign In with Apple"
38
+
39
+ _other Sign In with Apple guides:_
40
+ - ["How To" by janak amarasena (2019)](https://medium.com/identity-beyond-borders/how-to-configure-sign-in-with-apple-77c61e336003)
41
+ - [the docs, by Apple](https://developer.apple.com/sign-in-with-apple/)
42
+
43
+ ### Look out for the values you need for your config
44
+ 1. your domain and subdomains, something like: `myapp.com`, `www.myapp.com`
45
+ 2. your redirect uri, something like: `https://myapp.com/users/auth/apple/callback` (check `rails routes` to be sure)
46
+ 3. omniauth's "client id" will be Apple's "bundle id", something like: `com.myapp`
47
+ 4. you will get the "team id" value from Apple when you create your _**App Id**_, something like: `H000000B`
48
+ 5. Apple will give you a `.p8` file, which you'll use to GENERATE your `:pem` value
49
+
50
+ ### Steps
51
+
52
+ 1. Log into your [Apple Developer Account](https://idmsa.apple.com/IDMSWebAuth/signin?appIdKey=891bd3417a7776362562d2197f89480a8547b108fd934911bcbea0110d07f757&path=%2Faccount%2F&rv=1)
53
+ (if you don't have one, you can [create one here](https://appleid.apple.com/account?appId=632&returnUrl=https%3A%2F%2Fdeveloper.apple.com%2Faccount%2F))
54
+
55
+ 2. Get an App Id with the "Sign In with Apple" capability
56
+ - go to your [Identifiers](https://developer.apple.com/account/resources/identifiers/list) list
57
+ - [start a new Identifier](https://developer.apple.com/account/resources/identifiers/add/bundleId) by clicking on the + sign in the Identifiers List
58
+ - select _**App IDs**_ and click _**continue**_
59
+ - select _**App**_ and _**continue**_
60
+ - enter a description and a bundle id
61
+ - check the **_"Sign In with Apple"_** capability
62
+ - save it
63
+
64
+ 3. Get a Services Id (which we will use as our client id)
65
+ - go to your [Identifiers](https://developer.apple.com/account/resources/identifiers/list) list
66
+ - [start a new Identifier](https://developer.apple.com/account/resources/identifiers/add/bundleId) by clicking on the + sign in the Identifiers List
67
+ - select _**Services IDs**_ and click _**continue**_
68
+ - enter a description and a bundle id
69
+ - make sure **_"Sign In with Apple"_** is checked, then click _**configure**_
70
+ - make sure the Primary App ID matches the App ID you configured earlier
71
+ - enter all the subdomains you might use (comma delimited):
72
+
73
+ example.com,www.example.com
74
+
75
+ - enter all the redirect URLS you might use (comma delimited):
76
+
77
+ https://example.com/users/auth/apple/callback,https://example.com/users/auth/apple/callback
78
+
79
+ - save the "Sign In with Apple" capability config and the Service Id
80
+
81
+ 4. Get a Secret Key
82
+ - go to your [Keys](https://developer.apple.com/account/resources/authkeys/list) list
83
+ - [start a new Key](https://developer.apple.com/account/resources/authkeys/add) by clicking on the + sign in the Keys List
84
+ - enter a name
85
+ - make sure **_"Sign In with Apple"_** is checked, then click _**configure**_
86
+ - make sure the Primary App ID matches the App ID you configured earlier
87
+ - save the "Sign In with Apple" capability
88
+ - click "continue" to finish the Key config (you will be prompted to _**Download Your Key**_)
89
+ - Apple will give you a `.p8` file, keep it safe and secure (don't commit it).
90
+
91
+ ### Mapping Apple Values to OmniAuth Values
92
+ - your `:team_id` is in the top-right of your App Id config (aka _**App ID Prefix**_), it looks like: `H000000B`
93
+ - your `:client_id` is in the top-right of your Services Id config (aka _**Identifier**_), it looks like: `com.example`
94
+ - your `:key_id` is on the left side of your Key Details page, it looks like: `XYZ000000`
95
+ - your `:pem` is the content of the `.p8` file you got from Apple, _**with an extra newline at the end**_
96
+
97
+ - example from a Devise config:
98
+
99
+ ```ruby
100
+ config.omniauth :apple, ENV['APPLE_SERVICE_BUNDLE_ID'], '', {
101
+ scope: 'email name',
102
+ team_id: ENV['APPLE_APP_ID_PREFIX'],
103
+ key_id: ENV['APPLE_KEY_ID'],
104
+ pem: ENV['APPLE_P8_FILE_CONTENT_WITH_EXTRA_NEWLINE']
105
+ }
106
+ ```
107
+
37
108
  ## Contributing
38
109
 
39
110
  Bug reports and pull requests are welcome on GitHub at https://github.com/nhosoya/omniauth-apple.
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Apple
3
- VERSION = "1.0.2"
3
+ VERSION = '1.3.0'
4
4
  end
5
5
  end
@@ -1,49 +1,66 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'omniauth-oauth2'
4
- require 'net/https'
4
+ require 'json/jwt'
5
5
 
6
6
  module OmniAuth
7
7
  module Strategies
8
8
  class Apple < OmniAuth::Strategies::OAuth2
9
+ ISSUER = 'https://appleid.apple.com'
10
+
9
11
  option :name, 'apple'
10
12
 
11
13
  option :client_options,
12
- site: 'https://appleid.apple.com',
14
+ site: ISSUER,
13
15
  authorize_url: '/auth/authorize',
14
- token_url: '/auth/token'
16
+ token_url: '/auth/token',
17
+ auth_scheme: :request_body
15
18
  option :authorize_params,
16
19
  response_mode: 'form_post',
17
20
  scope: 'email name'
18
21
  option :authorized_client_ids, []
19
22
 
20
- uid { id_info['sub'] }
23
+ uid { id_info[:sub] }
21
24
 
25
+ # Documentation on parameters
26
+ # https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_rest_api/authenticating_users_with_sign_in_with_apple
22
27
  info do
23
28
  prune!(
24
- sub: id_info['sub'],
29
+ sub: id_info[:sub],
25
30
  email: email,
26
31
  first_name: first_name,
27
32
  last_name: last_name,
28
33
  name: (first_name || last_name) ? [first_name, last_name].join(' ') : email,
34
+ email_verified: email_verified,
35
+ is_private_email: is_private_email
29
36
  )
30
37
  end
31
38
 
32
39
  extra do
33
- id_token = request.params['id_token'] || access_token&.params&.dig('id_token')
34
- prune!(raw_info: {id_info: id_info, user_info: user_info, id_token: id_token})
40
+ id_token_str = request.params['id_token'] || access_token&.params&.dig('id_token')
41
+ prune!(raw_info: {id_info: id_info, user_info: user_info, id_token: id_token_str})
35
42
  end
36
43
 
37
44
  def client
38
45
  ::OAuth2::Client.new(client_id, client_secret, deep_symbolize(options.client_options))
39
46
  end
40
47
 
48
+ def email_verified
49
+ value = id_info[:email_verified]
50
+ value == true || value == "true"
51
+ end
52
+
53
+ def is_private_email
54
+ value = id_info[:is_private_email]
55
+ value == true || value == "true"
56
+ end
57
+
41
58
  def authorize_params
42
59
  super.merge(nonce: new_nonce)
43
60
  end
44
61
 
45
62
  def callback_url
46
- options[:redirect_uri] || (full_host + script_name + callback_path)
63
+ options[:redirect_uri] || (full_host + callback_path)
47
64
  end
48
65
 
49
66
  private
@@ -58,43 +75,68 @@ module OmniAuth
58
75
 
59
76
  def id_info
60
77
  @id_info ||= if request.params&.key?('id_token') || access_token&.params&.key?('id_token')
61
- id_token = request.params['id_token'] || access_token.params['id_token']
62
- jwt_options = {
63
- verify_iss: true,
64
- iss: 'https://appleid.apple.com',
65
- verify_iat: true,
66
- verify_aud: true,
67
- aud: [options.client_id].concat(options.authorized_client_ids),
68
- algorithms: ['RS256'],
69
- jwks: fetch_jwks
70
- }
71
- payload, _header = ::JWT.decode(id_token, nil, true, jwt_options)
72
- verify_nonce!(payload)
73
- payload
78
+ id_token_str = request.params['id_token'] || access_token.params['id_token']
79
+ id_token = JSON::JWT.decode(id_token_str, :skip_verification)
80
+ verify_id_token! id_token
81
+ id_token
74
82
  end
75
83
  end
76
84
 
77
- def fetch_jwks
78
- http = Net::HTTP.new('appleid.apple.com', 443)
79
- http.use_ssl = true
80
- request = Net::HTTP::Get.new('/auth/keys', 'User-Agent' => 'ruby/omniauth-apple')
81
- response = http.request(request)
82
- JSON.parse(response.body, symbolize_names: true)
85
+ def verify_id_token!(id_token)
86
+ jwk = fetch_jwk! id_token.kid
87
+ verify_signature! id_token, jwk
88
+ verify_claims! id_token
83
89
  end
84
90
 
85
- def verify_nonce!(payload)
86
- return unless payload['nonce_supported']
91
+ def fetch_jwk!(kid)
92
+ JSON::JWK::Set::Fetcher.fetch File.join(ISSUER, 'auth/keys'), kid: kid
93
+ rescue => e
94
+ raise CallbackError.new(:jwks_fetching_failed, e)
95
+ end
87
96
 
88
- return if payload['nonce'] && payload['nonce'] == stored_nonce
97
+ def verify_signature!(id_token, jwk)
98
+ id_token.verify! jwk
99
+ rescue => e
100
+ raise CallbackError.new(:id_token_signature_invalid, e)
101
+ end
102
+
103
+ def verify_claims!(id_token)
104
+ verify_iss!(id_token)
105
+ verify_aud!(id_token)
106
+ verify_iat!(id_token)
107
+ verify_exp!(id_token)
108
+ verify_nonce!(id_token) if id_token[:nonce_supported]
109
+ end
110
+
111
+ def verify_iss!(id_token)
112
+ invalid_claim! :iss unless id_token[:iss] == ISSUER
113
+ end
89
114
 
90
- fail!(:nonce_mismatch, CallbackError.new(:nonce_mismatch, 'nonce mismatch'))
115
+ def verify_aud!(id_token)
116
+ invalid_claim! :aud unless [options.client_id].concat(options.authorized_client_ids).include?(id_token[:aud])
117
+ end
118
+
119
+ def verify_iat!(id_token)
120
+ invalid_claim! :iat unless id_token[:iat] <= Time.now.to_i
121
+ end
122
+
123
+ def verify_exp!(id_token)
124
+ invalid_claim! :exp unless id_token[:exp] >= Time.now.to_i
125
+ end
126
+
127
+ def verify_nonce!(id_token)
128
+ invalid_claim! :nonce unless id_token[:nonce] && id_token[:nonce] == stored_nonce
129
+ end
130
+
131
+ def invalid_claim!(claim)
132
+ raise CallbackError.new(:id_token_claims_invalid, "#{claim} invalid")
91
133
  end
92
134
 
93
135
  def client_id
94
136
  @client_id ||= if id_info.nil?
95
137
  options.client_id
96
138
  else
97
- id_info['aud'] if options.authorized_client_ids.include? id_info['aud']
139
+ id_info[:aud] if options.authorized_client_ids.include? id_info[:aud]
98
140
  end
99
141
  end
100
142
 
@@ -106,7 +148,7 @@ module OmniAuth
106
148
  end
107
149
 
108
150
  def email
109
- id_info['email']
151
+ id_info[:email]
110
152
  end
111
153
 
112
154
  def first_name
@@ -125,16 +167,15 @@ module OmniAuth
125
167
  end
126
168
 
127
169
  def client_secret
128
- payload = {
170
+ jwt = JSON::JWT.new(
129
171
  iss: options.team_id,
130
- aud: 'https://appleid.apple.com',
172
+ aud: ISSUER,
131
173
  sub: client_id,
132
- iat: Time.now.to_i,
133
- exp: Time.now.to_i + 60
134
- }
135
- headers = { kid: options.key_id }
136
-
137
- ::JWT.encode(payload, private_key, 'ES256', headers)
174
+ iat: Time.now,
175
+ exp: Time.now + 60
176
+ )
177
+ jwt.kid = options.key_id
178
+ jwt.sign(private_key).to_s
138
179
  end
139
180
 
140
181
  def private_key
@@ -37,10 +37,10 @@ Gem::Specification.new do |spec|
37
37
  spec.require_paths = ["lib"]
38
38
 
39
39
  spec.add_dependency 'omniauth-oauth2'
40
- spec.add_dependency 'jwt'
40
+ spec.add_dependency 'json-jwt'
41
41
  spec.add_development_dependency "bundler", "~> 2.0"
42
42
  spec.add_development_dependency "rake", "~> 13.0"
43
43
  spec.add_development_dependency "rspec", "~> 3.9"
44
44
  spec.add_development_dependency "webmock", "~> 3.8"
45
- spec.add_development_dependency 'simplecov', "~> 0.18"
45
+ spec.add_development_dependency "simplecov", "~> 0.18"
46
46
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-apple
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nhosoya
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2021-05-19 00:00:00.000000000 Z
12
+ date: 2023-01-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: omniauth-oauth2
@@ -26,7 +26,7 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
- name: jwt
29
+ name: json-jwt
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ">="
@@ -150,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
150
  - !ruby/object:Gem::Version
151
151
  version: '0'
152
152
  requirements: []
153
- rubygems_version: 3.2.3
153
+ rubygems_version: 3.3.26
154
154
  signing_key:
155
155
  specification_version: 4
156
156
  summary: OmniAuth strategy for Sign In with Apple