Socket
Book a DemoInstallSign in
Socket

omniauth_oidc

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

omniauth_oidc

0.2.6
bundlerRubygems
Version published
Maintainers
1
Created
Source

OmniAuth::Oidc

This gem provides an OmniAuth strategy for integrating OpenID Connect (OIDC) authentication into your Ruby on Rails application. It allows seamless login using various OIDC providers.

Developed with reference to omniauth-openid-connect and omniauth_openid_connect.

Article on Medium about the development of this gem.

Installation

To install the gem run the following command in the terminal:

$ bundle add omniauth_oidc

If bundler is not being used to manage dependencies, install the gem by executing:

$ gem install omniauth_oidc

Usage

To use the OmniAuth OIDC strategy, you need to configure your Rails application and set up the necessary environment variables for OIDC client credentials.

Configuration

You have to provide Client ID, Client Secret and url for the OIDC configuration endpoint as a bare minimum for the omniauth_oidc to work properly. Create an initializer file at config/initializers/omniauth.rb

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :oidc, {
    name: :simple_provider, # used for dynamic routing
    client_options: {
      identifier: '23575f4602bebbd9a17dbc38d85bd1a77',
      secret: ENV['SIMPLE_PROVIDER_CLIENT_SECRET'],
      config_endpoint: 'https://simpleprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/.well-known/openid-configuration'
    }
  }
end

With Devise

Devise.setup do |config|
  config.omniauth :oidc, {
    name: :simple_provider,
    scope: [:openid, :email, :profile, :address],
    response_type: :code,
    uid_field: "preferred_username",
    client_options: {
      identifier: '23575f4602bebbd9a17dbc38d85bd1a77',
      secret: ENV['SIMPLE_PROVIDER_CLIENT_SECRET'],
      config_endpoint: 'https://simpleprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/.well-known/openid-configuration'
    }
  }
end

The gem also supports a wide range of optional parameters for higher degree of configurability.

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :oidc, {
    name: :complex_provider, # used for dynamic routing
    issuer: 'https://complexprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77',
    scope: [:openid],
    response_type: 'id_token',
    require_state: true,
    response_mode: :query,
    prompt: :login,
    send_nonce: false,
    uid_field: "sub",
    pkce: false,
    client_options: {
      identifier: '23575f4602bebbd9a17dbc38d85bd1a77',
      secret: ENV['COMPLEX_PROVIDER_CLIENT_SECRET'],
      config_endpoint: 'https://complexprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/.well-known/openid-configuration',
      host: 'complexprovider.com'
      scheme: "https",
      port: 443,
      authorization_endpoint: 'https://complexprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/authorization',
      token_endpoint: 'https://complexprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/token',
      userinfo_endpoint: 'https://complexprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/userinfo',
      jwks_uri: 'https://complexprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/jwks',
      end_session_endpoint: '/signout'
    }
  }
end

Ensure to replace identifier, secret, configuration endpoint url and others with credentials received from your OIDC provider. Please note that the gem does not accept redirect_uri as a configurable option. For details please see section Routes.

Redirecting for Authentication

Buttons and links to initialize the authentication request can be placed on relevant pages as below:

<%= button_to "Login with Simple Provider", "/auth/simple_provider" %>

Handling Callbacks

The gem uses dyanmic routes to handle different phases, and while you can use same routes in your Rails application, for better experience you should have a controller to process the authenticated user. Create a CallbacksController:

# app/controllers/callbacks_controller.rb
class CallbacksController < ApplicationController
  def omniauth
    # user info received from OIDC provider will be available in `request.env['omniauth.auth']`
    auth = request.env['omniauth.auth']

    user = User.find_or_create_by(uid: auth['uid']) do |user|
      user.name = auth['info']['name']
      user.email = auth['info']['email']
    end

    session[:user_id] = user.id
    redirect_to root_path, notice: 'Successfully logged in!'
  end
end

Routes

