Skip to content

Commit

Permalink
Merge pull request #26 from nhosoya/verify-id_token
Browse files Browse the repository at this point in the history
Verify ID Token
  • Loading branch information
nhosoya authored Jun 9, 2020
2 parents 6911d51 + b3ff35d commit e54f61e
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
## [Unreleased]

### Added

- [#26](https://github.com/nhosoya/omniauth-apple/pull/26) Support ID Token verification

### Changed

- [#27](https://github.com/nhosoya/omniauth-apple/pull/27) Update development dependency

## [0.0.3] - 2020-05-15

## [0.0.2] - 2020-01-16

## [0.0.1] - 2019-06-07

[Unreleased]: https://github.com/nhosoya/omniauth-apple/compare/v0.0.3...master
59 changes: 48 additions & 11 deletions lib/omniauth/strategies/apple.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'omniauth-oauth2'
require 'net/https'

module OmniAuth
module Strategies
Expand All @@ -14,7 +15,7 @@ class Apple < OmniAuth::Strategies::OAuth2
option :authorize_params,
response_mode: 'form_post'
option :authorized_client_ids, []

uid { id_info['sub'] }

info do
Expand All @@ -36,26 +37,62 @@ def client
::OAuth2::Client.new(client_id, client_secret, deep_symbolize(options.client_options))
end

def authorize_params
super.merge(nonce: new_nonce)
end

def callback_url
options[:redirect_uri] || (full_host + script_name + callback_path)
end

private

def new_nonce
session['omniauth.nonce'] = SecureRandom.urlsafe_base64(16)
end

def stored_nonce
session.delete('omniauth.nonce')
end

def id_info
if request.params&.key?('id_token') || access_token&.params&.key?('id_token')
id_token = request.params['id_token'] || access_token.params['id_token']
log(:info, "id_token: #{id_token}")
@id_info ||= ::JWT.decode(id_token, nil, false)[0] # payload after decoding
end
@id_info ||= if request.params&.key?('id_token') || access_token&.params&.key?('id_token')
id_token = request.params['id_token'] || access_token.params['id_token']
jwt_options = {
verify_iss: true,
iss: 'https://appleid.apple.com',
verify_iat: true,
verify_aud: true,
aud: [options.client_id].concat(options.authorized_client_ids),
algorithms: ['RS256'],
jwks: fetch_jwks
}
payload, _header = ::JWT.decode(id_token, nil, true, jwt_options)
verify_nonce!(payload)
payload
end
end

def client_id
unless id_info.nil?
return id_info['aud'] if options.authorized_client_ids.include? id_info['aud']
end
def fetch_jwks
uri = URI.parse('https://appleid.apple.com/auth/keys')
response = Net::HTTP.get_response(uri)
{ keys: JSON.parse(response.body)['keys'].map(&:with_indifferent_access) }
end

def verify_nonce!(payload)
return unless payload[:nonce_supported]

return if payload[:nonce].present? && payload[:nonce] != stored_nonce

options.client_id
fail!(:nonce_mismatch, CallbackError.new(:nonce_mismatch, 'nonce mismatch'))
end

def client_id
@client_id ||= if id_info.nil?
options.client_id
else
id_info['aud'] if options.authorized_client_ids.include? id_info['aud']
end
end

def user_info
Expand Down

0 comments on commit e54f61e

Please # to comment.