diff --git a/Gemfile b/Gemfile index e4d7c06..0bc986a 100644 --- a/Gemfile +++ b/Gemfile @@ -28,6 +28,9 @@ gem "rotp", "~> 6.3" # QR code generation for TOTP setup gem "rqrcode", "~> 2.0" +# JWT for OIDC ID tokens +gem "jwt", "~> 2.9" + # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem "tzinfo-data", platforms: %i[ windows jruby ] diff --git a/Gemfile.lock b/Gemfile.lock index 316af9e..50efbbf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -145,6 +145,8 @@ GEM actionview (>= 7.0.0) activesupport (>= 7.0.0) json (2.15.1) + jwt (2.10.2) + base64 kamal (2.8.1) activesupport (>= 7.0) base64 (~> 0.2) @@ -412,6 +414,7 @@ DEPENDENCIES image_processing (~> 1.2) importmap-rails jbuilder + jwt (~> 2.9) kamal propshaft puma (>= 5.0) diff --git a/app/controllers/oidc_controller.rb b/app/controllers/oidc_controller.rb index dfb4aa4..1382c31 100644 --- a/app/controllers/oidc_controller.rb +++ b/app/controllers/oidc_controller.rb @@ -1,6 +1,6 @@ class OidcController < ApplicationController # Discovery and JWKS endpoints are public - allow_unauthenticated_access only: [:discovery, :jwks, :token] + allow_unauthenticated_access only: [:discovery, :jwks, :token, :userinfo] skip_before_action :verify_authenticity_token, only: [:token] # GET /.well-known/openid-configuration diff --git a/app/models/oidc_authorization_code.rb b/app/models/oidc_authorization_code.rb index 73042f9..dd9c598 100644 --- a/app/models/oidc_authorization_code.rb +++ b/app/models/oidc_authorization_code.rb @@ -15,7 +15,7 @@ class OidcAuthorizationCode < ApplicationRecord expires_at <= Time.current end - def valid? + def usable? !used? && !expired? end diff --git a/config/routes.rb b/config/routes.rb index 7ae9d2b..1b5976c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,14 @@ Rails.application.routes.draw do get "/totp-verification", to: "sessions#verify_totp", as: :totp_verification post "/totp-verification", to: "sessions#verify_totp" + # OIDC (OpenID Connect) routes + get "/.well-known/openid-configuration", to: "oidc#discovery" + get "/.well-known/jwks.json", to: "oidc#jwks" + get "/oauth/authorize", to: "oidc#authorize" + post "/oauth/authorize/consent", to: "oidc#consent", as: :oauth_consent + post "/oauth/token", to: "oidc#token" + get "/oauth/userinfo", to: "oidc#userinfo" + # Authenticated routes root "dashboard#index" resource :profile, only: [:show, :update]