Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/thirdweb-example/firebase-auth

Integrate sign in with Ethereum using thirdweb Auth into your Firebase application
https://github.com/thirdweb-example/firebase-auth

auth firebase web2

Last synced: about 1 month ago
JSON representation

Integrate sign in with Ethereum using thirdweb Auth into your Firebase application

Awesome Lists containing this project

README

        

> [!Important]
> This repository is referencing the `mumbai` chain.
>
> `Mumbai` [is deprecated since 08/04/2024](https://blog.thirdweb.com/deprecation-of-mumbai-testnet/), meaning the code in this repository will no longer work out of the box.
>
> You can still use this repository, however you will have to switch any references to `mumbai` to another chain.

# thirdweb Auth + Firebase

This template shows you can use thirdweb Auth as a custom authentication provider for Firebase, and automatically create a document in the `users` Firestore collection when a user signs up successfully.





## Pre-requisites

- [Create a Firebase project](https://firebase.google.com/docs/web/setup#create-project)
- [Register your Firebase app](https://firebase.google.com/docs/web/setup#register-app)
- [Create and export a service account as a JSON file](https://firebase.google.com/docs/admin/setup#initialize-sdk)
- Make sure to enable Firebase Authentication as we'll be using the [Custom Authentication](https://firebase.google.com/docs/auth/web/custom-auth?hl=en&authuser=0) method and create a [Cloud Firestore](https://firebase.google.com/docs/firestore/quickstart?hl=en&authuser=0) database within your project.

## Set Up

To begin with, let's create a new Next.js project with the SDK configured:

```bash
npx thirdweb create app --next --ts
```

From within the created directory, we need to install `@thirdweb-dev/auth`, `firebase` and `firebase-admin`:

```bash npm2yarn
npm install @thirdweb-dev/auth firebase firebase-admin
```

### Configure Firebase

We'll use environment variables to store our Firebase configuration.

Create a `.env.local` file in the root of your project and add the corresponding values from your Firebase project:

```
NEXT_PUBLIC_API_KEY=
NEXT_PUBLIC_AUTH_DOMAIN=
NEXT_PUBLIC_PROJECT_ID=
NEXT_PUBLIC_STORAGE_BUCKET=
NEXT_PUBLIC_MESSAGING_SENDER_ID=
NEXT_PUBLIC_APP_ID=
FIREBASE_PRIVATE_KEY=
FIREBASE_CLIENT_ID=
FIREBASE_PRIVATE_KEY_ID=
FIREBASE_CLIENT_EMAIL=
```

Most of the above environment variables can be found in the settings page of your Firebase project (after adding a Web app to your project), or in the service role JSON file you created and downloaded earlier.

Create a new directory called `lib` and create two helper scripts to initialize Firebase in the browser and server:

- [lib/initFirebase.ts](https://github.com/thirdweb-example/firebase-auth/blob/main/lib/initFirebase.ts)
- [lib/initFirebaseAdmin.ts](https://github.com/thirdweb-example/firebase-auth/blob/main/lib/initFirebaseAdmin.ts)

Now we have an easy way to access Firebase Auth and Firestore in both client and server environments!

### Configure thirdweb Auth

Finally, to configure thirdweb Auth, we just need to add the `NEXT_PUBLIC_THIRDWEB_AUTH_DOMAIN` evironment variable to the `.env.local` file as follows:

```
NEXT_PUBLIC_THIRDWEB_AUTH_DOMAIN=
```

The `NEXT_PUBLIC_THIRDWEB_AUTH_DOMAIN` is used to prevent phishing attacks - and is usually set to the domain of your project like `example.com`. You can read more about it in the [thirdweb Auth Documentation](https://portal.thirdweb.com/auth/how-auth-works/sign-in-with-wallet#domain).

### ThirdwebProvider

Inside the `pages/_app.tsx` file, configure the `authConfig` option:

```ts title="pages/_app.tsx"
import type { AppProps } from "next/app";
import { ThirdwebProvider } from "@thirdweb-dev/react";

// This is the chain your dApp will work on.
const activeChain = "mumbai";

function MyApp({ Component, pageProps }: AppProps) {
return (



);
}

export default MyApp;
```

## Sign Up / Log In Users

The process of creating users in Firebase by authenticating them with their wallet has two steps:

1. Authenticate the user with their wallet
2. Create a user in Firebase with the knowledge that they own this wallet

On the homepage (`pages/index.tsx`), we'll allow the user to connect their wallet and then sign in with Ethereum.

```tsx title="pages/index.tsx"
import React from "react";
import { ConnectWallet, useAddress, useAuth } from "@thirdweb-dev/react";
import { doc, serverTimestamp, setDoc } from "firebase/firestore";
import { signInWithCustomToken } from "firebase/auth";
import initializeFirebaseClient from "../lib/initFirebase";

export default function Login() {
const thirdwebAuth = useAuth();
const address = useAddress();
const { auth, db } = initializeFirebaseClient();

return (


{address ? (
signIn()}>Sign in with Wallet
) : (

)}

);
}
```

The `signIn` function:

1. Makes a request to the `api/auth/login` endpoint to get a custom token from Firebase
2. Signs the user in with the custom token
3. Creates a user in Firestore with the verified user's address

```tsx title="pages/index.tsx"
// Note: This function lives inside the Login component above.
const signIn = async () => {
// Use the same address as the one specified in _app.tsx.
const payload = await thirdwebAuth?.login();

try {
// Make a request to the API with the payload.
const res = await fetch("/api/auth/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ payload }),
});

// Get the returned JWT token to use it to sign in with
const { token } = await res.json();

// Sign in with the token.
const userCredential = await signInWithCustomToken(auth, token);
// On success, we have access to the user object.
const user = userCredential.user;

// If this is a new user, we create a new document in the database.
const usersRef = doc(db, "users", user.uid!);
const userDoc = await getDoc(usersRef);

if (!userDoc.exists()) {
// User now has permission to update their own document outlined in the Firestore rules.
setDoc(usersRef, { createdAt: serverTimestamp() }, { merge: true });
}
} catch (error) {
console.error(error);
}
};
```

In this function, you'll notice we're calling the `/api/auth/login` endpoint to get a
[custom JWT token from Firebase](https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_the_firebase_admin_sdk).

Let's take a look at that API route.

### Auth API Route

Create a folder that lives in the `/pages/api/auth` directory called `login.ts`.

This API route is responsible for:

1. Verifying the payload provided by the client
2. Once the payload is verified, creating a [custom token](https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_the_firebase_admin_sdk)
for the user to sign in to Firebase with.

```ts title="pages/api/auth/login.ts"
import { NextApiRequest, NextApiResponse } from "next";
import { verifyLogin } from "@thirdweb-dev/auth/evm";
import initializeFirebaseServer from "../../../lib/initFirebaseAdmin";

const login = async (req: NextApiRequest, res: NextApiResponse) => {
// Grab the login payload the user sent us with their request.
const payload = req.body.payload;

const { address, error } = await verifyLogin(
process.env.NEXT_PUBLIC_THIRDWEB_AUTH_DOMAIN as string,
payload
);
if (!address) {
return res.status(401).json({ error });
}

// Initialize the Firebase Admin SDK.
const { auth } = initializeFirebaseServer();

// Generate a JWT token for the user to be used on the client-side.
const token = await auth.createCustomToken(address);

// Send the token to the client-side.
return res.status(200).json({ token });
};

export default login;
```

You'll now be able to use Firebase Authentication to authenticate users with their wallets!

### Firestore Rules (Optional)

You'll likely want to add a [security rule](https://firebase.google.com/docs/firestore/security/get-started)
to your Firestore database that only allows users to update their documents.

```cel title="firestore.rules"
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// The wildcard expression {userId} makes the userId variable available in rules.
match /users/{userId} {
// Only allow users to update their own documents.
allow create, update, delete: if request.auth != null && request.auth.uid == userId;
// But anybody can read their profile.
allow read;
}
}
}
```

### Viewing the Result

When you click the "Sign in with Ethereum" button and successfully sign in, you'll be signed up as a user in Firebase and a new document will be created in your `users` collection in Firestore:

You can now use all the functionality of Firebase Authentication and Firestore to build your app!

## What's Next?

- [Get the current Firebase user](https://github.com/thirdweb-example/firebase-auth/blob/main/lib/useFirebaseUser.ts)
- [Read the current user's document from Firestore](https://github.com/thirdweb-example/firebase-auth/blob/main/lib/useFirebaseUserDocument.ts)
- [Sign out](https://github.com/thirdweb-example/firebase-auth/blob/main/pages/index.tsx#L84-L89)