Skip to content

Commit

Permalink
Verify ID Token
Browse files Browse the repository at this point in the history
  • Loading branch information
nhosoya committed Jun 9, 2020
1 parent 92c35fe commit 012b054
Showing 1 changed file with 48 additions and 11 deletions.
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 012b054

Please # to comment.