-
-
Notifications
You must be signed in to change notification settings - Fork 915
feat(dashboard): login with google and "last used" indicator #2746
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
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c95b0f5
feat(dashboard): login with google and "last used" indicator
ericallam 5523569
a few tweaks via CodeRabbit
ericallam 1bcfd32
Changed login buttons to secondary style
samejr 6deed23
Nicer styling/layout for the last used badge
samejr 9fc1dd8
Moved google svg logo to new component
samejr ddecae4
update existing google user details like email when they already exis…
ericallam 7e50b54
Improved the last used badge position on small screens
samejr 3e1b5e0
handle the case where the google auth conflicts with an existing user…
ericallam 6944207
Add auth info when upserting a user
ericallam 9f84f97
better check for existing emails in the profile info
ericallam File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| export function GoogleLogo({ className }: { className?: string }) { | ||
| return ( | ||
| <svg className={className} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
| <path | ||
| d="M19.9075 21.0983C22.7427 18.4521 24.0028 14.0417 23.2468 9.82031H11.9688V14.4827H18.3953C18.1433 15.9949 17.2612 17.255 16.0011 18.0741L19.9075 21.0983Z" | ||
| fill="#4285F4" | ||
| /> | ||
| <path | ||
| d="M1.25781 17.3802C2.08665 19.013 3.27532 20.4362 4.73421 21.5428C6.1931 22.6493 7.88415 23.4102 9.67988 23.7681C11.4756 24.1261 13.3292 24.0717 15.1008 23.6091C16.8725 23.1465 18.516 22.2877 19.9075 21.0976L16.0011 18.0733C12.6618 20.2785 7.11734 19.4594 5.22717 14.293L1.25781 17.3802Z" | ||
| fill="#34A853" | ||
| /> | ||
| <path | ||
| d="M5.22701 14.2922C4.72297 12.717 4.72297 11.2679 5.22701 9.69275L1.25765 6.60547C-0.191479 9.50373 -0.632519 13.5991 1.25765 17.3794L5.22701 14.2922Z" | ||
| fill="#FBBC02" | ||
| /> | ||
| <path | ||
| d="M5.22717 9.69209C6.6133 5.34469 12.5358 2.82446 16.5052 6.5418L19.9705 3.13949C15.0561 -1.58594 5.47919 -1.39692 1.25781 6.60481L5.22717 9.69209Z" | ||
| fill="#EA4335" | ||
| /> | ||
| </svg> | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| import type { LoaderFunction } from "@remix-run/node"; | ||
| import { redirect } from "@remix-run/node"; | ||
| import { prisma } from "~/db.server"; | ||
| import { getSession, redirectWithErrorMessage } from "~/models/message.server"; | ||
| import { authenticator } from "~/services/auth.server"; | ||
| import { setLastAuthMethodHeader } from "~/services/lastAuthMethod.server"; | ||
| import { commitSession } from "~/services/sessionStorage.server"; | ||
| import { redirectCookie } from "./auth.google"; | ||
| import { sanitizeRedirectPath } from "~/utils"; | ||
|
|
||
| export let loader: LoaderFunction = async ({ request }) => { | ||
| const cookie = request.headers.get("Cookie"); | ||
| const redirectValue = await redirectCookie.parse(cookie); | ||
| const redirectTo = sanitizeRedirectPath(redirectValue); | ||
|
|
||
| const auth = await authenticator.authenticate("google", request, { | ||
| failureRedirect: "/login", // If auth fails, the failureRedirect will be thrown as a Response | ||
| }); | ||
|
|
||
| // manually get the session | ||
| const session = await getSession(request.headers.get("cookie")); | ||
|
|
||
| const userRecord = await prisma.user.findFirst({ | ||
| where: { | ||
| id: auth.userId, | ||
| }, | ||
| select: { | ||
| id: true, | ||
| mfaEnabledAt: true, | ||
| }, | ||
| }); | ||
|
|
||
| if (!userRecord) { | ||
| return redirectWithErrorMessage( | ||
| "/login", | ||
| request, | ||
| "Could not find your account. Please contact support." | ||
| ); | ||
| } | ||
|
|
||
| if (userRecord.mfaEnabledAt) { | ||
| session.set("pending-mfa-user-id", userRecord.id); | ||
| session.set("pending-mfa-redirect-to", redirectTo); | ||
|
|
||
| const headers = new Headers(); | ||
| headers.append("Set-Cookie", await commitSession(session)); | ||
| headers.append("Set-Cookie", await setLastAuthMethodHeader("google")); | ||
|
|
||
| return redirect("/login/mfa", { headers }); | ||
| } | ||
|
|
||
| // and store the user data | ||
| session.set(authenticator.sessionKey, auth); | ||
|
|
||
| const headers = new Headers(); | ||
| headers.append("Set-Cookie", await commitSession(session)); | ||
| headers.append("Set-Cookie", await setLastAuthMethodHeader("google")); | ||
|
|
||
| return redirect(redirectTo, { headers }); | ||
| }; | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { type ActionFunction, type LoaderFunction, redirect, createCookie } from "@remix-run/node"; | ||
| import { authenticator } from "~/services/auth.server"; | ||
| import { env } from "~/env.server"; | ||
| import { sanitizeRedirectPath } from "~/utils"; | ||
|
|
||
| export let loader: LoaderFunction = () => redirect("/login"); | ||
|
|
||
| export let action: ActionFunction = async ({ request }) => { | ||
| const url = new URL(request.url); | ||
| const redirectTo = url.searchParams.get("redirectTo"); | ||
| const safeRedirect = sanitizeRedirectPath(redirectTo, "/"); | ||
|
|
||
| try { | ||
| // call authenticate as usual, in successRedirect use returnTo or a fallback | ||
| return await authenticator.authenticate("google", request, { | ||
| successRedirect: safeRedirect, | ||
| failureRedirect: "/login", | ||
| }); | ||
| } catch (error) { | ||
| // here we catch anything authenticator.authenticate throw, this will | ||
| // include redirects | ||
| // if the error is a Response and is a redirect | ||
| if (error instanceof Response) { | ||
| // we need to append a Set-Cookie header with a cookie storing the | ||
| // returnTo value (store the sanitized path) | ||
| error.headers.append("Set-Cookie", await redirectCookie.serialize(safeRedirect)); | ||
| } | ||
| throw error; | ||
| } | ||
| }; | ||
|
|
||
| export const redirectCookie = createCookie("google-redirect-to", { | ||
| maxAge: 60 * 60, // 1 hour | ||
| httpOnly: true, | ||
| sameSite: "lax", | ||
| secure: env.NODE_ENV === "production", | ||
| }); | ||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.