This Gem enables you to easily connect to the Zaikio Directory and use the OAuth2 flow and easily lookup matching Access Tokens.
Simply add the following in your Gemfile:
Setup & Configuration
1. Setup Active Record encryption
Setup Active Record Encryption by running:
(Continue generating the credentials each for different environments)
2. Copy & run Migrations
rails zaikio_oauth_client:install:migrations rails db:migrate
This will create the tables:
3. Mount routes
Add this to
mount Zaikio::OAuthClient::Engine => "/zaikio"
4. Configure Gem
# config/initializers/zaikio_oauth_client.rb Rails.application.reloader.to_prepare do Zaikio::OAuthClient.configure do |config| config.environment = :sandbox config.register_client :warehouse do |warehouse| warehouse.client_id = "52022d7a-7ba2-41ed-8890-97d88e6472f6" warehouse.client_secret = "ShiKTnHqEf3M8nyHQPyZgbz7" warehouse.default_scopes = %w[directory.person.r] warehouse.register_organization_connection do |org| org.default_scopes = %w[directory.organization.r] end end config.register_client :warehouse_goods_call_of do |warehouse_goods_call_of| warehouse_goods_call_of.client_id = "12345-7ba2-41ed-8890-97d88e6472f6" warehouse_goods_call_of.client_secret = "secret" warehouse_goods_call_of.default_scopes = %w[directory.person.r] warehouse_goods_call_of.register_organization_connection do |org| org.default_scopes = %w[directory.organization.r] end end config.around_auth do |access_token, block| Zaikio::Hub.with_token(access_token.token) do block.call(access_token) end end end end
5. Clean up outdated access tokens (recommended)
To avoid keeping all expired oath and refresh tokens in your database, we recommend to implement their scheduled deletion. We recommend therefore to use a schedule gems such as sidekiq and sidekiq-scheduler.
Simply add the following to your Gemfile:
gem "sidekiq" gem "sidekiq-scheduler"
Configure sidekiq scheduler in
:schedule: cleanup_access_tokens_job: cron: '0 3 * * *' # This will delete all expired tokens every day at 3am. class: 'Zaikio::CleanupAccessTokensJob'
From any point in your application you can start using the Zaikio Hub OAuth2 flow with
redirect_to zaikio_oauth_client.new_session_path # or redirect_to zaikio_oauth_client.new_session_path(client_name: 'my_other_client') # or install as organization redirect_to zaikio_oauth_client.new_connection_path(client_name: 'my_other_client')
This will redirect the user to the OAuth Authorize endpoint of the Zaikio Directory
.../oauth/authorize and include all necessary parameters like your client_id. You may
state parameters through, like so:
# Take the user directly to the signup page redirect_to zaikio_oauth_client.new_session_path(show_signup: true) # Force the user to re-authenticate even if they have an existing session redirect_to zaikio_oauth_client.new_session_path(force_login: true) # Pass a custom Oauth 2.0 state parameter redirect_to zaikio_oauth_client.new_session_path(state: "something-my-app-uses")
You can also send them to the Subscription Redirect flow, which behaves & redirects back like a regular Organization flow except it additionally sets up a subscription for the organization:
# Require them to select a plan themselves... redirect_to zaikio_oauth_client.new_subscription_path # Or preselect a plan for them redirect_to zaikio_oauth_client.new_subscription_path(plan: "free")
The Zaikio gem engine will set a cookie for the access token after a successful OAuth flow:
If you are using for example
Zaikio::Hub::Models, you can use this snippet to set the current user:
access_token = ::.(session[:zaikio_access_token_id]) session[:zaikio_access_token_id] = access_token&.id Current.user = ::Hub::Models::Person.find_by(id: access_token&.bearer_id) unless Current.user session[:origin] = request.fullpath redirect_to zaikio_oauth_client.new_session_path end
You can then use
For logout use:
zaikio_oauth_client.session_path, method: :delete or build your own controller for deleting the cookie. If you do build your own controller, please be aware that it is possible for the access token to be nil, and you should handle this accordingly.
When performing requests against directory APIs, it is important to always provide the correct client in order to use the client credentials flow correctly. Otherwise always the first client will be used. It is recommended to specify an
class ApplicationController < ActionController::Base around_action :with_client private def with_client Zaikio::OAuthClient.with_client Current.client_name do yield end end end
zaikio_oauth_client.new_session_path which was used for the first initiation of the OAuth flow, accepts an optional parameter
origin which will then be used to redirect the user at the end of a completed & successful OAuth flow.
Additionally you can also specify your own redirect handlers in your
class ApplicationController < ActionController::Base def after_approve_path_for(access_token, origin) session[:zaikio_person_id] = access_token.bearer_id unless access_token.organization? # Sync data on login Zaikio::Hub.with_token(access_token.token) do access_token.bearer_klass.find_and_reload!(access_token.bearer_id, includes: :all) end origin || main_app.root_path end def after_destroy_path_for(access_token_id) reset_session main_app.root_path end def error_path_for(error_code, description: nil) # Handle error main_app.root_path end end
Since the built in
ConnectionsController are inheriting from the main app's
ApplicationController all behaviour will be added there, too. In some cases you might want to explicitly skip a
before_action or add custom
You can achieve this by adding a custom controller name to your configuration:
# app/controllers/sessions_controller.rb class SessionsController < Zaikio::OAuthClient::SessionsController skip_before_action :redirect_unless_authenticated end # config/initializers/zaikio_oauth_client.rb Zaikio::OAuthClient.configure do |config| # ... config.sessions_controller_name = "sessions" # config.connections_controller_name = "connections" # ... end
You can use our test helper to login different users:
# test_helper.rb class ActiveSupport::TestCase # ... include Zaikio::OAuthClient::TestHelper # ... end # my_controller_test.rb class MyControllerTest < ActionDispatch::IntegrationTest test "does request" do person = people(:my_person) logged_in_as(person) # ... make the request end end
For system tests (e.g. with a separate browser instance), there's a special helper:
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase include Zaikio::OAuthClient::SystemTestHelper test "does request" do person = people(:my_person) logged_in_as(person) visit "/" end end
Now further requests to the Directory API or to other Zaikio APIs should be made. For this purpose the OAuthClient provides a helper method
with_auth that automatically fetches an access token from the database, requests a refresh token or creates a new access token via client credentials flow.
Zaikio::OAuthClient.with_auth(bearer_type: "Organization", bearer_id: "fd61f5f5-038b-44cf-b554-dfe9555f1e29", scopes: %w[directory.organization.r directory.organization_members.r]) do |access_token| # call config.around_auth with given access token end
If you need the token for a certain period (e.g. a long-running job which makes many
requests in sequence), you can specify the
valid_for interval when requesting the token.
By default, it won't return an access token which was due to expire in less than 30
seconds from now. If there is an existing token, but it was due to expire before the end
of the validity period, this will go and get a fresh token anyway:
Zaikio::OAuthClient.with_auth(..., valid_for: 10.minutes) do |access_token| # ... end
Use of dummy app
You can use the included dummy app as a showcase for the workflow and to adjust your own application. To set up the dummy application properly, go into
test/dummy and use puma-dev like this:
puma-dev link -n 'zaikio-oauth-client'
This will make the dummy app available at: http://zaikio-oauth-client.test
If you use the provided OAuth credentials from above and test this against the Sandbox, everything should work as the redirect URLs for http://zaikio-oauth-client.test are approved within the Sandbox.
Make sure you have the dummy app running locally to validate your changes.
- Make your changes and submit a pull request for them
- Make sure to update
To release a new version of the gem:
- Update the version in
CHANGELOG.mdto include the new version and its release date
- Commit and push your changes
- Create a new release on GitHub
- CircleCI will build the Gem package and push it Rubygems for you
The gem is available as open source under the terms of the MIT License.