The gem uses dynamic routes when making requests to the OIDC provider endpoints, so called redirect_uri which is a non-configurable value that follows the naming pattern of https://your_app.com/auth/<simple_provider>/callback, where <simple_provider> is the provider name defined within the configuration of the omniauth.rb initializer. This represents the redirect_uri that will be passed with the authorization request to your OIDC provider and that has to be registered with your OIDC provider as permitted redirect_uri.

Dynamic routes are used to process responses and perform intermediary steps by the middleware, e.g. request phase, token verification. While you can define and use same routes within your Rails app, it is highly recommended to modify your routes.rb to perform a dynamic redirect to a another controller method so this does not cause any conflicts with the middleware or the authorization flow.

In an example below, auth/:provider/callback is generalized redirect_uri value that is passed in the authorization flow, while all OIDC provider responses are ultimately redirected to the omniauth method of the callbacks_controller, which could be a "Swiss army knife" method to handle authentication or user data from various omniauth providers:

# config/routes.rb
Rails.application.routes.draw do
  match 'auth/:provider/callback', via: :get, to: "callbacks#omniauth"
end

Alternatively, you can specify separate redirects for some of your OIDC providers, in case you need to handle responses differently:

# config/routes.rb
Rails.application.routes.draw do
  match 'auth/simple_provider/callback', via: :get, to: "callbacks#simple_provider"
  match 'auth/complex_provider/callback', via: :get, to: "callbacks#complex_provider"

  # you can add the line below if you would like the rest of the providers to be redirected to a universal `omniauth` method
  match 'auth/:provider/callback', via: :get, to: "callbacks#omniauth"
end

Please note that you should register https://your_app.com/auth/<simple_provider>/callback with your OIDC provider as a callback redirect url.

Using Access Token Without User Info

In case your app requries only an access token and not the user information, then you can specify an optional configuration in the omniauth initializer:

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :oidc, {
    name: :simple_provider_access_token_only,
    fetch_user_info: false, # if not specified, default value of true will be applied
    client_options: {
      identifier: '23575f4602bebbd9a17dbc38d85bd1a77',
      secret: ENV['SIMPLE_PROVIDER_CLIENT_SECRET'],
      config_endpoint: 'https://simpleprovider.com/cdn-cgi/access/sso/oidc/23575f4602bebbd9a17dbc38d85bd1a77/.well-known/openid-configuration'
    }
  }
end

Then the callback returned once your user authenticates with the OIDC provider will contain only access token parameters:

# app/controllers/callbacks_controller.rb
class CallbacksController < ApplicationController
  def omniauth
    # access token parameters received from OIDC provider will be available in `request.env['omniauth.auth']`
    omniauth_params = request.env['omniauth.auth']

    # omniauth_params will contain similar data as shown below
    # {"provider"=>:simple_provider_access_token_only,
    #  "credentials"=>
    #   {"id_token"=> "id token value",
    #    "token"=> "token value",
    #    "refresh_token"=>"refresh token value",
    #    "expires_in"=>300,
    #    "scope"=>nil
    #   }
    # }
  end
end

Ending Session

The gem provides two configuration options to allow ending a session simultaneously with your client application and the OIDC provider.

To use this feature, you need to provide a logout_path in the options and an end_session_endpoint in the client options. Here’s a sample setup:

  provider :oidc, {
    name: :simple_provider,
    client_options: {
      identifier: ENV['SIMPLE_PROVIDER_CLIENT_ID'],
      secret: ENV['SIMPLE_PROVIDER_SECRET'],
      config_endpoint: 'https://simpleprovider.com/1234567890/.well-known/openid-configuration',
      end_session_endpoint: 'https://simpleprovider.com/signout' # URL to end session with OIDC provider
    },
    logout_path: '/logout' # path in your application to end user session
  }
  • end_session_endpoint is the URL to which your client app can redirect to log out the user from the OIDC provider's application. It can be dynamically fetched from the config_endpoint response if your OIDC provider specifies it there. Alternatively, you can explicitly provide it in the client options.

  • logout_path is the URL in your application that can be called to terminate the current user's session.

Using these two configurations, you can ensure that when a user logs out from your application, they are also logged out from the OIDC provider, providing a seamless logout across multiple services.

