weibeu / Flask-Discord

Discord OAuth2 extension for Flask. An Easier implementation of "Log In With Discord".
https://flask-discord.readthedocs.io/en/latest/
MIT License
183 stars 47 forks source link

Secret doesn't end up in JWT #66

Open Mister-SOSA opened 1 year ago

Mister-SOSA commented 1 year ago

Some Contextual Information: Python v3.10 JWT v.2.6.0 OS: Ubuntu

Firstly, I am constructing a DiscordOAuth2Session() like so (I have shuffled up all the values to protect my application):

app = Flask(__name__)
app.config["SECRET_KEY"] = 'os.urandom(24)'

os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "true"

app.config["DISCORD_CLIENT_ID"] = 398041555473157536
app.config["DISCORD_CLIENT_SECRET"] = "LQYn4UiOgyIJspje6Y1aueKwK2Ccwput"            
app.config["DISCORD_REDIRECT_URI"] = "http://mysite.net/callback/"             
app.config["DISCORD_BOT_TOKEN"] = "QNkkzNjoyODgzFzE2EzU4MjI1.BVHlrQ.kdCdDeAKzFXYByMkB3_zVIaosQrQFO4Us6tjdQ" 

discord = DiscordOAuth2Session(app)

I then specify my callback address and input it into the Discord Developer Panel:

@app.route("/callback/")
def callback():
    discord.callback()
    user = discord.fetch_user()
    return redirect('/')

@app.errorhandler(Unauthorized)
def redirect_unauthorized(e):
    return redirect(url_for("login"))

image

Upon trying to access a @requires_authorization location on my site, I am redirected to the Discord OAuth screen, perfect so far. All the information displayed on this screen is correct.

As soon as I click "Authorize," I am redirected to what appears to be the correct location on my website, with a Flask traceback indicating some sort of problem with JWT.

The traceback:

Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.10/site-packages/jwt/api_jws.py", line 251, in _load
    signing_input, crypto_segment = jwt.rsplit(b".", 1)
ValueError: not enough values to unpack (expected 2, got 1)

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask/app.py", line 2548, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask/app.py", line 2528, in wsgi_app
    response = self.handle_exception(e)
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask/app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/home/ubuntu/discord_bot/web/flask/main.py", line 48, in callback
    discord.callback()
  File "/home/ubuntu/.local/lib/python3.10/site-packages/flask_discord/client.py", line 161, in callback
    return jwt.decode(state, current_app.config["SECRET_KEY"], algorithms="HS256")
  File "/home/ubuntu/.local/lib/python3.10/site-packages/jwt/api_jwt.py", line 168, in decode
    decoded = self.decode_complete(
  File "/home/ubuntu/.local/lib/python3.10/site-packages/jwt/api_jwt.py", line 120, in decode_complete
    decoded = api_jws.decode_complete(
  File "/home/ubuntu/.local/lib/python3.10/site-packages/jwt/api_jws.py", line 191, in decode_complete
    payload, signing_input, header, signature = self._load(jwt)
  File "/home/ubuntu/.local/lib/python3.10/site-packages/jwt/api_jws.py", line 254, in _load
    raise DecodeError("Not enough segments") from err
jwt.exceptions.DecodeError: Not enough segments

It's hard for me to tell exactly what is wrong, as I am not very good at cracking modules open myself, but this is what I was able to find.

I've tried several different types of secrets to no avail, and I am currently torn between this being my own error or not. If someone has more details, please let me know.

weibeu commented 1 year ago

Check if this helps https://github.com/weibeu/Flask-Discord/issues/56#issuecomment-985147104 Additionally, re-check just in case that your callback URL configured in config and that on dashboard are exactly same. Including http/https URL scheme

Mister-SOSA commented 1 year ago

I feel fairly confident that I have done this part correctly, but anything is possible when I take on a project. Here's what I have:

In main.py: app.config["DISCORD_REDIRECT_URI"] = "http://XXXXX.net/callback/"

On my Discord Developer Dashboard: http://XXXXX.net/callback/

What appears in the addressbar after I click "Authorize": http://XXXXX.net/callback/?code=NfqYd9YQqieAGCEjHhhHUeXceBr3hz&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfX3N0YXRlX3NlY3JldF8iOiJxQTV5dzU2dHZoY0VMVXI5TmJ2c052NVlqTW5ieEQifQ.DxB1RwizZnLMBFikrGkEQf5OKvFy4QLgrNXu_kKuGuM

My @app.route():

@app.route("/callback/")
def callback():
    discord.callback() # <--- Error occurs here according to traceback
    user = discord.fetch_user()
    return redirect('/')

Setting my secret key:

app.config["SECRET_KEY"] = os.urandom(24)
Mister-SOSA commented 1 year ago

Some newfound information.

In callback(self) at line 142, self.__get_state() returns nothing. If I try to print it, it's an empty string, which leads me to believe that this item is not in my session when it is called? That would explain why there isn't enough segments when it's passed to jwt.decode()

weibeu commented 1 year ago

Sounds either of the following or something similar could be happening:

fizzrepo commented 11 months ago

Hello @Mister-SOSA - If you still need this to be fixed, you need to change this line. https://github.com/weibeu/Flask-Discord/pull/74