ueberauth / ueberauth_slack

Slack OAuth2 Strategy for Überauth
MIT License
23 stars 33 forks source link

Support for V2 Oauth API #35

Open emilsoman opened 4 years ago

emilsoman commented 4 years ago

Slack now allows apps to configure granular scopes for the bot token. This uses a new version of their oauth URLs and also changes the structure of the callback payload. More information here: https://api.slack.com/authentication/oauth-v2. If you upgrade to this version, it looks like you cannot go back to using the old version and you'll get a oauth_authorization_url_mismatch error.

To solve this (until the default oauth URLs in ueberauth_slack are changed):

  1. Override authorize_url and token_url in your config:
    config :ueberauth, Ueberauth.Strategy.Slack.OAuth,
    client_id: System.get_env("SLACK_CLIENT_ID"),
    client_secret: System.get_env("SLACK_CLIENT_SECRET"),
    authorize_url: "https://slack.com/oauth/v2/authorize",
    token_url: "https://slack.com/api/oauth.v2.access"
  2. Change your callback function in AuthController to support the new payload structure. Compare the responses of https://api.slack.com/methods/oauth.access and https://api.slack.com/methods/oauth.v2.access to get an idea.
doomspork commented 4 years ago

Hi @emilsoman, thanks for opening this issue, this should absolutely be on the radar! I also appreciate you documenting the workaround for others :grin:

@scrogson what is the status of the oauth lib changes you had mentioned? Are we good to start to migration to that version of the oauth lib?

emilsoman commented 4 years ago

Another related breaking change with the v2 API - if you don't use any "bot" related scope, for example when using the "Sign in with Slack" button using only identity related scopes, Slack doesn't send you any bot access token. Instead, it sends the user access token in a map nested under the key "authed_user" (see https://api.slack.com/methods/oauth.v2.access). This will cause an error in ueberauth_slack because it expects an :access_token to be present in the root level of the response (here's the old response: https://api.slack.com/methods/oauth.access).

I've fixed this in a fork to unblock my work: https://github.com/emilsoman/ueberauth_slack/commit/4b428e06f6287bb72d4314398fd91fc2f2e5839c. Do you want to take this change in? Let me know if this needs more changes please.

acconrad commented 4 years ago

@doomspork we need to get this in because new apps are requiring OAuth v2 access and I can't log in anymore because I'm getting a oauth_authorization_url_mismatch error which, according to the documentation, says:

The OAuth flow was initiated on an incorrect version of the authorization url. The flow must be initiated via /oauth/v2/authorize

I am using @emilsoman 's code to get around this

doomspork commented 4 years ago

@acconrad okay, do you need me to release a new version?

acconrad commented 4 years ago

@doomspork yes that would be helpful!

doomspork commented 4 years ago

@acconrad don't we need the change from @emilsoman? Are you opening a PR?

In the future it is best to ping the team and not just me directly, I can swamped at times.

acconrad commented 4 years ago

can we merge that branch in?

Hanspagh commented 4 years ago

@emilsoman can you open a pr, then we can get started on this

ream88 commented 4 years ago

I needed to change fetch_identity as well to get it working for me:

defp fetch_identity(conn, token) do
  scope_string = token.other_params["authed_user"]["scope"] || ""
  scopes = String.split(scope_string, ",")

  user_token = OAuth2.AccessToken.new(token.other_params["authed_user"])

  case "identity.basic" in scopes do
    false ->
      conn

    true ->
      case Ueberauth.Strategy.Slack.OAuth.get(user_token, "/users.identity") do
        {:ok, %OAuth2.Response{status_code: 401, body: _body}} ->
          set_errors!(conn, [error("token", "unauthorized")])

        {:ok, %OAuth2.Response{status_code: status_code, body: identity}}
        when status_code in 200..399 ->
          if identity["ok"] do
            put_private(conn, :slack_identity, identity)
          else
            set_errors!(conn, [error(identity["error"], identity["error"])])
          end

        {:error, %OAuth2.Error{reason: reason}} ->
          set_errors!(conn, [error("OAuth2", reason)])
      end
  end
end
ream88 commented 4 years ago

I think once my mix format branch is merged, I can help with this issue here 😊

emilsoman commented 4 years ago

Unfortunately I am not able to work on this PR at the moment. @ream88 thanks for pitching in, please feel free to take my code if needed.

Hanspagh commented 4 years ago

Format pr has now been merged. Let me know if you need nay help

jsmestad commented 3 years ago

Looking deeper into the new Slack OAuth V2 endpoint, it actually is quite a bit different than their old one. They introduced "bot tokens" versus "user tokens" both coming back from a single oauth call.

I still have to figure out how best to handle two distinct tokens coming back from one OAuth workflow. I created a detached fork called ueberauth_slack_v2 so I can specifically handle this unique two token flow.

It is still a work in progress to figure out the ins-and-outs of handling two tokens, but you should be able to copy some of the changes to make this library drop the bot token and only use the user token.

messutied commented 3 years ago

What is the current state of this efforts? let me know if I can be of help on the PR/fork.

chasers commented 3 years ago

@jsmestad thanks for this ... using your fork for now!