title: oath2 - Authorization Code Grant with Flask (accessing bitbucket)?
body: <p>I'm testing various <code>oath2</code> workflows and the one I'm strugglink to, is <code>Authorization Code Grant</code>.</p>
  
  <p>I can successfully get a token If I copy/paste urls in a straight forward way. </p>
  
  <p>I mean <code>request access</code>, <code>copy paste given URl</code>, <code>enter it in a browser</code>, <code>accept authorization</code>, <code>copy paste back callback url</code> -> <strong>access resources</strong>. Like in this example:</p>
  
  <pre><code>from requests_oauthlib import OAuth2Session
  
  
  class ClientSecrets:
      """
      The structure of this class follows Google convention for `client_secrets.json`:
      https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
      Bitbucket does not emit this structure so it must be manually constructed.
      """
      client_id = "myid"
      client_secret = "mysecret"
      auth_uri = "https://bitbucket.org/site/oauth2/authorize"
      token_uri = "https://bitbucket.org/site/oauth2/access_token"
      server_base_uri = "https://api.bitbucket.org/"
  
  
  def main():
      c = ClientSecrets()
      # Fetch a request token
      bitbucket = OAuth2Session(c.client_id)
      # Redirect user to Bitbucket for authorization
      authorization_url = bitbucket.authorization_url(c.auth_uri)
      print('Please go here and authorize: {}'.format(authorization_url[0]))
      # Get the authorization verifier code from the callback url
      redirect_response = raw_input('Paste the full redirect URL here:')
      # Fetch the access token
      bitbucket.fetch_token(
        c.token_uri,
        authorization_response=redirect_response,
        username=c.client_id,
        password=c.client_secret)
      # Fetch a protected resource, i.e. user profile
      r = bitbucket.get(c.server_base_uri + '1.0/user')
      print(r.content)
  </code></pre>
  
  <p>Though if I try to do that using Flask imitating actual web app that tries to get access to bitbucket, it fails to get access.</p>
  
  <p>My Flask app implementation sample looks like this:</p>
  
  <pre><code>from flask import Flask, redirect, request, session
  
  from requests_oauthlib import OAuth2Session
  
  app = Flask(__name__)
  
  client_id = 'myid'
  client_secret = 'mysecret'
  authorization_base_url = 'https://bitbucket.org/site/oauth2/authorize'
  token_url = 'https://bitbucket.org/site/oauth2/access_token'
  redirect_uri = 'https://127.0.0.1:5000/callback'
  
  
  @app.route('/login')
  def login():
      oauth2 = OAuth2Session(client_id, redirect_uri=redirect_uri)
      authorization_url, state = oauth2.authorization_url(
          authorization_base_url,
  
      )
      # State is used to prevent CSRF, keep this for later.
      session['oauth_state'] = state
      return redirect(authorization_url)
  
  
  @app.route("/callback")
  def callback():
      bitbucket = OAuth2Session(client_id, state=session['oauth_state'])
      bitbucket.fetch_token(
          token_url,
          client_secret=client_secret,
          authorization_response=request.url)
      return bitbucket.get('some_resource_url').content
  
  if __name__ == '__main__':
      # Certificate and key files.
      context = ('cert/server.crt', 'cert/server.key')
      app.run(debug=True, ssl_context=context)
  </code></pre>
  
  <p>If I run app like in example, then I get this error when trying to access URL: <code>https://127.0.0.1:5000/login</code></p>
  
  <pre><code>File "/home/oerp/python-programs/flask-app/bitiface/test.py", line 23, in login
      session['oauth_state'] = state
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/werkzeug/local.py", line 350, in __setitem__
      self._get_current_object()[key] = value
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/sessions.py", line 130, in _fail
      raise RuntimeError('The session is unavailable because no secret '
  RuntimeError: The session is unavailable because no secret key was set.  Set the secret_key on the application to something unique and secret.
  </code></pre>
  
  <p>It looks like that something todo with <code>oath_state</code>. If I comment <code>oath_state</code> assigning and try to run app like before. Then I get this error:</p>
  
  <pre><code>Traceback (most recent call last):
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1994, in __call__
      return self.wsgi_app(environ, start_response)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
      response = self.handle_exception(e)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
      reraise(exc_type, exc_value, tb)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
      response = self.full_dispatch_request()
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
      rv = self.handle_user_exception(e)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
      reraise(exc_type, exc_value, tb)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
      rv = self.dispatch_request()
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
      return self.view_functions[rule.endpoint](**req.view_args)
    File "/home/oerp/python-programs/flask-app/bitiface/test.py", line 33, in callback
      authorization_response=request.url)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 244, in fetch_token
      self._client.parse_request_body_response(r.text, scope=self.scope)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
      self.token = parse_token_response(body, scope=scope)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
      validate_token_parameters(params)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
      raise_from_error(params.get('error'), params)
    File "/home/oerp/python-programs/flask-app/bitiface/venv/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 325, in raise_from_error
      raise cls(**kwargs)
  InvalidClientIdError: (invalid_request) redirect_uri does not match
  </code></pre>
  
  <p>It looks like if I skip <code>oath_session</code>, then it actually starts new session on callback and redirect_uri will not match or something like that.</p>
  
  <p><strong>Does anyone know what could be the problem?</strong></p>
  
  <p><strong>Update</strong></p>
  
  <p>I updated Flask with <code>secret_key</code>, so error regarding no <code>secret_key</code> is gone, but the second error is still there. This error: <code>InvalidClientIdError: (invalid_request) redirect_uri does not match</code> is raised at this part of code:</p>
  
  <pre><code>...
  ...
  bitbucket.fetch_token(
      token_url,
      client_secret=client_secret,
      authorization_response=request.url)
  ...
  ...
  </code></pre>
  
  <p>I do not know if this is related, but printing <code>request.url</code>, it gives me this: <code>https://127.0.0.1:5000/callback?state=[bunch_of_random_symbols]</code>. So the first part <code>https://127.0.0.1:5000/callback</code> is exactly the same as I I set on consumer to be callback URL. To me it looks like it is actually matching.
  `</p>
  
  <p>P.S. Full traceback is provided.</p>