Skip to content

Commit 127966d

Browse files
committed
Rearrange the files and create some necessary ones
1 parent c063340 commit 127966d

File tree

10 files changed

+108
-132
lines changed

10 files changed

+108
-132
lines changed

.env

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
GITHUB_CLIENT_ID=eccd08d6736b7999a32a
2-
GITHUB_CLIENT_SECRET=642999c1c5f2b3df8b877afdc78252ef5b594d31
3-
GITHUB_REDIRECT_URL=http://127.0.0.1:8000/auth/callback
4-
MAIN_PAGE_REDIRECT_URL=http://127.0.0.1:8000/
1+
CLIENT_ID=eccd08d6736b7999a32a
2+
CLIENT_SECRET=642999c1c5f2b3df8b877afdc78252ef5b594d31
3+
CALLBACK_URL=http://127.0.0.1:8000/auth/callback
4+
REDIRECT_URL=http://127.0.0.1:8000/
55

6-
JWT_SECRET_KEY=secret
6+
JWT_SECRET=secret
77
JWT_ALGORITHM=HS256
8-
JWT_TOKEN_EXPIRES=300
8+
JWT_EXPIRES=5

demo/config.py

Lines changed: 0 additions & 16 deletions
This file was deleted.

demo/dependencies.py

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from starlette.requests import Request
99
from starlette.status import HTTP_403_FORBIDDEN
1010

11-
from .config import SECRET_KEY, ALGORITHM
11+
from fastapi_oauth2.config import JWT_SECRET, JWT_ALGORITHM
1212

1313

1414
class OAuth2PasswordBearerCookie(OAuth2):
@@ -19,38 +19,17 @@ def __init__(
1919
scopes: dict = None,
2020
auto_error: bool = True,
2121
):
22-
if not scopes:
23-
scopes = {}
24-
flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes})
22+
flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes or {}})
2523
super().__init__(flows=flows, scheme_name=scheme_name, auto_error=auto_error)
2624

2725
async def __call__(self, request: Request) -> Optional[str]:
28-
header_authorization: str = request.headers.get("Authorization")
29-
cookie_authorization: str = request.cookies.get("Authorization")
26+
scheme, param = get_authorization_scheme_param(request.headers.get("Authorization"))
27+
authorization = scheme.lower() == "bearer"
28+
if not authorization:
29+
scheme, param = get_authorization_scheme_param(request.cookies.get("Authorization"))
30+
authorization = scheme.lower() == "bearer"
3031

