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 +4 -4
- data/.github/workflows/rspec.yml +11 -10
- data/CHANGELOG.md +37 -4
- data/README.md +71 -0
- data/lib/omniauth/apple/version.rb +1 -1
- data/lib/omniauth/strategies/apple.rb +82 -41
- data/omniauth-apple.gemspec +2 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0a0049edf786737a4acc4af68aeff8b8323a020822dfd530a01c0f8925cc1f1
|
4
|
+
data.tar.gz: 44d8cf583c85cb198f6dd5a9f7e593d5109335a78cc01ec7b32feaa69b449df0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecc115718bb19ab99e6b15c05432b19ae73499a8b76f98e05e5cb0b45d61b61549a283709180d0df60b188e3c5db789a5d4c0cfe79d147014ca798df5ecc511a
|
7
|
+
data.tar.gz: eaa439dee2483186d09f0aa24e6e653118ca37545f01d074c098366c24daa8b355c8e24df1e0138e0fcd93efa0946a7ae9141c21e6cee7c3629941dbe59b2a65
|
data/.github/workflows/rspec.yml
CHANGED
@@ -6,21 +6,22 @@ on:
|
|
6
6
|
- master
|
7
7
|
pull_request:
|
8
8
|
|
9
|
+
permissions:
|
10
|
+
contents: read
|
11
|
+
|
9
12
|
jobs:
|
10
|
-
|
13
|
+
spec:
|
11
14
|
runs-on: ubuntu-latest
|
12
15
|
strategy:
|
13
16
|
fail-fast: false
|
14
17
|
matrix:
|
15
|
-
ruby: ['2.
|
18
|
+
ruby: ['2.6', '2.7', '3.0', '3.1']
|
16
19
|
steps:
|
17
|
-
- uses: actions/checkout@
|
18
|
-
- name: Set up Ruby
|
19
|
-
uses:
|
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
|
-
|
23
|
-
|
24
|
-
|
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
|
48
|
-
[1.
|
49
|
-
[1.0
|
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,49 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'omniauth-oauth2'
|
4
|
-
require '
|
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:
|
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[
|
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[
|
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
|
-
|
34
|
-
prune!(raw_info: {id_info: id_info, user_info: user_info, 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 +
|
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
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
86
|
-
|
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
|
-
|
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
|
-
|
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[
|
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[
|
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
|
-
|
170
|
+
jwt = JSON::JWT.new(
|
129
171
|
iss: options.team_id,
|
130
|
-
aud:
|
172
|
+
aud: ISSUER,
|
131
173
|
sub: client_id,
|
132
|
-
iat: Time.now
|
133
|
-
exp: Time.now
|
134
|
-
|
135
|
-
|
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
|
data/omniauth-apple.gemspec
CHANGED
@@ -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
|
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
|
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:
|
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.
|
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
|