Skip to content

Rails 8

Rails 8 + omniauth 스타일을 쓰지 않고 직접 OAuth 클라이언트를 구현합니다 (의존성 최소화).

ruby
# app/controllers/sessions_controller.rb
class LogiSessionsController < ApplicationController
  def start
    verifier = SecureRandom.urlsafe_base64(32).delete("=")
    challenge = Base64.urlsafe_encode64(Digest::SHA256.digest(verifier), padding: false)
    state = SecureRandom.hex(16)

    session[:logi_pkce] = verifier
    session[:logi_state] = state

    redirect_to "#{ENV['LOGI_API_URL']}/oauth/authorize?" + {
      client_id: ENV["LOGI_CLIENT_ID"],
      redirect_uri: logi_callback_url,
      response_type: "code",
      scope: "profile email",
      state: state,
      code_challenge: challenge,
      code_challenge_method: "S256",
    }.to_query, allow_other_host: true
  end

  def callback
    return render_error("state mismatch") if params[:state] != session[:logi_state]

    res = Net::HTTP.post_form(
      URI("#{ENV['LOGI_API_URL']}/oauth/token"),
      grant_type: "authorization_code",
      code: params[:code],
      redirect_uri: logi_callback_url,
      code_verifier: session[:logi_pkce],
      client_id: ENV["LOGI_CLIENT_ID"],
      client_secret: ENV["LOGI_CLIENT_SECRET"]
    )
    tokens = JSON.parse(res.body)

    session.delete(:logi_pkce); session.delete(:logi_state)
    cookies.signed.permanent[:logi_rt] = {
      value: tokens["refresh_token"], httponly: true, secure: Rails.env.production?, same_site: :strict
    }
    redirect_to root_path
  end
end

JWT 검증:

ruby
gem "jwt"

jwks = JSON.parse(Net::HTTP.get(URI("#{ENV['LOGI_API_URL']}/.well-known/jwks.json")))
payload, = JWT.decode(
  access_token, nil, true,
  algorithms: ["RS256"],
  jwks: JWT::JWK::Set.new(jwks),
  iss: "logi", verify_iss: true,
  aud: ENV["LOGI_CLIENT_ID"], verify_aud: true
)

MIT License · Identity가 제품의 신뢰를 만듭니다.