Switch to diy oauth

This commit is contained in:
Dan Milne
2025-11-07 16:38:18 +11:00
parent f50ebe666e
commit c9e2992fe0
4 changed files with 120 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
class OidcAuthController < ApplicationController
allow_unauthenticated_access only: [:authorize, :callback]
# POST /auth/oidc - Initiate OIDC flow
def authorize
redirect_to oidc_client.authorization_uri(
scope: [:openid, :email, :profile],
state: generate_state_token,
nonce: generate_nonce
), allow_other_host: true
end
# GET /auth/oidc/callback - Handle provider callback
def callback
# Verify state token
unless valid_state_token?(params[:state])
redirect_to new_session_path, alert: "Invalid authentication state"
return
end
# Exchange authorization code for tokens
oidc_client.authorization_code = params[:code]
access_token = oidc_client.access_token!
# Get user info
user_info = access_token.userinfo!
# Find user by email
user = User.find_by(email_address: user_info.email)
unless user
redirect_to new_session_path, alert: "No user found with email: #{user_info.email}"
return
end
# Update role based on OIDC groups if present
if user_info.respond_to?(:groups) && user_info.groups.present?
user.update_role_from_oidc_groups(user_info.groups)
end
start_new_session_for(user)
redirect_to root_path, notice: "Successfully signed in via OIDC"
rescue OpenIDConnect::Exception, Rack::OAuth2::Client::Error => e
Rails.logger.error "OIDC authentication failed: #{e.message}"
redirect_to new_session_path, alert: "Authentication failed: #{e.message}"
end
private
def oidc_client
@oidc_client ||= begin
discovery = OpenIDConnect::Discovery::Provider::Config.discover!(ENV['OIDC_DISCOVERY_URL'])
OpenIDConnect::Client.new(
identifier: ENV['OIDC_CLIENT_ID'],
secret: ENV['OIDC_CLIENT_SECRET'],
redirect_uri: ENV['OIDC_REDIRECT_URI'] || oidc_callback_url,
authorization_endpoint: discovery.authorization_endpoint,
token_endpoint: discovery.token_endpoint,
userinfo_endpoint: discovery.userinfo_endpoint
)
end
end
def generate_state_token
token = SecureRandom.hex(32)
session[:oidc_state] = token
token
end
def generate_nonce
SecureRandom.hex(32)
end
def valid_state_token?(state)
state.present? && session[:oidc_state] == state
end
def oidc_callback_url
"#{request.base_url}/auth/oidc/callback"
end
end