Skip to content

Commit

Permalink
feat(login-with-google): changed signin oauth and created login oauth…
Browse files Browse the repository at this point in the history
… to allow login with google (#116)

### Short description of changes:

Created oauth login controller
  • Loading branch information
elliotsaha committed Feb 17, 2024
2 parents 2562fe6 + 168ecde commit 320ef14
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 40 deletions.
44 changes: 35 additions & 9 deletions src/app/(pages)/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '@chakra-ui/react';
import {useForm} from 'react-hook-form';
import {FiArrowRight} from 'react-icons/fi';
import {FaGoogle} from 'react-icons/fa';
import {Subheader} from '@components';
import {useSearchParams} from 'next/navigation';
import {authBroadcast} from '@broadcasts';
Expand All @@ -35,23 +36,33 @@ type Form = z.infer<typeof schema>;
const Login = () => {
const statusToast = useToast();
const params = useSearchParams();

const redirectURL = params.get('redirect');
const confirmationStatus = params.get('confirmation-status');
const recoveryStatus = params.get('recovery-status');
const invalidate = params.get('invalidate');
const sameGoogleEmail = params.get('same-google-email');
const badOauth = params.get('bad-oauth');

const GOOGLE_AUTH_LINK = `${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/login/google`;

useEffect(() => {
if (sameGoogleEmail) {
if (sameGoogleEmail === 'true') {
statusToast({
id: 'google_email',
title: 'A non-google account with the same email exists',
status: 'error',
});
}
if (sameGoogleEmail === 'true') {
statusToast({
id: 'same_google_email',
title: 'A non-google account with the same email exists',
status: 'error',
});
}

if (badOauth === 'true') {
statusToast({
id: 'bad_oauth',
title: 'You need to sign up before logging in',
status: 'error',
});
}
});
}, [sameGoogleEmail, badOauth]);

useEffect(() => {
if (invalidate === 'true') {
Expand Down Expand Up @@ -191,6 +202,21 @@ const Login = () => {
<Subheader mt="-2" mb="1">
Welcome Back
</Subheader>

<Button
flexGrow={1}
onClick={() => {
window.location.href = GOOGLE_AUTH_LINK;
}}
colorScheme="brand"
variant="outline"
size="lg"
_hover={{
bg: 'gray.100',
}}
>
<Icon as={FaGoogle} mr={4} color="brand.500" /> Login with Google
</Button>
<FormControl isInvalid={Boolean(errors.email_address)}>
<Input
id="email_address"
Expand Down
4 changes: 0 additions & 4 deletions src/app/(pages)/(auth)/signup/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import {
ModalContent,
ModalCloseButton,
ModalBody,
Link,
Text,
HStack,
} from '@chakra-ui/react';
import {FiArrowRight, FiMail} from 'react-icons/fi';
import {FaGoogle} from 'react-icons/fa';
Expand All @@ -33,7 +30,6 @@ import z from 'zod';
import axios from 'axios';
import {zodResolver} from '@hookform/resolvers/zod';
import {DEFAULT_SERVER_ERR, ZOD_ERR} from '@constants';
import {ExternalLinkIcon} from '@chakra-ui/icons';

const schema = z
.object({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import {ServerResponse} from '@helpers/serverResponse';
import {auth, googleAuth} from '@lib/lucia';
import {ServerResponse} from '@helpers';
import {auth, googleLogin} from '@lib/lucia';
import {OAuthRequestError} from '@lucia-auth/oauth';
import {User} from '@models/User';
import {cookies, headers} from 'next/headers';
import {NextResponse, NextRequest} from 'next/server';
import {NextRequest, NextResponse} from 'next/server';

export const GET = async (request: NextRequest) => {
const state = request.nextUrl.searchParams.get('state');
Expand All @@ -14,34 +13,42 @@ export const GET = async (request: NextRequest) => {
}

try {
const {getExistingUser, createUser, googleUser} =
await googleAuth.validateCallback(code!);
const {getExistingUser, googleUser} = await googleLogin.validateCallback(
code!
);

const userAttributes = {
first_name: googleUser.given_name,
last_name: googleUser.family_name,
email_address: googleUser.email,
email_verified: googleUser.email_verified,
skill: 1,
instagram: null,
profile: googleUser.picture,
};

const getUser = async () => {
const existingUser = await getExistingUser();
if (existingUser) return existingUser;
const user = await createUser({
attributes: userAttributes,
});
return user;

return NextResponse.redirect(
new URL('/login?bad-oauth=true', request.url)
);
};

const user = await getUser();
const session = await auth.createSession({
userId: user.userId,
attributes: {},
attributes: userAttributes,
});

const authRequest = auth.handleRequest(request.method, {
cookies,
headers,
});

authRequest.setSession(session);

return NextResponse.redirect(new URL('/', request.url));
} catch (e) {
if (e instanceof OAuthRequestError) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {googleAuth} from '@lib/lucia';
import {googleLogin} from '@lib/lucia';
import * as context from 'next/headers';

export const GET = async () => {
const [url, state] = await googleAuth.getAuthorizationUrl();
const [url, state] = await googleLogin.getAuthorizationUrl();
// store state
context.cookies().set('google_oauth_state', state, {
httpOnly: true,
Expand Down
13 changes: 3 additions & 10 deletions src/app/api/auth/signup/google/callback/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ServerResponse} from '@helpers/serverResponse';
import {auth, googleAuth} from '@lib/lucia';
import {ServerResponse} from '@helpers';
import {auth, googleSignup} from '@lib/lucia';
import {OAuthRequestError} from '@lucia-auth/oauth';
import {cookies, headers} from 'next/headers';
import {NextResponse, NextRequest} from 'next/server';
Expand All @@ -14,10 +14,7 @@ export const GET = async (request: NextRequest) => {
}

try {
const {getExistingUser, createUser, googleUser} =
await googleAuth.validateCallback(code!);

console.log(googleUser);
const {createUser, googleUser} = await googleSignup.validateCallback(code!);

const userAttributes = {
first_name: googleUser.given_name,
Expand All @@ -40,10 +37,6 @@ export const GET = async (request: NextRequest) => {
}

const getUser = async () => {
const existingUser = await getExistingUser();

if (existingUser) return existingUser;

const user = await createUser({
attributes: userAttributes,
});
Expand Down
4 changes: 2 additions & 2 deletions src/app/api/auth/signup/google/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {googleAuth} from '@lib/lucia';
import {googleSignup} from '@lib/lucia';
import * as context from 'next/headers';

export const GET = async () => {
const [url, state] = await googleAuth.getAuthorizationUrl();
const [url, state] = await googleSignup.getAuthorizationUrl();
// store state
context.cookies().set('google_oauth_state', state, {
httpOnly: true,
Expand Down
18 changes: 16 additions & 2 deletions src/lib/lucia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,25 @@ export const auth = lucia({
},
});

export const googleAuth = google(auth, {
const googleController = (redirectUri: string) => ({
clientId: process.env.NEXT_OAUTH_ID!,
clientSecret: process.env.NEXT_OAUTH_SECRET!,
redirectUri: `${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/signup/google/callback`,
scope: ['https://www.googleapis.com/auth/userinfo.email'],
redirectUri,
});

export const googleSignup = google(
auth,
googleController(
`${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/signup/google/callback`
)
);

export const googleLogin = google(
auth,
googleController(
`${process.env.NEXT_PUBLIC_HOSTNAME}/api/auth/login/google/callback`
)
);

export type Auth = typeof auth;

0 comments on commit 320ef14

Please sign in to comment.