Skip to content

tanmer/doorkeeper-sso

Repository files navigation

Doorkeeper SSO

This gem makes Doorkeeper acts as real SSO(Single-Sign-On)/SLO(Single-Log-Out) system. Original doorkeeper can be a SSO system, but it isn't a SLO system, which mean one place logout, another place and Account center still be logged in. With this gem, all places will be logged out.

Theory

# from SSO Web site

sequenceDiagram

Browser ->> SSO Web Site: #
SSO Web Site ->> SSO Web Site: generate session guid
SSO Web Site -->> Browser: # successfully, write session guid to cookie
Loading

# from SSO Web site to App

sequenceDiagram
Browser ->> App: #
App -->> Browser: redirect to SSO for code
Browser -->> SSO Web Site: redirect to /oauth/authorize
SSO Web Site -->> SSO Web Site: generate code and relate it to session guid
SSO Web Site -->> Browser: redirect back to App with code
Browser -->> App: Send authorization code
App -->> SSO Web Site: exchange access token with code, POST /oauth/token
SSO Web Site -->> SSO Web Site: generate access token and relate it to session guid according to code
SSO Web Site -->> App: response access token
App -->> Browser: write access token to cookie
Loading

Check # status in App

sequenceDiagram
Browser ->> App: check # status
App -->> SSO Web Site: get profile by access token
SSO Web Site -->> SSO Web Site: validate access token, check if related session guid is logged out
SSO Web Site -->> App: valid access token
App -->> Browser: user signed in
Loading

Sign out from App

sequenceDiagram
Browser ->> App: DELETE /sign-out
App ->> SSO Web Site: POST /oauth/revoke?token=xxx
App -->> Browser: Sign out successfully, delete access token from cookie
Loading

Or sign out from SSO Web Site

sequenceDiagram
Browser ->> SSO Web Site: DELETE /sign-out
SSO Web Site -->> SSO Web Site: make session guid as logged out, expire related access tokens
SSO Web Site -->> Browser: Sign out successfully, delete session guid and credentials from cookie
Loading

Usage

requirements

gem 'doorkeeper', '~ 5.1'
bundle i
rails g doorkeeper:install
rails g doorkeeper:migration
rake doorkeeper_sso:install:migrations
rails db:migrate

configuration

# config/initializers/doorkeeper_sso.rb

# callback: signed in from controller
Doorkeeper::SSO.on_signed_in = ->(controller:, cookies:, session:, sso_session:) {
  puts "-> user signed in: #{sso_session.guid} - #{sso_session.ip_address} - #{sso_session.user_agent}"
}

# callback: signed out from controller
Doorkeeper::SSO.on_signed_out = ->(controller:, cookies:, session:, sso_session:) {
  puts "-> user signed out: #{sso_session.guid}"
}

in your session controller, such as `app/controller/sessions_controller.rb'

def create
  user = User.from(params[:username], params[:password])
  if user
    Doorkeeper::SSO::Session.sign_in!(self, user: user) do |session:, **_|
      session[:user_id] = user.id
    end
    flash[:notice] = 'signed in successfully!'
    redirect_to home_path
  else
    flash[:alert] = 'invalid email or password'
    render :new
  end
end

def destroy
    Doorkeeper::SSO::Session.sign_out!(self) do |session:, **_|
      session.delete :user_id
    end
    redirect_to root_path
end

in current_user helper, we have to check session(Warden/Devise session) and cookies[Doorkeeper::SSO.cookie_name], because a user maybe logged out from API, we just marked Doorkeeper::SSO::Session#signed_out = true, do touch cookies.

def current_user
  return @current_user if instance_variable_defined?(:@current_user)

  sso_session = Doorkeeper::SSO::Session.from_cookie(cookies)
  user = User.find_by(id: session[:user_id])
  if sso_session && user && sso_session.resource_owner_id == user.id
    @current_user = user
  else
    @current_user = nil
  end
end

Installation

Add this line to your application's Gemfile:

gem 'doorkeeper-sso'

And then execute:

$ bundle

Or install it yourself as:

$ gem install doorkeeper-sso

Contributing

Contribution directions go here.

License

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

Releases

No releases published

Packages

No packages published