Skip to content

Commit

Permalink
feat: one tap (better-auth#419)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bekacru authored Nov 4, 2024
1 parent 72de87f commit 2ba1584
Show file tree
Hide file tree
Showing 21 changed files with 378 additions and 43 deletions.
6 changes: 6 additions & 0 deletions demo/nextjs/app/(auth)/sign-in/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
import SignIn from "@/components/sign-in";
import { SignUp } from "@/components/sign-up";
import { Tabs } from "@/components/ui/tabs2";
import { client } from "@/lib/auth-client";
import { useEffect } from "react";

export default function Page() {
useEffect(() => {
client.oneTap();
}, []);

return (
<div className="w-full">
<div className="flex items-center flex-col justify-center w-full md:py-10">
Expand Down
15 changes: 10 additions & 5 deletions demo/nextjs/app/admin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,21 @@ export default function AdminDashboard() {

const { data: users, isLoading: isUsersLoading } = useQuery({
queryKey: ["users"],
queryFn: () =>
client.admin
.listUsers({
queryFn: async () => {
const data = await client.admin.listUsers(
{
query: {
limit: 10,
sortBy: "createdAt",
sortDirection: "desc",
},
})
.then((res) => res.data?.users ?? []),
},
{
throw: true,
},
);
return data?.users || [];
},
});

const handleCreateUser = async (e: React.FormEvent) => {
Expand Down
11 changes: 1 addition & 10 deletions demo/nextjs/app/dashboard/user-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ import {
} from "lucide-react";
import Image from "next/image";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useState } from "react";
import { toast } from "sonner";
import { UAParser } from "ua-parser-js";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import {
Table,
TableBody,
Expand All @@ -63,14 +62,7 @@ export default function UserCard(props: {
}) {
const router = useRouter();
const { data, isPending, error } = useSession();
const [ua, setUa] = useState<UAParser.UAParserInstance>();

const session = data || props.session;

useEffect(() => {
setUa(new UAParser(session?.session.userAgent));
}, [session?.session.userAgent]);

const [isTerminating, setIsTerminating] = useState<string>();
const [isPendingTwoFa, setIsPendingTwoFa] = useState<boolean>(false);
const [twoFaPassword, setTwoFaPassword] = useState<string>("");
Expand Down Expand Up @@ -668,7 +660,6 @@ function EditUserDialog(props: { session: Session | null }) {
function AddPasskey() {
const [isOpen, setIsOpen] = useState(false);
const [passkeyName, setPasskeyName] = useState("");
const queryClient = useQueryClient();
const [isLoading, setIsLoading] = useState(false);

const handleAddPasskey = async () => {
Expand Down
17 changes: 0 additions & 17 deletions demo/nextjs/components/account-swtich.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,8 @@ export default function AccountSwitcher({
}: {
sessions: Session[];
}) {
const { data: users } = useQuery({
queryKey: ["users"],
queryFn: async () => {
return;
},
});
const { data: currentUser } = useSession();
const [open, setOpen] = useState(false);

const handleUserSelect = (user: Session) => {
// setCurrentUser(user);
setOpen(false);
};

const handleAddAccount = () => {
// Implement add account logic here
console.log("Add account clicked");
setOpen(false);
};
const router = useRouter();
return (
<Popover open={open} onOpenChange={setOpen}>
Expand Down
4 changes: 2 additions & 2 deletions demo/nextjs/components/logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ export const Logo = (props: SVGProps<any>) => {
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
fillRule="evenodd"
clipRule="evenodd"
d="M0 0H15V15H30V30H15V45H0V30V15V0ZM45 30V15H30V0H45H60V15V30V45H45H30V30H45Z"
className="fill-black dark:fill-white"
/>
Expand Down
4 changes: 4 additions & 0 deletions demo/nextjs/lib/auth-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
twoFactorClient,
adminClient,
multiSessionClient,
oneTapClient,
} from "better-auth/client/plugins";
import { toast } from "sonner";

Expand All @@ -18,6 +19,9 @@ export const client = createAuthClient({
passkeyClient(),
adminClient(),
multiSessionClient(),
oneTapClient({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!,
}),
],
fetchOptions: {
onError(e) {
Expand Down
2 changes: 2 additions & 0 deletions demo/nextjs/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
organization,
passkey,
twoFactor,
oneTap,
} from "better-auth/plugins";
import { reactInvitationEmail } from "./email/invitation";
import { LibsqlDialect } from "@libsql/kysely-libsql";
Expand Down Expand Up @@ -120,5 +121,6 @@ export const auth = betterAuth({
bearer(),
admin(),
multiSession(),
oneTap(),
],
});
20 changes: 20 additions & 0 deletions docs/components/sidebar-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,26 @@ export const contents: Content[] = [
),
},

{
title: "One Tap",
href: "/docs/plugins/one-tap",
icon: () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="1.2em"
height="1.2em"
viewBox="0 0 14 14"
>
<path
fill="currentColor"
fillRule="evenodd"
d="M3.254 4.361a2.861 2.861 0 1 1 5.647.651a.75.75 0 0 0 1.461.34a4.361 4.361 0 1 0-8.495 0a.75.75 0 0 0 1.461-.34a3 3 0 0 1-.074-.651m1.63 5.335V4.26a1.26 1.26 0 0 1 2.518 0v4.077h2.464a2.573 2.573 0 0 1 2.573 2.573V13a1 1 0 0 1-1 1H4.83a1 1 0 0 1-.823-.433l-.764-1.11a1.715 1.715 0 0 1 1.097-2.66l.543-.102Z"
clipRule="evenodd"
></path>
</svg>
),
},

{
title: "Authorization",
group: true,
Expand Down
89 changes: 89 additions & 0 deletions docs/content/docs/plugins/one-tap.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
title: One Tap
description: One Tap plugin for BetterAuth
---

The One Tap plugin allows users to login with a single tap using Google's One Tap API.

## Installation

<Steps>
<Step>
### Add the server Plugin

Add the One Tap plugin to your auth config.

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { oneTap } from "better-auth/plugins";

export const auth = betterAuth({
plugins: [ // [!code highlight]
oneTap(), // [!code highlight]
] // [!code highlight]
})
```
</Step>

<Step>
### Add the client Plugin

Add the client plugin and Specify where the user should be redirected if they need to verify 2nd factor

```ts title="client.ts"
import { createAuthClient } from "better-auth/client"
import { oneTapClient } from "better-auth/client/plugins"

const client = createAuthClient({
plugins: [
oneTapClient({
clientId: "YOUR_CLIENT_ID"
})
]
})
```
</Step>
</Steps>

## Usage

To make the one tap pop up appear, you can call the `oneTap` method.

```ts
await authClient.oneTap()
```

By default, the plugin will automatically redirect the user to "/" after the user has successfully logged in. It does a hard redirect, so the page will be reloaded. If you want to
avoid this, you can pass `fetchOptions` to the `oneTap` method.

```tsx
authClient.oneTap({
fetchOptions: {
onSuccess: () => {
router.push("/dashboard")
}
}
})
```

If you want it to hard redirect to a different page, you can pass the `callbackURL` option to the `oneTap` method.

```tsx
authClient.oneTap({
callbackURL: "/dashboard"
})
```

## Client Options

**clientId**: The client ID of your Google One Tap API

**autoSelect**: Automatically select the first account in the list. Default is `false`

**context**: The context in which the One Tap API should be used. Default is `signin`

**cancelOnTapOutside**: Cancel the One Tap popup when the user taps outside of the popup. Default is `true`.

## Server Options

**disableSignUp**: Disable the sign up option. Default is `false`. If set to `true`, the user will only be able to sign in with an existing account.
1 change: 0 additions & 1 deletion packages/better-auth/src/api/routes/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ export const getSession = <Option extends BetterAuthOptions>() =>

const session =
await ctx.context.internalAdapter.findSession(sessionCookieToken);
console.log({ session });

if (!session || session.session.expiresAt < new Date()) {
deleteSessionCookie(ctx);
Expand Down
2 changes: 0 additions & 2 deletions packages/better-auth/src/api/routes/sign-in.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { APIError } from "better-call";
import { generateCodeVerifier } from "oslo/oauth2";
import { z } from "zod";
import { createAuthEndpoint } from "../call";
import { setSessionCookie } from "../../cookies";
import { socialProviderList } from "../../social-providers";
import { createEmailVerificationToken } from "./email-verification";
import { generateState, logger } from "../../utils";
import { hmac } from "../../crypto/hash";

export const signInOAuth = createAuthEndpoint(
"/sign-in/social",
Expand Down
1 change: 1 addition & 0 deletions packages/better-auth/src/client/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from "../../plugins/generic-oauth/client";
export * from "../../plugins/jwt/client";
export * from "../../plugins/multi-session/client";
export * from "../../plugins/email-otp/client";
export * from "../../plugins/one-tap/client";
2 changes: 1 addition & 1 deletion packages/better-auth/src/client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export type InferActions<O extends ClientOptions> = O["plugins"] extends Array<
>
? UnionToIntersection<
Plugin extends BetterAuthClientPlugin
? Plugin["getActions"] extends ($fetch: BetterFetch) => infer Actions
? Plugin["getActions"] extends (...args: any) => infer Actions
? Actions
: {}
: {}
Expand Down
2 changes: 1 addition & 1 deletion packages/better-auth/src/db/internal-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export const createInternalAdapter = (
},
createSession: async (
userId: string,
request?: Request | Headers,
request: Request | Headers | undefined,
dontRememberMe?: boolean,
override?: Partial<Session> & Record<string, any>,
) => {
Expand Down
1 change: 1 addition & 0 deletions packages/better-auth/src/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from "./generic-oauth";
export * from "./jwt";
export * from "./multi-session";
export * from "./email-otp";
export * from "./one-tap";
Loading

0 comments on commit 2ba1584

Please sign in to comment.