Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add github sso #190

Merged
merged 2 commits into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion auth/src/services/authManager/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { OAuthUser } from "../../models/index";
import { ApiKeyAuth } from "./providers/apikey";
import { CustomJWTAuth } from "./providers/custom";
import { DiscordAuth, GoogleAuth } from "./providers/index";
import { DiscordAuth, GitHubAuth, GoogleAuth } from "./providers/index";

const getUserFromAccessToken = async (
provider: string,
Expand All @@ -16,6 +16,8 @@ const getUserFromAccessToken = async (
return ApiKeyAuth.getUserFromApiKey(accessToken);
case "custom-jwt":
return CustomJWTAuth.getUserFromAccessToken(accessToken);
case "github":
return GitHubAuth.getUserFromAccessToken(accessToken);
default:
throw new Error("Invalid provider");
}
Expand Down
31 changes: 31 additions & 0 deletions auth/src/services/authManager/providers/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { OAuthUser } from "../../../models";

type GitHubUser = {
id: number;
login: string;
};

const getUserFromAccessToken = async (
accessToken: string
): Promise<OAuthUser> => {
const githubUser = await fetch("https://api.github.com/user", {
headers: {
Authorization: `Bearer ${accessToken}`,
},
}).then((res) => {
if (res.status >= 400) {
throw new Error("Failed to fetch user info");
}
return res.json() as Promise<GitHubUser>;
});

return {
provider: "github",
// Convert numeric GitHub ID to string if you want a uniform type
id: githubUser.id.toString(),
};
};

export const GitHubAuth = {
getUserFromAccessToken,
};
1 change: 1 addition & 0 deletions auth/src/services/authManager/providers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./google";
export * from "./discord";
export * from "./github";
5 changes: 5 additions & 0 deletions frontend/src/app/api/auth/[...nextauth]/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AuthOptions } from 'next-auth';
import GoogleProvider from 'next-auth/providers/google';
import GithubProvider from 'next-auth/providers/github';
import DiscordProvider from 'next-auth/providers/discord';
import {
generateAccessToken,
Expand All @@ -19,6 +20,10 @@ export const authOptions: AuthOptions = {
clientId: process.env.DISCORD_AUTH_CLIENT_ID as string,
clientSecret: process.env.DISCORD_AUTH_CLIENT_SECRET as string,
}),
GithubProvider({
clientId: process.env.GITHUB_AUTH_CLIENT_ID as string,
clientSecret: process.env.GITHUB_AUTH_CLIENT_SECRET as string,
}),
],
callbacks: {
async jwt({ account, token }) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/common/Disclaimer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const Disclaimer = () => {
return (
<div className='relative rounded-lg border border-red-300 bg-red-50 bg-opacity-60 p-4'>
<div className='dark:text-darkBlack relative rounded-lg border border-red-300 bg-red-50 bg-opacity-60 p-4 dark:bg-red-400'>
<h3 className='mb-2 font-semibold'>Please, note:</h3>
<ul className='list-inside list-disc space-y-1 text-sm font-bold'>
<li>Uploaded content will be visible and searchable by everyone</li>
Expand Down
17 changes: 17 additions & 0 deletions frontend/src/components/common/GithubIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const GithubIcon = ({ fillColor }: { fillColor: string }) => {
return (
<svg
width='24'
height='24'
role='img'
viewBox='0 0 24 24'
xmlns='http://www.w3.org/2000/svg'
>
<title>GitHub</title>
<path
fill={fillColor}
d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'
/>
</svg>
);
};
15 changes: 15 additions & 0 deletions frontend/src/views/Home/SignInButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { signIn } from 'next-auth/react';
import { useCallback, useState } from 'react';
import { DiscordIcon } from '../../components/common/DiscordIcon';
import { GoogleIcon } from '../../components/common/GoogleIcon';
import { GithubIcon } from '../../components/common/GithubIcon';
import { BuiltInProviderType } from 'next-auth/providers';
import { LoaderCircle } from 'lucide-react';

Expand All @@ -17,6 +18,11 @@ export const SigningInButtons = () => {
signIn('discord');
}, []);

const handleGithubAuth = useCallback(() => {
setIsClicked('github');
signIn('github');
}, []);

return (
<div className='flex flex-col gap-2'>
<button
Expand All @@ -37,6 +43,15 @@ export const SigningInButtons = () => {
Sign in with Discord
{isClicked === 'discord' && <LoaderCircle className='animate-spin' />}
</button>
<button
onClick={handleGithubAuth}
className='dark:bg-darkWhite dark:border-darkBlack dark:text-darkBlack flex w-full max-w-xs transform items-center justify-center gap-2 rounded-full border-2 border-backgroundDarker bg-white px-6 py-3 font-bold text-backgroundDarker transition duration-300 ease-in-out hover:-translate-y-1 hover:scale-105 hover:opacity-80 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2'
aria-label='Sign in with Github'
>
<GithubIcon fillColor='currentColor' />
Sign in with Github
{isClicked === 'github' && <LoaderCircle className='animate-spin' />}
</button>
</div>
);
};
13 changes: 6 additions & 7 deletions frontend/src/views/Onboarding/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import { Button, Checkbox } from '@headlessui/react';
import { CheckIcon } from 'lucide-react';
import { AuthService } from '../../services/auth/auth';
import { Disclaimer } from '../../components/common/Disclaimer';
// import { getDrivePath } from '../UserFiles';
import Image from 'next/image';
import { ROUTES } from '../../constants/routes';
import { AutonomysSymbol } from '../../components/common/AutonomysSymbol';

export const Onboarding = () => {
const [accepted, setAccepted] = useState(false);
Expand All @@ -23,14 +22,14 @@ export const Onboarding = () => {
}, []);

return (
<div className='flex h-screen flex-col items-center justify-center'>
<div className='dark:bg-darkWhite flex h-screen flex-col items-center justify-center bg-white'>
<header className='mb-8 flex flex-col items-center justify-between gap-4 md:flex-row md:gap-0'>
<div className='flex items-center space-x-2'>
<Image src='/autonomys.png' alt='Auto Drive' width={32} height={32} />
<div className='dark:text-darkBlack flex items-center space-x-2 text-black'>
<AutonomysSymbol />
<span className='text-xl font-semibold'>Auto Drive</span>
</div>
</header>
<div className='flex flex-col items-center gap-4'>
<div className='dark:text-darkBlack flex flex-col items-center gap-4'>
<Disclaimer />
<div className='flex items-center gap-2'>
<Checkbox
Expand All @@ -54,7 +53,7 @@ export const Onboarding = () => {
</div>
<Button
className={
'dark:bg-darkBlack rounded bg-black px-4 py-1 font-semibold text-white opacity-100 transition-all duration-300 hover:scale-105 hover:bg-gray-800 disabled:opacity-50'
'dark:bg-darkBlack dark:text-darkWhite dark:hover:bg-darkBlack rounded bg-black px-4 py-1 font-semibold text-white opacity-100 transition-all duration-300 hover:scale-105 hover:bg-gray-800 disabled:opacity-50 dark:hover:opacity-80'
}
disabled={!accepted}
onClick={onboardUser}
Expand Down