Class: Slack::Oauth2::Flow

Inherits:
FlowBase show all
Defined in:
lib/slack/oauth2/flow.rb

Overview

The standard OAuth 2 authorization helper.

Defined Under Namespace

Classes: BadRequestError, BadStateError, CsrfError, NotApprovedError, ProviderError

Instance Method Summary collapse

Constructor Details

#initialize(consumer_key, consumer_secret, redirect_uri, scope, team, session, csrf_token_session_key) ⇒ Flow

Returns a new instance of Flow.

Parameters:

  • consumer_key (String)

    Your Slack API app’s “app key”

  • consumer_secret (String)

    Your Slack API app’s “app secret”

  • redirect_uri (String)

    The URI that the Slack server will redirect the user to after the user finishes authorizing your app. This URI must be HTTPs-based and pre-registered with the Slack servers.

  • session (Hash)

    represents the current web app session (will be used to save the CSRF token)

  • csrf_token_key (Object)

    The key to use when storing the CSRF token in the session (for example, :slack_auth_csrf_token)



26
27
28
29
30
31
32
33
34
# File 'lib/slack/oauth2/flow.rb', line 26

def initialize(consumer_key, consumer_secret, redirect_uri, scope, team, session, csrf_token_session_key)
  super(consumer_key, consumer_secret, scope, team)
  unless redirect_uri.is_a?(String)
    raise ArgumentError, "redirect_uri must be a String, got #{consumer_secret.inspect}"
  end
  @redirect_uri = redirect_uri
  @session = session
  @csrf_token_session_key = csrf_token_session_key
end

Instance Method Details

#finish(query_params) ⇒ Object

Call this after the user has visited the authorize URL (see: start()), approved your app, and was redirected to your redirect URI.

Parameters:

  • query_params (Hash)

    The query params on the GET request to your redirect URI.

Returns:

  • Returns a tuple of (access_token, scope, url_state). access_token can be used to construct a SlackClient. scpe is the Slack scope the user that jsut approved your app. url_state is the value you originally passed in to start().

Raises:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/slack/oauth2/flow.rb', line 80

def finish(query_params)
  csrf_token_from_session = @session[@csrf_token_session_key]

  # Check well-formedness of request.

  state = query_params['state']
  if state.nil?
    raise BadRequestError.new("Missing query parameter 'state'.")
  end
  code = query_params['code']

  error = query_params['error']

  unless error.nil? || code.nil?
    raise BadRequestError.new("Query parameters 'code' and 'error' are both set;" +
    " only one must be set.")
  end
  if error.nil? && code.nil?
    raise BadRequestError.new("Neither query parameter 'code' or 'error' is set.")
  end

  # Check CSRF token

  if csrf_token_from_session.nil?
    raise BadStateError.new("Missing CSRF token in session.");
  end
  unless csrf_token_from_session.length > 20
    raise RuntimeError.new("CSRF token unexpectedly short: #{csrf_token_from_session.inspect}")
  end

  split_pos = state.index('|')
  if split_pos.nil?
    given_csrf_token = state
    url_state = nil
  else
    given_csrf_token, url_state = state.split('|', 2)
  end
  unless Slack::safe_string_equals(csrf_token_from_session, given_csrf_token)
    raise CsrfError.new("Expected #{csrf_token_from_session.inspect}, " +
                        "got #{given_csrf_token.inspect}.")
  end
  @session.delete(@csrf_token_session_key)

  # Check for error identifier

  unless error.nil?
    if error == 'access_denied'
      # The user clicked "Deny"
      raise NotApprovedError.new("No additional description from Slack.")
    else
      raise ProviderError.new(error)
    end
  end

  # If everything went ok, make the network call to get an access token.

  access_token, scope = _finish(code, @redirect_uri)
  return access_token, scope, url_state
end

#start(url_state = nil) ⇒ Object

Starts the OAuth 2 authorizaton process, which involves redirecting the user to the returned “authorization URL” (a URL on the Slack website). When the user then either approves or denies your app access, Slack will redirect them to the redirect_uri you provided to the constructor, at which point you should call finish() to complete the process.

This function will also save a CSRF token to the session and csrf_token_session_key you provided to the constructor. This CSRF token will be checked on finish() to prevent request forgery.

Parameters:

  • url_state (String) (defaults to: nil)

    Any data you would like to keep in the URL through the authorization process. This exact value will be returned to you by finish().

Returns:

  • Returns the URL to redirect the user to.



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/slack/oauth2/flow.rb', line 51

def start(url_state=nil)
  unless url_state.nil? or url_state.is_a?(String)
    raise ArgumentError, "url_state must be a String"
  end

  csrf_token = SecureRandom.base64(16)
  state = csrf_token
  unless url_state.nil?
      state += "|" + url_state
  end
  @session[@csrf_token_session_key] = csrf_token
  _get_authorize_url(@redirect_uri, state)
end