Skip to content

Commit bf48b64

Browse files
committed
add github oauth
1 parent f80229a commit bf48b64

File tree

4 files changed

+86
-4
lines changed

4 files changed

+86
-4
lines changed

.github/workflows/fastapi-to-gcr.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ jobs:
4343
gcloud run deploy $SERVICE_NAME \
4444
--image ${{ env.DOCKER_IMAGE_URL }}:latest \
4545
--platform managed \
46-
--set-env-vars POSTGRES_SERVER=${{ secrets.POSTGRES_SERVER }},POSTGRES_PORT=${{ secrets.POSTGRES_PORT }},POSTGRES_DB=${{ secrets.POSTGRES_DB }},POSTGRES_USER=${{ secrets.POSTGRES_USER }},POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }},ENCRYPTION_KEY=${{ secrets.ENCRYPTION_KEY }},PROJECT_NAME=${{ env.PROJECT_ID }},FIRST_SUPERUSER=${{ secrets.FIRST_SUPERUSER }},FIRST_SUPERUSER_PASSWORD=${{ secrets.FIRST_SUPERUSER_PASSWORD }},USERS_OPEN_REGISTRATION=${{ env.USERS_OPEN_REGISTRATION }},GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }},GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }},GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }} \
46+
--set-env-vars POSTGRES_SERVER=${{ secrets.POSTGRES_SERVER }},POSTGRES_PORT=${{ secrets.POSTGRES_PORT }},POSTGRES_DB=${{ secrets.POSTGRES_DB }},POSTGRES_USER=${{ secrets.POSTGRES_USER }},POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }},ENCRYPTION_KEY=${{ secrets.ENCRYPTION_KEY }},PROJECT_NAME=${{ env.PROJECT_ID }},FIRST_SUPERUSER=${{ secrets.FIRST_SUPERUSER }},FIRST_SUPERUSER_PASSWORD=${{ secrets.FIRST_SUPERUSER_PASSWORD }},USERS_OPEN_REGISTRATION=${{ env.USERS_OPEN_REGISTRATION }},GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }},GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }},GOOGLE_REDIRECT_URI=${{ secrets.GOOGLE_REDIRECT_URI }},GH_CLIENT_ID=${{ secrets.GH_CLIENT_ID }},GH_CLIENT_SECRET=${{ secrets.GH_CLIENT_SECRET }} \
4747
--region australia-southeast1 \
4848
--allow-unauthenticated

backend/src/app/api/routes/login.py

+71-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def login_google():
141141

142142
# Handle Google OAuth callback
143143
@router.get("/auth/google")
144-
def auth(session: SessionDep, code: str, response: Response):
144+
def google_oauth(session: SessionDep, code: str, response: Response):
145145
token_url = "https://oauth2.googleapis.com/token"
146146
token_data = {
147147
"code": code,
@@ -206,3 +206,73 @@ def auth(session: SessionDep, code: str, response: Response):
206206
httponly=True,
207207
)
208208
return response
209+
210+
211+
# Handle Github OAuth callback
212+
@router.get("/auth/github")
213+
def github_oauth(session: SessionDep, code: str, response: Response):
214+
token_url = "https://github.com/login/oauth/access_token"
215+
token_data = {
216+
"code": code,
217+
"client_id": settings.GITHUB_CLIENT_ID,
218+
"client_secret": settings.GITHUB_CLIENT_SECRET,
219+
}
220+
headers = {"Accept": "application/json"}
221+
222+
token_r = requests.post(token_url, data=token_data, headers=headers)
223+
token_json = token_r.json()
224+
if "error" in token_json:
225+
raise HTTPException(
226+
status_code=400, detail="Failed to retrieve token from Github"
227+
)
228+
access_token = token_json["access_token"]
229+
# Get user info from Github
230+
user_info = requests.get(
231+
"https://api.github.com/user",
232+
headers={"Authorization": f"Bearer {access_token}"},
233+
).json()
234+
235+
user_emails = requests.get(
236+
"https://api.github.com/user/emails",
237+
headers={"Authorization": f"Bearer {access_token}"},
238+
).json()
239+
240+
# Check if the user already exists
241+
user = crud.get_user_by_email(session=session, email=user_emails[0]["email"])
242+
access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
243+
if user:
244+
response = RedirectResponse("http://localhost:3000/dashboard")
245+
response.set_cookie(
246+
key="access_token",
247+
value=security.create_access_token(
248+
user.id, expires_delta=access_token_expires
249+
),
250+
httponly=True,
251+
)
252+
return response
253+
254+
# Check if the app is open for new user registration
255+
if not settings.USERS_OPEN_REGISTRATION:
256+
raise HTTPException(
257+
status_code=403,
258+
detail="Open user registration is forbidden on this server",
259+
)
260+
# Create a new user
261+
user_create = UserCreateOauth.model_validate(
262+
{
263+
"email": user_emails[0]["email"],
264+
"is_active": True,
265+
"is_superuser": False,
266+
"full_name": user_info["login"],
267+
"provider": "github",
268+
}
269+
)
270+
user = crud.create_user_oauth(session=session, user_create=user_create)
271+
272+
response = RedirectResponse("http://localhost:3000/dashboard")
273+
response.set_cookie(
274+
key="access_token",
275+
value=security.create_access_token(user.id, expires_delta=access_token_expires),
276+
httponly=True,
277+
)
278+
return response

backend/src/app/core/config.py

+3
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,8 @@ def _enforce_non_default_secrets(self) -> Self:
122122
GOOGLE_CLIENT_SECRET: str
123123
GOOGLE_REDIRECT_URI: str
124124

125+
GH_CLIENT_ID: str
126+
GH_CLIENT_SECRET: str
127+
125128

126129
settings = Settings() # type: ignore

frontend/components/oauth-login.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,18 @@ export function OAuthLogin() {
1111
console.error("Google Client ID or Redirect URI is not defined");
1212
}
1313
const googleAuthUrl = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${GOOGLE_CLIENT_ID}&redirect_uri=${GOOGLE_REDIRECT_URI}&response_type=code&scope=email%20profile`;
14-
console.log(googleAuthUrl);
1514
window.location.href = googleAuthUrl;
1615
}
16+
async function loginGithub() {
17+
const GITHUB_CLIENT_ID = process.env.NEXT_PUBLIC_GITHUB_CLIENT_ID;
18+
const GITHUB_REDIRECT_URI = process.env.NEXT_PUBLIC_GITHUB_REDIRECT_URI;
19+
20+
if (!GITHUB_CLIENT_ID || !GITHUB_REDIRECT_URI) {
21+
console.error("GitHub Client ID or Redirect URI is not defined");
22+
}
23+
const githubAuthUrl = `https://github.com/login/oauth/authorize?client_id=${GITHUB_CLIENT_ID}&scope=read:user user:email`;
24+
window.location.href = githubAuthUrl;
25+
}
1726
return (
1827
<div className="grid grid-cols-2 gap-6 mt-3">
1928
<Button variant="outline" onClick={loginGoogle}>
@@ -38,7 +47,7 @@ export function OAuthLogin() {
3847
</svg>
3948
Google
4049
</Button>
41-
<Button variant="outline">
50+
<Button variant="outline" onClick={loginGithub}>
4251
<Github className="mr-2 h-4 w-4" />
4352
GitHub
4453
</Button>

0 commit comments

Comments
 (0)