I'm attempting to use Omniauth to implement an authorization code grant-type through Okta. I've implemented a strategy that is nearly identical to that in the okta omniauth gem. I've added the necessary code to the devise initializer and it easily retrieves the authorization code and grant type form the authorization endpoint. However, when it returns the parameters to the redirect_uri, I don't understand how to get the strategy to initiate the callback_phase
method which is necessary to exchange the code for an access token with the token endpoint. As a result, the auth hash is not created so the User.from_omniauth call in my controller throws an error.
Question: How do I deliver the access code to my strategy to retrieve the access token?
Any help would be greatly appreciated.
Strategy: require 'omniauth' require 'net/http'
# frozen_string_literal: true
require 'omniauth-oauth2'
module OmniAuth
module Strategies
class Moto < OmniAuth::Strategies::OAuth2
ORG = AUTH['oauth2']['moto']['OKTA_ORG'] || 'your-org'
DOMAIN = AUTH['oauth2']['moto']['OKTA_DOMAIN'] || "https://#{ORG}.okta.com"
BASE_URL = DOMAIN
DEFAULT_SCOPE = %[openid profile email].freeze
option :name, 'moto'
option :skip_jwt, false
option :jwt_leeway, 60
option :redirect_uri, AUTH['oauth2']['moto']['redirect']
option :client_options, {
site: BASE_URL,
authorize_url: "#{BASE_URL}/oauth2/v1/authorize",
token_url: "#{BASE_URL}/oauth2/v1/token",
response_type: 'authorization_code'
}
option :scope, DEFAULT_SCOPE
uid { raw_info['sub'] }
info do
{
name: raw_info['name'],
email: raw_info['email'],
first_name: raw_info['given_name'],
last_name: raw_info['family_name'],
image: raw_info['picture']
}
end
extra do
hash = {}
hash[:raw_info] = raw_info unless skip_info?
hash[:id_token] = access_token.token
if !options[:skip_jwt] && !access_token.token.nil?
hash[:id_info] = validated_token(access_token.token)
end
hash
end
alias :oauth2_access_token :access_token
def access_token
puts "in access token"
::OAuth2::AccessToken.new(client, oauth2_access_token.token, {
:refresh_token => oauth2_access_token.refresh_token,
:expires_in => oauth2_access_token.expires_in,
:expires_at => oauth2_access_token.expires_at
})
end
def raw_info
@_raw_info ||= access_token.get('/oauth2/v1/userinfo').parsed || {}
rescue ::Errno::ETIMEDOUT
raise ::Timeout::Error
end
def request_phase
puts "In request phase"
super
end
def callback_phase
puts "in callback phase"
build_access_token
super
end
def callback_url
options[:redirect_uri] || (full_host + script_name + callback_path)
end
def validated_token(token)
JWT.decode(token,
nil,
false,
verify_iss: true,
iss: BASE_URL,
verify_aud: true,
aud: BASE_URL,
verify_sub: true,
verify_expiration: true,
verify_not_before: true,
verify_iat: true,
verify_jti: false,
leeway: options[:jwt_leeway]
).first
end
end
end
end
controller callback
class OmniauthController < Devise::OmniauthCallbacksController
def moto_callback
# You need to implement the method below in your model (e.g. app/models/user.rb)
puts "Request env #{env['omniauth.auth']}"
logger.debug "Request env #{env['omniauth.auth']}"
@user = User.from_omniauth(request.env["omniauth.auth"])
print(@user)
if @user.save
session[:oktastate] = request.env["omniauth.auth"]
print(@user.oauth_permissions(session[:oktastate]))
else
print(@user.errors.full_messages)
end
if @user.persisted?
redirect_to "/users"
end
end
end
initializer/devise.rb
config.omniauth(:moto, AUTH['oauth2']['moto']['OKTA_CLIENT_ID'], AUTH['oauth2']['moto']['OKTA_CLIENT_SECRET'], :scope => 'openid profile email', :fields => ['profile', 'email'], :strategy_class => OmniAuth::Strategies::Moto)
Aucun commentaire:
Enregistrer un commentaire