This works by calling other_phase on every controller request in your application. The method checks if the requested URL matches the defined logout_path. If it does (i.e. current user has requested to log out from your application) other_phase performs a redirect to the end_session_endpoint to terminate the user's session with the OIDC provider and then it returns back to your application and concludes the request to end the current user's session.

For additional details please refer to the OIDC specification.

Advanced Configuration

You can customize the OIDC strategy further by adding additional configuration options:

FieldDescriptionRequiredDefault ValueExample/Notes
nameArbitrary string to identify OIDC provider and segregate it from other OIDC providersno"oidc":simple_provider
issuerRoot url for the OIDC authorization servernoretrived from config_endpoint"https://simpleprovider.com"
fetch_user_infoFetches user information from user_info_endpoint using the access token. If set to false the omniauth params will include only access tokennotruefetch_user_info: false
client_auth_methodAuthentication method to be used with the OIDC authorization serverno:basic"basic", "jwks"
scopeOIDC scopes to be included in the server's response[:openid] is requiredall scopes offered by OIDC provider[:openid, :profile, :email]
response_typeOAuth2 response type expected from OIDC provider during authorizationno"code""code" or "id_token"
stateValue to be used for the OAuth2 state parameter on the authorization request. Can be a proc that generates a stringnoRandom 16 character stringProc.new { SecureRandom.hex(32) }
require_stateBoolean to indicate if state param should be verified. This is a recommendation by OIDC specnotruetrue or false
response_modeThe response mode per OIDC specnonil:query, :fragment, :form_post or :web_message
displaySpecifies how OIDC authorization server should display the authentication and consent UI pages to the end usernonil:page, :popup, :touch or :wap
promptSpecifies whether the OIDC authorization server prompts the end user for reauthentication and consentnonil:none, :login, :consent or :select_account
send_scope_to_token_endpointShould the scope parameter be sent to the authorization token endpointnotruetrue or false
post_logout_redirect_uriLogout redirect uri to use per the session management draftnonil"https://your_app.com/logout/callback"
uid_fieldField of the user info response to be used as a unique IDno'sub'"sub" or "preferred_username"
extra_authorize_paramsHash of extra fixed parameters that will be merged to the authorization requestno{}{"tenant" => "common"}
allow_authorize_paramsList of allowed dynamic parameters that will be merged to the authorization requestno[][:screen_name]
pkceEnable PKCE flownofalsetrue or false
pkce_verifierSpecify custom PKCE verifier codenoRandom 128-character stringProc.new { SecureRandom.hex(64) }
pkce_optionsSpecify custom implementation of the PKCE code challenge/methodnoSHA256(code_challenge) in hexProc to customise the code challenge generation
client_optionsHash of client options detailed below in a separate tableyessee belowsee below
jwt_secret_base64Specify the base64-encoded secret used to sign the JWT token for HMAC with SHA2 (e.g. HS256) signing algorithmsnoclient_options.secret"bXlzZWNyZXQ=\n"
logout_pathLog out is only triggered when the request path ends on this pathno'/logout''/sign_out'
acr_valuesAuthentication Class Reference (ACR) values to be passed to the authorize_uri to enforce a specific level, see RFC9470nonil"c1 c2" å

Below are options for the client_options hash of the configuration:

FieldDescriptionRequiredDefault value
identifierOAuth2 client_idyesnil
secretOAuth2 client secretyesnil
config_endpointOIDC configuration endpointyesnil
schemehttp scheme to usenohttps
hosthost of the authorization servernonil
portport for the authorization serverno443
authorization_endpointauthorize endpoint on the authorization servernoretrived from config_endpoint
token_endpointtoken endpoint on the authorization servernoretrived from config_endpoint
userinfo_endpointuser info endpoint on the authorization servernoretrived from config_endpoint
jwks_urijwks_uri on the authorization servernoretrived from config_endpoint
end_session_endpointurl to call to log the user out at the authorization servernonil

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/msuliq/omniauth_oidc. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the OmniauthOidc project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

FAQs

Package last updated on 16 Oct 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.