Open javierohern opened 1 year ago
I realized i left out @app.on_event("startup") async def on_startup(): await discord.init() But after adding this I get AttributeError: 'DiscordOAuthClient' object has no attribute 'init'
"EDIT"
I got the init problem to go away by installing dependencies from source. With that the
@app.on_event("startup") async def on_startup(): await discord.init()
The previous issue is now gone. But after logging in, I get the discord authorization page, and on login my url is appended with ?{code} but I'm still not receiving an access token?
Whole snippet of code ->
`@app.on_event("startup")
async def on_startup():
await discord.init()
@app.get("/login")
async def login():
return {"url": discord.oauth_login_url}
@app.get("/callback")
async def callback(code: str):
token, refresh_token = await discord.get_access_token(code)
return {"access_token": token, "refresh_token": refresh_token}
@app.get(
"/authenticated",
dependencies=[Depends(discord.requires_authorization)],
response_model=bool,
)
async def isAuthenticated(token: str = Depends(discord.get_token)):
try:
auth = await discord.isAuthenticated(token)
return auth
except Unauthorized:
return False
@app.exception_handler(Unauthorized)
async def unauthorized_error_handler(_, __):
return JSONResponse({"error": "Unauthorized"}, status_code=401)
@app.exception_handler(RateLimited)
async def rate_limit_error_handler(_, e: RateLimited):
return JSONResponse(
{"error": "RateLimited", "retry": e.retry_after, "message": e.message},
status_code=429,
)
@app.get(
"/user", dependencies=[Depends(discord.requires_authorization)], response_model=User
)
async def get_user(user: User = Depends(discord.user)):
return user
@app.get(
"/guilds",
dependencies=[Depends(discord.requires_authorization)],
response_model=List[GuildPreview],
)
async def get_guilds(guilds: List = Depends(discord.guilds)):
return guilds
`
@javierohern I was having a similar issue:
It's coming from this piece:
@app.get("/callback")
async def callback(code: str):
token, refresh_token = await discord.get_access_token(code)
return {"access_token": token, "refresh_token": refresh_token}
And more specifically, token, refresh_token = await discord.get_access_token(code)
.
It appears that there is something going wrong where the discord.get_access_token(code) is not returning a value, which is leaving "token" as None.
If you look at Discord's OAuth2 documentation, you can see how to call for an access token yourself.
Here is what I ended up doing to get around the packaged DiscordOAuthClient.get_access_token returning None:
### DISCORD AUTH ###
dotenv.load_dotenv()
### Identify env variables
DISCORD_CLIENT = os.getenv('DISCORD_CLIENT')
DISCORD_CLIENT_SECRET = os.getenv('DISCORD_CLIENT_SECRET')
DISCORD_REDIRECT_URI = os.getenv('DISCORD_REDIRECT_URI')
DISCORD_TOKEN_URL = "https://discord.com/api/v10/oauth2/token"
discord = DiscordOAuthClient(
DISCORD_CLIENT, DISCORD_CLIENT_SECRET, DISCORD_REDIRECT_URI, ("identify", "guilds")
)
@app.get("/auth/callback")
async def callback(code: str, request: Request):
import httpx
async def exchange_code(code: str):
payload = {
"client_id": DISCORD_CLIENT,
"client_secret": DISCORD_CLIENT_SECRET,
"grant_type": "authorization_code",
"code": code,
"redirect_uri": DISCORD_REDIRECT_URI,
"scope": "identify guilds"
}
headers: dict = {"Content-Type": "application/x-www-form-urlencoded"}
async with httpx.AsyncClient() as client:
resp = await client.post(DISCORD_TOKEN_URL, data=payload, headers=headers)
return resp.json()
tokenData = await exchange_code(code)
logging.info(f"Token data: {tokenData}")
This takes the code that returns with the auth, then uses it to request, and receive, a token. Note that tokenData is still in JSON format, you'll need to parse it as needed.
tokenData looks like this:
{
'token_type': 'Bearer',
'access_token': stringfortoken',
'expires_in': 604800,
'refresh_token': 'd3mFnpt8IIjCmsPiaLO32qFJcdG1Y7',
'scope': 'identify guilds'
}
I could not reproduce this issue with neither v0.2.4 nor v0.2.5.
It would be helpful if you could try to reproduce the following steps:
git clone https://github.com/Tert0/fastapi-discord.git
cd fastapi-discord
git checkout v0.2.5
http://127.0.0.1:8000/callback
as a redirect URL.examples/basic.py
and use http://127.0.0.1:8000/callback
as the redirect URL.pip3 install fastapi-discord==0.2.5 uvicorn
uvicorn examples.basic
curl http://localhost:8000/login
Or open http://localhost:8000/login
in a browser. Then open the generated URL in a browser and click on authorize.
The browsers should display the access and refresh token in JSON.
{"access_token":"redacted","refresh_token":"redacted"}
I hope it works for you, at least it works for me.
(I have tested it with a docker container python (Debian-based))
Title. Discord developer portal knows about my redirect_uri which is http://localhost:8000/callback