myinfo 0.1.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 +7 -0
- data/README.md +112 -0
- data/lib/myinfo.rb +55 -0
- data/lib/myinfo/errors.rb +7 -0
- data/lib/myinfo/helpers/attributes.rb +14 -0
- data/lib/myinfo/helpers/callable.rb +10 -0
- data/lib/myinfo/v3/api.rb +131 -0
- data/lib/myinfo/v3/authorise_url.rb +54 -0
- data/lib/myinfo/v3/person.rb +61 -0
- data/lib/myinfo/v3/person_basic.rb +56 -0
- data/lib/myinfo/v3/response.rb +23 -0
- data/lib/myinfo/v3/token.rb +56 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9c42852df0d1859a05e3b6626cc2abb19945cc2072d5cf2313bacc09ce15eb0b
|
4
|
+
data.tar.gz: 10b5b50b6882dad300511581299872d330df87b3d2df66734af3391406562ead
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dbee0afc819ced257f4392c0983c787e72347e9248cff74e3d1ff4885314005adc744fb4f14c04e5dff6e35da58aa80df7db74e440600636bc0b6cb727cfca80
|
7
|
+
data.tar.gz: be29694339f25994661aafa7d2c581ee94a0179d3b66c4db123ccc71a3fc8b51a925dd21a662c3fd9bc44f12d62fea052c736d7c3c1957ff9dab06bbae7cd952
|
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
# Rails wrapper for MyInfo API
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
|
6
|
+
[MyInfo Documentation (Public)](https://public.cloud.myinfo.gov.sg/myinfo/api/myinfo-kyc-v3.1.0.html)
|
7
|
+
|
8
|
+
[MyInfo Documentation (Government)](https://public.cloud.myinfo.gov.sg/myinfo/tuo/myinfo-tuo-specs.html)
|
9
|
+
## Basic Setup (Public)
|
10
|
+
|
11
|
+
1. `bundle add myinfo`
|
12
|
+
2. Create a `config/initializers/myinfo.rb` and add the required configuration based on your environment.
|
13
|
+
```ruby
|
14
|
+
MyInfo.configure do |config|
|
15
|
+
config.app_id = ''
|
16
|
+
config.client_id = ''
|
17
|
+
config.client_secret = ''
|
18
|
+
config.base_url = 'test.api.myinfo.gov.sg' # don't set https://
|
19
|
+
config.redirect_uri = 'https://localhost:3001/callback'
|
20
|
+
config.public_facing = true
|
21
|
+
config.private_key = File.read(Rails.root.join('private_key_location'))
|
22
|
+
config.public_cert = File.read(Rails.root.join('public_cert_location'))
|
23
|
+
config.sandbox = false # optional, false by default
|
24
|
+
config.proxy = { address: 'proxy_address', port: 'proxy_port' } # optional, nil by default
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
3. To obtain a person's MyInfo information, we need to authorise the query first:
|
29
|
+
```ruby
|
30
|
+
redirect_to MyInfo::V3::AuthoriseUrl.call(
|
31
|
+
purpose: 'set your purpose here',
|
32
|
+
state: SecureRandom.hex # set a state to check on callback
|
33
|
+
)
|
34
|
+
```
|
35
|
+
|
36
|
+
4. On `redirect_url`, obtain a `MyInfo::V3::Token`. This token can only be used once.
|
37
|
+
```ruby
|
38
|
+
response = MyInfo::V3::Token.call(
|
39
|
+
code: params[:code],
|
40
|
+
state: params[:state]
|
41
|
+
)
|
42
|
+
```
|
43
|
+
|
44
|
+
5. Obtain the `access_token` from the `response` and query for `MyInfo::V3::Person`:
|
45
|
+
```ruby
|
46
|
+
result = MyInfo::V3::Person.call(access_token: response.data) if response.success?
|
47
|
+
```
|
48
|
+
|
49
|
+
## Basic Setup (Government)
|
50
|
+
|
51
|
+
1. `bundle add myinfo`
|
52
|
+
2. Create a `config/initializers/myinfo.rb` and add the required configuration based on your environment.
|
53
|
+
```ruby
|
54
|
+
MyInfo.configure do |config|
|
55
|
+
config.app_id = ''
|
56
|
+
config.client_id = ''
|
57
|
+
config.client_secret = ''
|
58
|
+
config.base_url = 'test.api.myinfo.gov.sg' # don't set https://
|
59
|
+
config.redirect_uri = 'https://localhost:3001/callback'
|
60
|
+
config.singpass_eservice_id = 'MYINFO-CONSENTPLATFORM'
|
61
|
+
config.private_key = File.read(Rails.root.join('private_key_location'))
|
62
|
+
config.public_cert = File.read(Rails.root.join('public_cert_location'))
|
63
|
+
config.sandbox = false # optional, false by default
|
64
|
+
config.proxy = { address: 'proxy_address', port: 'proxy_port' } # optional, nil by default
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
3. To obtain a person's MyInfo information, we need to authorise the query first:
|
69
|
+
```ruby
|
70
|
+
redirect_to MyInfo::V3::AuthoriseUrl.call(
|
71
|
+
nric_fin: "user's NRIC", # see documentation for list of sample NRICs
|
72
|
+
purpose: 'set your purpose here',
|
73
|
+
state: SecureRandom.hex # set a state to check on callback
|
74
|
+
)
|
75
|
+
```
|
76
|
+
|
77
|
+
4. On `redirect_url`, obtain a `MyInfo::V3::Token`. This token can only be used once.
|
78
|
+
```ruby
|
79
|
+
response = MyInfo::V3::Token.call(
|
80
|
+
code: params[:code],
|
81
|
+
state: params[:state]
|
82
|
+
)
|
83
|
+
```
|
84
|
+
|
85
|
+
5. Obtain the `access_token` from the `response` and query for `MyInfo::V3::Person`:
|
86
|
+
```ruby
|
87
|
+
result = MyInfo::V3::Person.call(access_token: response.data) if response.success?
|
88
|
+
```
|
89
|
+
|
90
|
+
## Sample App Demo
|
91
|
+
|
92
|
+
1. `git clone git@github.com:GovTechSG/myinfo-rails.git`
|
93
|
+
2. `cd myinfo-rails`
|
94
|
+
3. `bundle install`
|
95
|
+
4. `cd spec/dummy && rails s`
|
96
|
+
5. Navigate to `localhost:3001`
|
97
|
+
|
98
|
+
## Advanced
|
99
|
+
- `attributes` can be passed to `AuthoriseUrl` and `Person` as an array to override the default attributes queried - check MyInfo for a list of available attributes.
|
100
|
+
|
101
|
+
- `success?` can be called on `MyInfo::V3::Response` to determine whether the query has succeeded or failed. Check MyInfo API for a list of responses and how to handle them.
|
102
|
+
|
103
|
+
## Disclaimer
|
104
|
+
Provided credentials in the repository are either obtained from [MyInfo Demo App](https://github.com/ndi-trusted-data/myinfo-demo-app) or samples online, and are only for testing purposes. They should not be re-used for staging or production environments. Visit the [official MyInfo tutorial](https://www.ndi-api.gov.sg/library/myinfo/tutorial3) for more information.
|
105
|
+
|
106
|
+
## Contributing
|
107
|
+
|
108
|
+
Contributions are welcome!
|
109
|
+
|
110
|
+
1. Fork the repository
|
111
|
+
2. Write code and tests
|
112
|
+
3. Submit a PR
|
data/lib/myinfo.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
require_relative 'myinfo/errors'
|
8
|
+
|
9
|
+
require_relative 'myinfo/helpers/callable'
|
10
|
+
require_relative 'myinfo/helpers/attributes'
|
11
|
+
|
12
|
+
require_relative 'myinfo/v3/response'
|
13
|
+
require_relative 'myinfo/v3/api'
|
14
|
+
require_relative 'myinfo/v3/token'
|
15
|
+
require_relative 'myinfo/v3/person'
|
16
|
+
require_relative 'myinfo/v3/person_basic'
|
17
|
+
require_relative 'myinfo/v3/authorise_url'
|
18
|
+
|
19
|
+
# Base MyInfo class
|
20
|
+
module MyInfo
|
21
|
+
class << self
|
22
|
+
attr_accessor :configuration
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.configure
|
26
|
+
self.configuration ||= Configuration.new
|
27
|
+
yield(configuration)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Configuration to set various properties needed to use MyInfo
|
31
|
+
class Configuration
|
32
|
+
attr_accessor :singpass_eservice_id, :app_id, :base_url, :client_id, :proxy,
|
33
|
+
:private_key, :public_cert, :client_secret, :redirect_uri
|
34
|
+
|
35
|
+
attr_writer :public_facing, :sandbox
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@public_facing = false
|
39
|
+
@sandbox = false
|
40
|
+
@proxy = { address: nil, port: nil }
|
41
|
+
end
|
42
|
+
|
43
|
+
def base_url_with_protocol
|
44
|
+
"https://#{base_url}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def public?
|
48
|
+
@public_facing
|
49
|
+
end
|
50
|
+
|
51
|
+
def sandbox?
|
52
|
+
@sandbox
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyInfo
|
4
|
+
# Attributes parsing
|
5
|
+
module Attributes
|
6
|
+
DEFAULT_VALUES = %i[name sex race dob residentialstatus email mobileno regadd].freeze
|
7
|
+
|
8
|
+
def self.parse(attributes)
|
9
|
+
attributes ||= DEFAULT_VALUES
|
10
|
+
|
11
|
+
attributes.is_a?(String) ? attributes : attributes.join(',')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwe'
|
4
|
+
require 'jwt'
|
5
|
+
|
6
|
+
module MyInfo
|
7
|
+
module V3
|
8
|
+
# Base API class
|
9
|
+
class Api
|
10
|
+
extend Callable
|
11
|
+
|
12
|
+
def endpoint
|
13
|
+
raise NotImplementedError, 'abstract'
|
14
|
+
end
|
15
|
+
|
16
|
+
def params(_args)
|
17
|
+
raise NotImplementedError, 'abstract'
|
18
|
+
end
|
19
|
+
|
20
|
+
def http_method
|
21
|
+
'GET'
|
22
|
+
end
|
23
|
+
|
24
|
+
def support_gzip?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def header(params:, access_token: nil)
|
29
|
+
{
|
30
|
+
'Content-Type' => 'application/json',
|
31
|
+
'Accept' => 'application/json',
|
32
|
+
'Cache-Control' => 'no-cache'
|
33
|
+
}.tap do |values|
|
34
|
+
values['Authorization'] = auth_header(params: params, access_token: access_token) unless config.sandbox?
|
35
|
+
|
36
|
+
if support_gzip?
|
37
|
+
values['Accept-Encoding'] = 'gzip'
|
38
|
+
values['Content-Encoding'] = 'gzip'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_response(response)
|
44
|
+
if response.code == '200'
|
45
|
+
yield
|
46
|
+
elsif errors.include?(response.code)
|
47
|
+
json = JSON.parse(response.body)
|
48
|
+
|
49
|
+
Response.new(success: false, data: "#{json['code']} - #{json['message']}")
|
50
|
+
else
|
51
|
+
Response.new(success: false, data: "#{response.code} - #{response.body}")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
def decrypt_jwe(text)
|
58
|
+
if config.sandbox?
|
59
|
+
JSON.parse(text)
|
60
|
+
else
|
61
|
+
JWE.decrypt(text, private_key)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def decode_jws(jws)
|
66
|
+
# TODO: verify signature
|
67
|
+
JWT.decode(jws, public_key, true, algorithm: 'RS256').first
|
68
|
+
end
|
69
|
+
|
70
|
+
def http
|
71
|
+
@http ||= if config.proxy.blank?
|
72
|
+
Net::HTTP.new(config.base_url, 443)
|
73
|
+
else
|
74
|
+
Net::HTTP.new(config.base_url, 443, config.proxy[:address], config.proxy[:port])
|
75
|
+
end
|
76
|
+
|
77
|
+
@http.use_ssl = true
|
78
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
79
|
+
|
80
|
+
@http
|
81
|
+
end
|
82
|
+
|
83
|
+
def config
|
84
|
+
MyInfo.configuration
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def private_key
|
90
|
+
raise MissingConfigurationError, :private_key if config.private_key.blank?
|
91
|
+
|
92
|
+
OpenSSL::PKey::RSA.new(config.private_key)
|
93
|
+
end
|
94
|
+
|
95
|
+
def public_key
|
96
|
+
raise MissingConfigurationError, :public_cert if config.public_cert.blank?
|
97
|
+
|
98
|
+
OpenSSL::X509::Certificate.new(config.public_cert).public_key
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_query(headers)
|
102
|
+
headers.sort_by { |k, v| [k.to_s, v] }
|
103
|
+
.map { |arr| arr.join('=') }
|
104
|
+
.join('&')
|
105
|
+
end
|
106
|
+
|
107
|
+
def auth_header(params:, access_token: nil)
|
108
|
+
auth_headers = {
|
109
|
+
app_id: config.app_id,
|
110
|
+
nonce: SecureRandom.hex,
|
111
|
+
signature_method: 'RS256',
|
112
|
+
timestamp: (Time.now.to_f * 1000).to_i
|
113
|
+
}.merge(params)
|
114
|
+
|
115
|
+
auth_headers[:signature] = sign(auth_headers)
|
116
|
+
|
117
|
+
header_elements = auth_headers.map { |k, v| "#{k}=\"#{v}\"" }
|
118
|
+
header_elements << "Bearer #{access_token}" if access_token.present?
|
119
|
+
|
120
|
+
"PKI_SIGN #{header_elements.join(',')}"
|
121
|
+
end
|
122
|
+
|
123
|
+
def sign(headers)
|
124
|
+
headers_query = to_query(headers)
|
125
|
+
base_string = "#{http_method}&#{config.base_url_with_protocol}/#{slug}&#{headers_query}"
|
126
|
+
signed_string = private_key.sign(OpenSSL::Digest.new('SHA256'), base_string)
|
127
|
+
Base64.strict_encode64(signed_string)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyInfo
|
4
|
+
module V3
|
5
|
+
# https://public.cloud.myinfo.gov.sg/myinfo/tuo/myinfo-tuo-specs.html#operation/getauthorise
|
6
|
+
class AuthoriseUrl
|
7
|
+
extend Callable
|
8
|
+
|
9
|
+
attr_accessor :nric_fin, :attributes, :purpose, :state, :authmode, :login_type
|
10
|
+
|
11
|
+
def initialize(purpose:, state:, nric_fin: nil, authmode: 'SINGPASS', login_type: 'SINGPASS', attributes: nil)
|
12
|
+
@nric_fin = nric_fin
|
13
|
+
@attributes = Attributes.parse(attributes)
|
14
|
+
@purpose = purpose
|
15
|
+
@authmode = authmode
|
16
|
+
@login_type = login_type
|
17
|
+
@state = state
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
query_string = {
|
22
|
+
authmode: authmode,
|
23
|
+
login_type: login_type,
|
24
|
+
purpose: purpose,
|
25
|
+
client_id: config.client_id,
|
26
|
+
attributes: attributes,
|
27
|
+
sp_esvcId: config.singpass_eservice_id,
|
28
|
+
state: state,
|
29
|
+
redirect_uri: config.redirect_uri
|
30
|
+
}.compact.to_param
|
31
|
+
|
32
|
+
endpoint(query_string)
|
33
|
+
end
|
34
|
+
|
35
|
+
def endpoint(query_string)
|
36
|
+
if config.public?
|
37
|
+
"#{config.base_url_with_protocol}/#{slug}/?#{query_string}"
|
38
|
+
else
|
39
|
+
"#{config.base_url_with_protocol}/#{slug}/#{nric_fin}/?#{query_string}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def slug
|
44
|
+
slug_prefix = config.public? ? 'com' : 'gov'
|
45
|
+
|
46
|
+
"#{slug_prefix}/v3/authorise"
|
47
|
+
end
|
48
|
+
|
49
|
+
def config
|
50
|
+
MyInfo.configuration
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyInfo
|
4
|
+
module V3
|
5
|
+
# Calls the Person API
|
6
|
+
class Person < Api
|
7
|
+
attr_accessor :access_token, :decoded_token, :attributes, :txn_no
|
8
|
+
|
9
|
+
def initialize(access_token:, txn_no: nil, attributes: nil)
|
10
|
+
@access_token = access_token
|
11
|
+
@decoded_token = decode_jws(access_token)
|
12
|
+
@attributes = Attributes.parse(attributes)
|
13
|
+
@txn_no = txn_no
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
headers = header(params: params, access_token: access_token)
|
18
|
+
endpoint_url = "/#{slug}?#{params.to_query}"
|
19
|
+
|
20
|
+
response = http.request_get(endpoint_url, headers)
|
21
|
+
parse_response(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
def slug
|
25
|
+
slug_prefix = config.public? ? 'com' : 'gov'
|
26
|
+
|
27
|
+
"#{slug_prefix}/v3/person/#{nric_fin}/"
|
28
|
+
end
|
29
|
+
|
30
|
+
def support_gzip?
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def params
|
35
|
+
{
|
36
|
+
txnNo: txn_no,
|
37
|
+
attributes: attributes,
|
38
|
+
client_id: config.client_id,
|
39
|
+
sp_esvcId: config.singpass_eservice_id
|
40
|
+
}.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
def nric_fin
|
44
|
+
@nric_fin ||= decoded_token['sub']
|
45
|
+
end
|
46
|
+
|
47
|
+
def errors
|
48
|
+
%w[401 403 404]
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_response(response)
|
52
|
+
super do
|
53
|
+
json = decrypt_jwe(response.body)
|
54
|
+
json = decode_jws(json.delete('"')) unless config.sandbox?
|
55
|
+
|
56
|
+
Response.new(success: true, data: json)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyInfo
|
4
|
+
module V3
|
5
|
+
# Calls the PersonBasic API
|
6
|
+
class PersonBasic < Api
|
7
|
+
attr_accessor :nric_fin, :attributes, :txn_no
|
8
|
+
|
9
|
+
def initialize(nric_fin:, txn_no: nil, attributes: nil)
|
10
|
+
raise UnavailableError, 'person-basic endpoint is not available for public-facing APIs.' if config.public?
|
11
|
+
|
12
|
+
@attributes = Attributes.parse(attributes)
|
13
|
+
@nric_fin = nric_fin
|
14
|
+
@txn_no = txn_no
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
headers = header(params: params)
|
19
|
+
endpoint_url = "/#{slug}?#{params.to_query}"
|
20
|
+
|
21
|
+
response = http.request_get(endpoint_url, headers)
|
22
|
+
parse_response(response)
|
23
|
+
end
|
24
|
+
|
25
|
+
def slug
|
26
|
+
"gov/v3/person-basic/#{nric_fin}/"
|
27
|
+
end
|
28
|
+
|
29
|
+
def support_gzip?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def params
|
34
|
+
{
|
35
|
+
txnNo: txn_no,
|
36
|
+
attributes: attributes,
|
37
|
+
client_id: config.client_id,
|
38
|
+
sp_esvcId: config.singpass_eservice_id
|
39
|
+
}.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def errors
|
43
|
+
%w[401 403 404 428 default]
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_response(response)
|
47
|
+
super do
|
48
|
+
json = decrypt_jwe(response.body)
|
49
|
+
json = decode_jws(json.delete('\"')) unless config.sandbox?
|
50
|
+
|
51
|
+
Response.new(success: true, data: json)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyInfo
|
4
|
+
module V3
|
5
|
+
# Simple response wrapper
|
6
|
+
class Response
|
7
|
+
attr_accessor :success, :data
|
8
|
+
|
9
|
+
def initialize(success:, data:)
|
10
|
+
@success = success
|
11
|
+
@data = data
|
12
|
+
end
|
13
|
+
|
14
|
+
def success?
|
15
|
+
@success
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
data
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyInfo
|
4
|
+
module V3
|
5
|
+
# Called after authorise to obtain a token for API calls
|
6
|
+
class Token < Api
|
7
|
+
attr_accessor :code, :state
|
8
|
+
|
9
|
+
def initialize(code:, state: nil)
|
10
|
+
@code = code
|
11
|
+
@state = state
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
headers = header(params: params).merge({ 'Content-Type' => 'application/x-www-form-urlencoded' })
|
16
|
+
response = http.request_post("/#{slug}", params.to_param, headers)
|
17
|
+
|
18
|
+
parse_response(response)
|
19
|
+
end
|
20
|
+
|
21
|
+
def http_method
|
22
|
+
'POST'
|
23
|
+
end
|
24
|
+
|
25
|
+
def slug
|
26
|
+
slug_prefix = config.public? ? 'com' : 'gov'
|
27
|
+
|
28
|
+
"#{slug_prefix}/v3/token"
|
29
|
+
end
|
30
|
+
|
31
|
+
def params
|
32
|
+
{
|
33
|
+
code: code,
|
34
|
+
state: state,
|
35
|
+
client_id: config.client_id,
|
36
|
+
client_secret: config.client_secret,
|
37
|
+
grant_type: 'authorization_code',
|
38
|
+
redirect_uri: config.redirect_uri
|
39
|
+
}.compact
|
40
|
+
end
|
41
|
+
|
42
|
+
def errors
|
43
|
+
%w[400 401]
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_response(response)
|
47
|
+
super do
|
48
|
+
json = JSON.parse(response.body)
|
49
|
+
access_token = json['access_token']
|
50
|
+
|
51
|
+
Response.new(success: true, data: access_token)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: myinfo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lim Yao Jie
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-01-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jwe
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jwt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '6.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '4.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.8'
|
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.21'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.21'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '3.11'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '3.11'
|
139
|
+
description: Rails wrapper for MyInfo API
|
140
|
+
email: limyaojie93@gmail.com
|
141
|
+
executables: []
|
142
|
+
extensions: []
|
143
|
+
extra_rdoc_files: []
|
144
|
+
files:
|
145
|
+
- README.md
|
146
|
+
- lib/myinfo.rb
|
147
|
+
- lib/myinfo/errors.rb
|
148
|
+
- lib/myinfo/helpers/attributes.rb
|
149
|
+
- lib/myinfo/helpers/callable.rb
|
150
|
+
- lib/myinfo/v3/api.rb
|
151
|
+
- lib/myinfo/v3/authorise_url.rb
|
152
|
+
- lib/myinfo/v3/person.rb
|
153
|
+
- lib/myinfo/v3/person_basic.rb
|
154
|
+
- lib/myinfo/v3/response.rb
|
155
|
+
- lib/myinfo/v3/token.rb
|
156
|
+
homepage: https://rubygems.org/gems/myinfo
|
157
|
+
licenses:
|
158
|
+
- MIT
|
159
|
+
metadata: {}
|
160
|
+
post_install_message:
|
161
|
+
rdoc_options: []
|
162
|
+
require_paths:
|
163
|
+
- lib
|
164
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - "~>"
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '2.7'
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubygems_version: 3.1.4
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: MyInfo gem
|
179
|
+
test_files: []
|