Skip to content

Commit bfbdf31

Browse files
committed
Fix #2 and #5, bump version to 0.1.1
Fix for #2 - PyPI installation should properly install the lib's dependencies now To address #5 - Optional 'state' and 'prompt' kwargs have been added to DiscordOAuthClient.redirect() Some small housekeeping with example and test scripts. Set discord.py dependency to <=1.7,<2 to prepare for discord.py 2.0 release possibly in the near future. Bumped version to 0.1.1! 🎉
1 parent 3a10a55 commit bfbdf31

File tree

9 files changed

+81
-14
lines changed

9 files changed

+81
-14
lines changed

examples/session_handling_fastapi.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@
77

88
import secrets
99
import uvicorn
10-
from fastapi import FastAPI, HTTPException
10+
from fastapi import FastAPI
1111
from starlette.requests import Request
1212
from starlette.responses import RedirectResponse
13+
from starlette.exceptions import HTTPException
1314
from starlette.middleware.sessions import SessionMiddleware
1415
from starlette_discord.client import DiscordOAuthClient
1516

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
discord.py
1+
discord.py>=1.7,<2
22
oauthlib
33
starlette>=0.13.6

setup.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', fp.read(), re.MULTILINE).group(1)
1111

1212

13+
with open('requirements.txt') as f:
14+
requirements = f.read().splitlines()
15+
16+
1317
setuptools.setup(
1418
name='starlette-discord',
1519
author='nwunderly',
@@ -21,14 +25,15 @@
2125
description='"Login with Discord" support for Starlette and FastAPI.',
2226
long_description=long_description,
2327
long_description_content_type='text/markdown',
28+
install_requires=requirements,
2429
extras_require={
2530
'docs': [
2631
'sphinx',
2732
'sphinxcontrib_trio',
2833
],
2934
},
30-
packages=setuptools.find_packages(),
3135
python_requires='>=3.8',
36+
packages=setuptools.find_packages(),
3237
classifiers=[
3338
'Development Status :: 2 - Pre-Alpha',
3439
'License :: OSI Approved :: MIT License',
@@ -42,3 +47,4 @@
4247
'Topic :: Utilities',
4348
],
4449
)
50+

starlette_discord/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111
__author__ = 'nwunderly'
1212
__license__ = 'MIT'
1313
__copyright__ = 'Copyright 2021 nwunderly'
14-
__version__ = '0.1.0'
14+
__version__ = '0.1.1'
1515

1616
from .client import DiscordOAuthClient, DiscordOAuthSession

starlette_discord/client.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ class DiscordOAuthSession(OAuth2Session):
1111
1212
Parameters
1313
----------
14-
code:
14+
code: :class:`str`
1515
Authorization code included with user request after redirect from Discord.
16+
client_id: :class:`int`
17+
Your Discord application client ID.
18+
scope: :class:`str`
19+
Discord authorization scopes separated by %20.
20+
redirect_uri: :class:`str`
21+
Your Discord application redirect URI.
1622
"""
1723
def __init__(self, code, client_id, client_secret, scope, redirect_uri):
1824
self._discord_auth_code = code
@@ -134,22 +140,39 @@ class DiscordOAuthClient:
134140
Discord application client secret.
135141
redirect_uri:
136142
Discord application redirect URI.
143+
scopes: :class:`tuple[str]`
144+
Discord authorization scopes.
137145
"""
138146
def __init__(self, client_id, client_secret, redirect_uri, scopes=('identify',)):
139147
self.client_id = client_id
140148
self.client_secret = client_secret
141149
self.redirect_uri = redirect_uri
142-
self.scopes = ' '.join(scope for scope in scopes)
150+
self.scope = ' '.join(scope for scope in scopes)
143151

144-
def redirect(self):
145-
"""Returns a RedirectResponse that directs to Discord login."""
152+
def redirect(self, state=None, prompt=None):
153+
"""Returns a RedirectResponse that directs to Discord login.
154+
155+
Parameters
156+
----------
157+
state: :class:`Optional[str]`
158+
Optional state parameter for Discord redirect URL.
159+
Docs can be found `here <https://discord.com/developers/docs/topics/oauth2#state-and-security>`_.
160+
161+
prompt: :class:`Optional[str]`
162+
Optional prompt parameter for Discord redirect URL.
163+
If ``consent``, user is prompted to re-approve authorization. If ``none``, skips authorization if user has already authorized.
164+
Defaults to ``consent``.
165+
"""
146166
client_id = f'client_id={self.client_id}'
147167
redirect_uri = f'redirect_uri={self.redirect_uri}'
148-
scopes = f'scope={self.scopes}'
168+
scopes = f'scope={self.scope}'
149169
response_type = 'response_type=code'
150-
return RedirectResponse(
151-
DISCORD_URL + f'/api/oauth2/authorize?{client_id}&{redirect_uri}&{scopes}&{response_type}'
152-
)
170+
url = DISCORD_URL + f'/api/oauth2/authorize?{client_id}&{redirect_uri}&{scopes}&{response_type}'
171+
if state:
172+
url += f'&state={state}'
173+
if prompt:
174+
url += f'&prompt={prompt}'
175+
return RedirectResponse(url)
153176

154177
def session(self, code) -> DiscordOAuthSession:
155178
"""Create a new DiscordOAuthSession with this client's information.
@@ -168,7 +191,7 @@ def session(self, code) -> DiscordOAuthSession:
168191
code=code,
169192
client_id=self.client_id,
170193
client_secret=self.client_secret,
171-
scope=self.scopes,
194+
scope=self.scope,
172195
redirect_uri=self.redirect_uri,
173196
)
174197

starlette_discord/oauth.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
########################################################################################################
22
# This file was originally found at: https://gist.github.com/kellerza/5ca798f49983bb702bc6e7a05ba53def #
3+
# Thanks, kellerza! <3 #
34
# #
4-
# Thanks, kellerza #
5+
# - nwunder #
56
########################################################################################################
67

78
"""OAuth2Support for aiohttp.ClientSession.

tests/test_state_fastapi.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import secrets
2+
import uvicorn
3+
from fastapi import FastAPI
4+
from starlette.requests import Request
5+
from starlette.exceptions import HTTPException
6+
from starlette.middleware.sessions import SessionMiddleware
7+
8+
from starlette_discord.client import DiscordOAuthClient
9+
from auth import CLIENT_ID, CLIENT_SECRET, REDIRECT_URI
10+
11+
12+
app = FastAPI()
13+
client = DiscordOAuthClient(CLIENT_ID, CLIENT_SECRET, REDIRECT_URI, scopes=('identify', 'guilds', 'email', 'connections'))
14+
15+
16+
@app.get('/login')
17+
async def login_with_discord(request: Request):
18+
state = secrets.token_urlsafe(32)
19+
request.session['state'] = state
20+
return client.redirect(state=state, prompt='none')
21+
22+
23+
@app.get('/callback')
24+
async def callback(request: Request, code: str, state: str):
25+
# raise 401-Unauthorized if state doesn't match
26+
if not state == request.session.get('state'):
27+
raise HTTPException(401)
28+
29+
async with client.session(code) as session:
30+
u = await session.identify()
31+
32+
return {'user': u}
33+
34+
35+
app.add_middleware(SessionMiddleware, secret_key=secrets.token_urlsafe(64))
36+
uvicorn.run(app, host='0.0.0.0', port=9000)

0 commit comments

Comments
 (0)