apple_id 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +52 -3
- data/Rakefile +15 -2
- data/VERSION +1 -1
- data/apple_id.gemspec +6 -3
- data/lib/apple_id.rb +4 -1
- data/lib/apple_id/access_token.rb +10 -0
- data/lib/apple_id/client.rb +23 -5
- data/lib/apple_id/id_token.rb +45 -0
- metadata +58 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e000f6003a2baeecbb6683a9636b311cac3eec9ec20df988f79f0bbd50231135
|
4
|
+
data.tar.gz: e4890bdb603981bcd9d4489915e607029490c221210816315f96dd3d6fccfd9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bb4b14f28e1906cf6517e2382422a5dd44c864479ea550bf2ad54a2758b166ab0464e0e04539f0e2f26c592daae932eba81d4f82f508b0aae2d45f956d1bcce
|
7
|
+
data.tar.gz: 406ae5c6dca6868bfac746b83b3422b1a92876e6f6d75ced236f2b653b88e8d6469ca5544b33afae387d8bca78aa2237608e1557022daff8d3f334667c8e1663
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# AppleID
|
2
2
|
|
3
|
-
|
3
|
+
"Sign-in with Apple" is an implementation of OpenID Connect with small custom features.
|
4
4
|
|
5
|
-
|
5
|
+
This gem handles such custom features.
|
6
|
+
|
7
|
+
Basically, this gem is based on my [OpenID Connect gem](https://github.com/nov/openid_connect) and [OAuth2 gem](https://github.com/nov/rack-oauth2), so the usage is almost same with them.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -22,7 +24,54 @@ Or install it yourself as:
|
|
22
24
|
|
23
25
|
## Usage
|
24
26
|
|
25
|
-
|
27
|
+
There is [a sample rails app](https://github.com/nov/signin-with-apple) running at [signin-with-apple.herokuapp.com](https://signin-with-apple.herokuapp.com).
|
28
|
+
|
29
|
+
If you run script in your terminal only, do like below.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'apple_id'
|
33
|
+
|
34
|
+
# NOTE: in debugging mode, you can see all HTTPS request & response in the log.
|
35
|
+
# AppleID.debug!
|
36
|
+
|
37
|
+
pem = <<-PEM
|
38
|
+
-----BEGIN PRIVATE KEY-----
|
39
|
+
:
|
40
|
+
:
|
41
|
+
-----END PRIVATE KEY-----
|
42
|
+
PEM
|
43
|
+
private_key = OpenSSL::PKey::EC.new pem
|
44
|
+
|
45
|
+
client = AppleID::Client.new(
|
46
|
+
identifier: '<YOUR-CLIENT-ID>',
|
47
|
+
team_id: '<YOUR-TEAM-ID>',
|
48
|
+
key_id: '<YOUR-KEY-ID>',
|
49
|
+
private_key: private_key,
|
50
|
+
redirect_uri: '<YOUR-REDIRECT-URI>'
|
51
|
+
)
|
52
|
+
|
53
|
+
authorization_uri = client.authorization_uri(scope: [:email, :name])
|
54
|
+
puts authorization_uri
|
55
|
+
`open "#{authorization_uri}"`
|
56
|
+
|
57
|
+
print 'code: ' and STDOUT.flush
|
58
|
+
code = gets.chop
|
59
|
+
|
60
|
+
client.authorization_code = code
|
61
|
+
response = client.access_token!
|
62
|
+
|
63
|
+
response.id_token.verify!(
|
64
|
+
client,
|
65
|
+
access_token: response.access_token,
|
66
|
+
|
67
|
+
# NOTE:
|
68
|
+
# When verifying signature, one http request to Apple's JWKs are required.
|
69
|
+
# You can skip ID Token signature verification when you got the token directly from the token endpoint in TLS channel.
|
70
|
+
verify_signature: false
|
71
|
+
)
|
72
|
+
puts response.id_token.sub # => OpenID Connect Subject Identifier (= Apple User ID)
|
73
|
+
puts response.id_token.original_jwt.pretty_generate
|
74
|
+
```
|
26
75
|
|
27
76
|
## Development
|
28
77
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,19 @@
|
|
1
|
-
require
|
2
|
-
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
|
+
require 'rspec/core/rake_task'
|
4
5
|
RSpec::Core::RakeTask.new(:spec)
|
5
6
|
|
7
|
+
namespace :coverage do
|
8
|
+
desc 'Open coverage report'
|
9
|
+
task :report do
|
10
|
+
require 'simplecov'
|
11
|
+
`open "#{File.join SimpleCov.coverage_path, 'index.html'}"`
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
task :spec do
|
16
|
+
Rake::Task[:'coverage:report'].invoke unless ENV['TRAVIS_RUBY_VERSION']
|
17
|
+
end
|
18
|
+
|
6
19
|
task :default => :spec
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/apple_id.gemspec
CHANGED
@@ -20,7 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'rack-oauth2', '~> 1.9.3'
|
22
22
|
spec.add_runtime_dependency 'openid_connect', '~> 1.0'
|
23
|
-
spec.add_development_dependency 'bundler'
|
24
|
-
spec.add_development_dependency 'rake'
|
25
|
-
spec.add_development_dependency 'rspec'
|
23
|
+
spec.add_development_dependency 'bundler'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'rspec'
|
26
|
+
spec.add_development_dependency 'rspec-its'
|
27
|
+
spec.add_development_dependency 'webmock'
|
28
|
+
spec.add_development_dependency 'simplecov'
|
26
29
|
end
|
data/lib/apple_id.rb
CHANGED
@@ -2,6 +2,7 @@ require 'openid_connect'
|
|
2
2
|
|
3
3
|
module AppleID
|
4
4
|
ISSUER = 'https://appleid.apple.com'
|
5
|
+
JWKS_URI = 'https://appleid.apple.com/auth/keys'
|
5
6
|
|
6
7
|
VERSION = ::File.read(
|
7
8
|
::File.join(::File.dirname(__FILE__), '../VERSION')
|
@@ -50,4 +51,6 @@ module AppleID
|
|
50
51
|
self.debugging = false
|
51
52
|
end
|
52
53
|
|
53
|
-
require 'apple_id/client'
|
54
|
+
require 'apple_id/client'
|
55
|
+
require 'apple_id/access_token'
|
56
|
+
require 'apple_id/id_token'
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module AppleID
|
2
|
+
class AccessToken < OpenIDConnect::AccessToken
|
3
|
+
undef_required_attributes :client
|
4
|
+
|
5
|
+
def initialize(access_token, attributes = {})
|
6
|
+
super attributes.merge(access_token: access_token)
|
7
|
+
self.id_token = IdToken.decode(id_token) if id_token.present?
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/apple_id/client.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module AppleID
|
2
2
|
class Client < OpenIDConnect::Client
|
3
|
+
class Error < Rack::OAuth2::Client::Error; end
|
4
|
+
|
3
5
|
attr_required :team_id, :key_id, :private_key
|
4
6
|
|
5
7
|
def initialize(attributes)
|
6
8
|
attributes_with_default = {
|
7
|
-
|
8
|
-
|
9
|
-
token_endpoint: '/auth/token'
|
9
|
+
authorization_endpoint: File.join(ISSUER, '/auth/authorize'),
|
10
|
+
token_endpoint: File.join(ISSUER, '/auth/token')
|
10
11
|
}.merge(attributes)
|
11
12
|
super attributes_with_default
|
12
13
|
end
|
@@ -21,7 +22,7 @@ module AppleID
|
|
21
22
|
def client_secret_jwt
|
22
23
|
jwt = JSON::JWT.new(
|
23
24
|
iss: team_id,
|
24
|
-
aud:
|
25
|
+
aud: ISSUER,
|
25
26
|
sub: identifier,
|
26
27
|
iat: Time.now,
|
27
28
|
exp: 1.minutes.from_now
|
@@ -29,5 +30,22 @@ module AppleID
|
|
29
30
|
jwt.kid = key_id
|
30
31
|
jwt.sign(private_key)
|
31
32
|
end
|
33
|
+
|
34
|
+
def setup_required_scope(scopes)
|
35
|
+
# NOTE:
|
36
|
+
# openid_connect gem add `openid` scope automatically.
|
37
|
+
# However, it's not required for Sign-in with Apple.
|
38
|
+
scopes
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_success_response(response)
|
42
|
+
token_hash = JSON.parse(response.body).with_indifferent_access
|
43
|
+
AccessToken.new token_hash.delete(:access_token), token_hash
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_error_response(response)
|
47
|
+
error = JSON.parse(response.body).with_indifferent_access
|
48
|
+
raise Error.new(response.status, error)
|
49
|
+
end
|
32
50
|
end
|
33
|
-
end
|
51
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module AppleID
|
2
|
+
class IdToken < OpenIDConnect::ResponseObject::IdToken
|
3
|
+
class VerificationFailed < StandardError; end
|
4
|
+
|
5
|
+
alias_method :original_jwt, :raw_attributes
|
6
|
+
|
7
|
+
def verify!(expected_client, access_token: nil, code: nil, verify_signature: true)
|
8
|
+
verify_signature! if verify_signature
|
9
|
+
verify_claims! expected_client, access_token, code
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def decode(jwt_string)
|
15
|
+
super jwt_string, :skip_verification
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def jwks
|
22
|
+
@jwks ||= JSON.parse(
|
23
|
+
OpenIDConnect.http_client.get_content(JWKS_URI)
|
24
|
+
).with_indifferent_access
|
25
|
+
JSON::JWK::Set.new @jwks[:keys]
|
26
|
+
end
|
27
|
+
|
28
|
+
def verify_signature!
|
29
|
+
original_jwt.verify! jwks
|
30
|
+
rescue
|
31
|
+
raise VerificationFailed, 'Signature Verification Failed'
|
32
|
+
end
|
33
|
+
|
34
|
+
def verify_claims!(expected_client, access_token, code)
|
35
|
+
# TODO: verify at_hash & c_hash
|
36
|
+
unless (
|
37
|
+
iss == ISSUER &&
|
38
|
+
aud == expected_client.identifier &&
|
39
|
+
Time.now.to_i.between?(iat, exp)
|
40
|
+
)
|
41
|
+
raise VerificationFailed, 'Claims Verification Failed'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apple_id
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack-oauth2
|
@@ -42,44 +42,86 @@ dependencies:
|
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-its
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
81
123
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
124
|
+
version: '0'
|
83
125
|
description: Sign-in with Apple backend library in Ruby.
|
84
126
|
email:
|
85
127
|
- nov@matake.jp
|
@@ -100,7 +142,9 @@ files:
|
|
100
142
|
- bin/console
|
101
143
|
- bin/setup
|
102
144
|
- lib/apple_id.rb
|
145
|
+
- lib/apple_id/access_token.rb
|
103
146
|
- lib/apple_id/client.rb
|
147
|
+
- lib/apple_id/id_token.rb
|
104
148
|
homepage: https://github.com/nov/apple_id
|
105
149
|
licenses:
|
106
150
|
- MIT
|