31-
header_scheme, header_param = get_authorization_scheme_param(
32-
header_authorization
33-
)
34-
cookie_scheme, cookie_param = get_authorization_scheme_param(
35-
cookie_authorization
36-
)
37-
38-
if header_scheme.lower() == "bearer":
39-
authorization = True
40-
scheme = header_scheme
41-
param = header_param
42-
43-
elif cookie_scheme.lower() == "bearer":
44-
authorization = True
45-
scheme = cookie_scheme
46-
param = cookie_param
47-
48-
else:
49-
authorization = False
50-
scheme = ""
51-
param = ""
52-
53-
if not authorization or scheme.lower() != "bearer":
32+
if not authorization:
5433
if self.auto_error:
5534
raise HTTPException(
5635
status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
@@ -65,7 +44,7 @@ async def __call__(self, request: Request) -> Optional[str]:
6544

6645
async def get_current_user(token: str = Depends(oauth2_scheme)):
6746
try:
68-
return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
47+
return jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])
6948
except JWTError:
7049
raise HTTPException(
7150
status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials"

demo/router.py

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,10 @@
1-
from datetime import timedelta
2-
31
from fastapi import APIRouter
42
from fastapi import Depends
5-
from fastapi.responses import RedirectResponse
63
from starlette.requests import Request
74

8-
from fastapi_oauth2.github import GitHubSSO
9-
from .config import (
10-
CLIENT_ID,
11-
CLIENT_SECRET,
12-
redirect_url,
13-
ACCESS_TOKEN_EXPIRE_MINUTES,
14-
redirect_url_main_page,
15-
)
165
from .dependencies import get_current_user
17-
from .utils import create_access_token
186

197
router = APIRouter()
20-
sso = GitHubSSO(
21-
client_id=CLIENT_ID,
22-
client_secret=CLIENT_SECRET,
23-
redirect_uri=redirect_url,
24-
allow_insecure_http=True,
25-
)
268

279

2810
@router.get("/user")
@@ -33,33 +15,3 @@ def user(current_user=Depends(get_current_user)):
3315
@router.post("/token")
3416
def token(request: Request):
3517
return request.cookies.get("Authorization")
36-
37-
38-
@router.get("/auth/login")
39-
async def auth_init():
40-
return await sso.get_login_redirect()
41-
42-
43-
@router.get("/auth/callback")
44-
async def auth_callback(request: Request):
45-
user = await sso.verify_and_process(request)
46-
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
47-
access_token = create_access_token(
48-
data=dict(user), expires_delta=access_token_expires
49-
)
50-
response = RedirectResponse(redirect_url_main_page)
51-
response.set_cookie(
52-
"Authorization",
53-
value=f"Bearer {access_token}",
54-
httponly=sso.allow_insecure_http,
55-
max_age=ACCESS_TOKEN_EXPIRE_MINUTES * 60,
56-
expires=ACCESS_TOKEN_EXPIRE_MINUTES * 60,
57-
)
58-
return response
59-
60-
61-
@router.get("/auth/logout")
62-
async def auth_logout():
63-
response = RedirectResponse(redirect_url_main_page)
64-
response.delete_cookie("Authorization")
65-
return response

demo/utils.py

Lines changed: 0 additions & 17 deletions
This file was deleted.

fastapi_oauth2/base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class SSOBase:
2121

2222
client_id: str = None
2323
client_secret: str = None
24-
redirect_uri: Optional[str] = None
24+
callback_url: Optional[str] = None
2525
allow_insecure_http: bool = False
2626
scope: Optional[List[str]] = None
2727
state: Optional[str] = None
@@ -36,13 +36,13 @@ def __init__(
3636
self,
3737
client_id: str,
3838
client_secret: str,
39-
redirect_uri: Optional[str] = None,
39+
callback_url: Optional[str] = None,
4040
allow_insecure_http: bool = False,
4141
scope: Optional[List[str]] = None,
4242
):
4343
self.client_id = client_id
4444
self.client_secret = client_secret
45-
self.redirect_uri = redirect_uri
45+
self.callback_url = callback_url
4646
self.allow_insecure_http = allow_insecure_http
4747
if allow_insecure_http:
4848
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
@@ -71,9 +71,9 @@ async def get_login_url(
7171
) -> Any:
7272
self.state = state
7373
params = params or {}
74-
redirect_uri = redirect_uri or self.redirect_uri
74+
redirect_uri = redirect_uri or self.callback_url
7575
if redirect_uri is None:
76-
raise ValueError("redirect_uri must be provided, either at construction or request time")
76+
raise ValueError("callback_url must be provided, either at construction or request time")
7777
return self.oauth_client.prepare_request_uri(
7878
self.authorization_endpoint, redirect_uri=redirect_uri, state=state, scope=self.scope, **params
7979
)
@@ -113,7 +113,7 @@ async def verify_and_process(
113113
token_url, headers, content = self.oauth_client.prepare_token_request(
114114
self.token_endpoint,
115115
authorization_response=current_url,
116-
redirect_url=redirect_uri or self.redirect_uri or current_path,
116+
redirect_url=redirect_uri or self.callback_url or current_path,
117117
code=request.query_params.get("code"),
118118
**params,
119119
)

fastapi_oauth2/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import os
2+
3+
from dotenv import load_dotenv
4+
5+
load_dotenv()
6+
7+
CLIENT_ID = os.getenv("CLIENT_ID")
8+
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
9+
CALLBACK_URL = os.getenv("CALLBACK_URL")
10+
REDIRECT_URL = os.getenv("REDIRECT_URL")
11+
12+
JWT_SECRET = os.getenv("JWT_SECRET")
13+
JWT_ALGORITHM = os.getenv("JWT_ALGORITHM")
14+
JWT_EXPIRES = int(os.getenv("JWT_EXPIRES"))

fastapi_oauth2/router.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from datetime import timedelta
2+
3+
from fastapi import APIRouter
4+
from fastapi.responses import RedirectResponse
5+
from starlette.requests import Request
6+
7+
from fastapi_oauth2.github import GitHubSSO
8+
from .config import (
9+
CLIENT_ID,
10+
CLIENT_SECRET,
11+
CALLBACK_URL,
12+
JWT_EXPIRES,
13+
REDIRECT_URL,
14+
)
15+
from .utils import create_access_token
16+
17+
router = APIRouter()
18+
sso = GitHubSSO(
19+
client_id=CLIENT_ID,
20+
client_secret=CLIENT_SECRET,
21+
callback_url=CALLBACK_URL,
22+
allow_insecure_http=True,
23+
)
24+
25+
26+
@router.get("/auth/login")
27+
async def login():
28+
return await sso.get_login_redirect()
29+
30+
31+
@router.get("/auth/callback")
32+
async def callback(request: Request):
33+
user = await sso.verify_and_process(request)
34+
expires_delta = timedelta(minutes=JWT_EXPIRES)
35+
access_token = create_access_token(
36+
data=dict(user), expires_delta=expires_delta
37+
)
38+
response = RedirectResponse(REDIRECT_URL)
39+
response.set_cookie(
40+
"Authorization",
41+
value=f"Bearer {access_token}",
42+
httponly=sso.allow_insecure_http,
43+
max_age=JWT_EXPIRES * 60,
44+
expires=JWT_EXPIRES * 60,
45+
)
46+
return response
47+
48+
49+
@router.get("/auth/logout")
50+
async def logout():
51+
response = RedirectResponse(REDIRECT_URL)
52+
response.delete_cookie("Authorization")
53+
return response

fastapi_oauth2/utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from datetime import datetime, timedelta
2+
from typing import Optional
3+
4+
from jose import jwt
5+
6+
from .config import JWT_SECRET, JWT_ALGORITHM
7+
8+
9+
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
10+
expire = datetime.utcnow() + expires_delta if expires_delta else timedelta(minutes=15)
11+
return jwt.encode({**data, "exp": expire}, JWT_SECRET, algorithm=JWT_ALGORITHM)

main.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import json
22

3-
import jwt
43
from fastapi import FastAPI, Request, APIRouter
54
from fastapi.responses import HTMLResponse
5+
from fastapi.security.utils import get_authorization_scheme_param
66
from fastapi.templating import Jinja2Templates
77
from starlette.authentication import AuthenticationBackend
88
from starlette.middleware.authentication import AuthenticationMiddleware
99

10-
from demo.config import SECRET_KEY, ALGORITHM
11-
from demo.router import router as auth_router
10+
from demo.dependencies import get_current_user
11+
from demo.router import router as demo_router
12+
from fastapi_oauth2.router import router as oauth2_router
1213

1314
router = APIRouter()
1415
templates = Jinja2Templates(directory="templates")
@@ -21,20 +22,19 @@ async def root(request: Request):
2122

2223
app = FastAPI()
2324
app.include_router(router)
24-
app.include_router(auth_router)
25+
app.include_router(demo_router)
26+
app.include_router(oauth2_router)
2527

2628

2729
class BearerTokenAuthBackend(AuthenticationBackend):
2830
async def authenticate(self, request):
2931
authorization = request.cookies.get("Authorization")
32+
scheme, param = get_authorization_scheme_param(authorization)
3033

31-
if not authorization:
34+
if not scheme or not param:
3235
return "", None
3336

34-
access_token = authorization.split(" ")[1]
35-
user = jwt.decode(access_token, SECRET_KEY, algorithms=[ALGORITHM])
36-
37-
return authorization, user
37+
return authorization, await get_current_user(param)
3838

3939

4040
@app.on_event('startup')

0 commit comments

Comments
 (0)