Skip to content

Instantly share code, notes, and snippets.

@amkisko
Last active August 24, 2023 13:36
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amkisko/75974437677b9bbdc37d0b04dc28fe04 to your computer and use it in GitHub Desktop.
Save amkisko/75974437677b9bbdc37d0b04dc28fe04 to your computer and use it in GitHub Desktop.
Slack oauth2 omniauth devise implementation
<%=
button_to(omniauth_authorize_path(resource_name, provider),
method: :post,
style: "margin:1rem;align-items:center;color:#fff;background-color:#4A154B;border:0;border-radius:48px;display:inline-flex;font-family:Lato, sans-serif;font-size:16px;font-weight:600;height:48px;justify-content:center;text-decoration:none;width:256px",
"data-turbo": false) do
%>
<svg
xmlns="http://www.w3.org/2000/svg"
style="height:20px;width:20px;margin-right:12px"
viewBox="0 0 122.8 122.8"
>
<path
d="M25.8 77.6c0 7.1-5.8 12.9-12.9 12.9S0 84.7 0 77.6s5.8-12.9 12.9-12.9h12.9v12.9zm6.5 0c0-7.1 5.8-12.9 12.9-12.9s12.9 5.8 12.9 12.9v32.3c0 7.1-5.8 12.9-12.9 12.9s-12.9-5.8-12.9-12.9V77.6z"
fill="#e01e5a"
></path>
<path
d="M45.2 25.8c-7.1 0-12.9-5.8-12.9-12.9S38.1 0 45.2 0s12.9 5.8 12.9 12.9v12.9H45.2zm0 6.5c7.1 0 12.9 5.8 12.9 12.9s-5.8 12.9-12.9 12.9H12.9C5.8 58.1 0 52.3 0 45.2s5.8-12.9 12.9-12.9h32.3z"
fill="#36c5f0"
></path>
<path
d="M97 45.2c0-7.1 5.8-12.9 12.9-12.9s12.9 5.8 12.9 12.9-5.8 12.9-12.9 12.9H97V45.2zm-6.5 0c0 7.1-5.8 12.9-12.9 12.9s-12.9-5.8-12.9-12.9V12.9C64.7 5.8 70.5 0 77.6 0s12.9 5.8 12.9 12.9v32.3z"
fill="#2eb67d"
></path>
<path
d="M77.6 97c7.1 0 12.9 5.8 12.9 12.9s-5.8 12.9-12.9 12.9-12.9-5.8-12.9-12.9V97h12.9zm0-6.5c-7.1 0-12.9-5.8-12.9-12.9s5.8-12.9 12.9-12.9h32.3c7.1 0 12.9 5.8 12.9 12.9s-5.8 12.9-12.9 12.9H77.6z"
fill="#ecb22e"
></path>
</svg>
Sign in with Slack
<% end %>
require "omniauth/slack_oauth2"
config.omniauth(
:slack_oauth2,
ENV.fetch("SLACK_CLIENT_ID"),
ENV.fetch("SLACK_CLIENT_SECRET"),
{
scope: "openid,email,profile",
redirect_uri: Rails.env.development? ? "https://localhost:3000/user/auth/slack_oauth2/callback" : nil,
provider_ignores_state: Rails.env.development?
}
)
class User::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
# NOTE: slack redirect_url is https://host:port/user/auth/slack_oauth2/callback
def slack_oauth2
if !auth[:extra][:data].email_verified ||
auth[:extra][:data].team_domain != ENV.fetch("SLACK_TEAM_DOMAIN")
redirect_to root_path, alert: "You are not authorized to use this app."
return
end
user_session =
UserSession.find_by(provider: auth["provider"], uid: auth["uid"])
@user = user_session&.user || User.find_or_create_with_omniauth(auth)
user_session ||=
@user.user_sessions.find_or_create_by(provider: auth["provider"])
user_session.assign_attributes(
name: auth["info"]["name"],
avatar_url: auth["info"]["image"]
)
user_session.data = {
"access_token" => auth.credentials.token,
"user_id" => auth[:extra][:data].user_id,
"team_id" => auth[:extra][:data].team_id,
"name" => auth[:extra][:data].name,
"team_name" => auth[:extra][:data].team_name,
"team_domain" => auth[:extra][:data].team_domain,
"picture" => auth[:extra][:data].picture
}
user_session.save!
flash[:notice] = I18n.t("devise.omniauth_callbacks.success", kind: "Slack")
sign_in @user
redirect_to root_path
end
def auth
request.env["omniauth.auth"]
end
end
devise_for(
:user,
controllers: {
sessions: "user/sessions",
omniauth_callbacks: "user/omniauth_callbacks"
}
)
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<% case provider %>
<% when :google_oauth2 %>
<%= render partial: "google_button", locals: { provider: provider, resource_name: resource_name } %>
<% when :slack_oauth2 %>
<%= render partial: "slack_button", locals: { provider: provider, resource_name: resource_name } %>
<% end %>
<% end %>
<% end %>
require "omniauth/strategies/oauth2"
module OmniAuth
module Strategies
class SlackOauth2 < OmniAuth::Strategies::OAuth2
AUTH_OPTIONS = %i[scope user_scope team team_domain]
INFO_DATA =
Data.define(
:user_id,
:team_id,
:email,
:email_verified,
:name,
:picture,
:given_name,
:family_name,
:locale,
:team_name,
:team_domain
)
option :name, "slack_oauth2"
option :client_options,
{
site: "https://slack.com",
authorize_url: "/openid/connect/authorize",
token_url: "/api/openid.connect.token"
}
option :redirect_uri
uid {
"#{raw_info.dig("https://slack.com/team_id")}-#{raw_info.dig("https://slack.com/user_id")}"
}
info { {
name: raw_info.dig("name"),
email: raw_info.dig("email"),
image: raw_info.dig("picture")
} }
extra do
{
data:
INFO_DATA.new(
user_id: raw_info.dig("https://slack.com/user_id"),
team_id: raw_info.dig("https://slack.com/team_id"),
email: raw_info.dig("email"),
email_verified: raw_info.dig("email_verified"),
name: raw_info.dig("name"),
picture: raw_info.dig("picture"),
given_name: raw_info.dig("given_name"),
family_name: raw_info.dig("family_name"),
locale: raw_info.dig("locale"),
team_name: raw_info.dig("https://slack.com/team_name"),
team_domain: raw_info.dig("https://slack.com/team_domain")
),
raw_info: raw_info
}
end
def callback_url
options.redirect_uri || full_host + script_name + callback_path
end
def raw_info
@raw_info ||= access_token.get("/api/openid.connect.userInfo").parsed
end
end
end
end
devise(
:database_authenticatable,
:trackable,
:omniauthable,
omniauth_providers: %i[google_oauth2 slack_oauth2]
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment