Skip to content
This repository has been archived by the owner on Jan 5, 2024. It is now read-only.

Commit

Permalink
docs: add custom auth docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ElasticBottle committed Dec 11, 2023
1 parent 43787f4 commit ceb02c6
Show file tree
Hide file tree
Showing 4 changed files with 351 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,110 @@ slug: /embedded-wallet/custom-auth
title: Use your own auth
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import Tabs from "@theme/Tabs";
import QuickstartCard from "@components/QuickstartCard";

By default, the embedded wallet service handles two things: auth, and spinning up crypto wallets tied to the auth. We require
valid authentication to ensure a wallet is created for the right person.
If you already have your own auth and only want to spin up wallets, we offer a simple way to hook up any **OpenID Connect ("OIDC") compatible** auth to create embedded wallets.
If you already have your own auth and only want to spin up wallets, we offer a simple way to hook up any auth to create embedded wallets.

## How it works

We offer two kinds of custom auth. One that is based on the OIDC standard, and one that is is based on you having you bring your own auth server.

### Bring your own auth server

- You have your own auth server that you use to authenticate users
- When a user logs in, you are able to generate a public identifier that allows you to identify the user.
- You can pass this identifier to the embedded wallet to generate a wallet for the user.
- When verifying the user, we will hit an endopint that you provide to verify the user's identity.
- We will then generate a wallet for the user if the provided payload is valid.

### OIDC

- An OIDC auth system has a public-private keypair, where the private key is used to sign auth tokens
- The public key is uploaded to a public URL in JWKS format. The standard location is `https://{domain}.com/.well-known/jwks.json`
- When a user logs in, a JWT token called the idToken is generated and signed by the private key. The OIDC spec provides an interface for fields that are used in this token.
- We use the public key to verify that the JWT was signed correctly, and proceed to generate a wallet based on the `sub` (user identifier) value of the idToken.
- This JWT is then passed to the embedded wallet to generate a wallet for the user.
- We will verify the JWT against the public key to verify that the JWT was signed correctly. Upon successful verification, we will proceed to generate a wallet based on the `sub` (user identifier) value of the idToken.

## Configuration Setup

In your API key settings, click edit, look for "Custom Auth" and provide the following values:

### Bring your own auth server

- An endpoint that we can hit to verify the user's identity
- This endpoint should accept a POST request with a JSON body containing the following fields:
- `payload`: This will correspont to the public identifier that was generated for your user.
- The endpoint should return a JSON body containing the following fields:
- `userId`: A uid for the user. Note that you can only create one wallet per `userId` at this point
- `email` (optional): If provided, the user will be able to access the same account outside of the platform for things like private key export // using with wallet connect etc.
- `exp` (optional): An expiration date for the user's wallet session. By default a session is 7 days long.
- A list of custom headers (optional)
- These headers will be sent with every request to your verification endpoint. You can use these to authenticate the request.

### OIDC

- The URL of the JWKS file (public key)
- This is used to verify the token was signed by you.
- The `aud` value of the idToken
- This is used to verify that thirdweb is the intended user of the token

## Authenticating a user

Once you've logged in with your own auth, you can pass the user's JWT to the embedded wallet to authenticate and connect.
Once you've logged in with your own auth, you can pass the user's detail to the embedded wallet to authenticate and connect.

### Bring your own auth server


<Tabs>
<TabItem value="react" label="React & React Native">

In React and React Native, the `useEmbeddedWallet()` hook handles authentication and connection states.

```typescript
import { useEmbeddedWallet } from "@thirdweb-dev/react"; // or /react-native

const embeddedWallet = useEmbeddedWallet();

const handlePostLogin = async (jwt: string) => {
await embeddedWallet.connect({
strategy: "auth_endpoint",
payload,
});
};
```

</TabItem>

<TabItem value="typescript" label="Other Typescript Frameworks">

In other frameworks, use your own instance of the wallet to authenticate and connect.

```typescript
import { EmbeddedWallet } from "@thirdweb-dev/wallets";
import { Goerli } from "@thirdweb-dev/chains";

const embeddedWallet = new EmbeddedWallet({
chain: Goerli, // chain to connect to
clientId: "YOUR_CLIENT_ID", // Your thirdweb client ID
});

const authResult = await embeddedWallet.authenticate({
strategy: "auth_endpoint",
payload,
});

const walletAddress = await embeddedWallet.connect({ authResult });
```

</TabItem>
</Tabs>


### OIDC

<Tabs>
<TabItem value="react" label="React & React Native">
Expand All @@ -51,7 +128,7 @@ const handlePostLogin = async (jwt: string) => {

</TabItem>

<TabItem value="typescript" label="Other Frameworks">
<TabItem value="typescript" label="Other Typescript Frameworks">

In other frameworks, use your own instance of the wallet to authenticate and connect.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,94 +3,118 @@ slug: /embedded-wallet/custom-auth-server
title: Custom Auth Server
---

# Create a custom auth server
# Create a custom JWT auth server

Learn how to integrate your auth backend with our embedded wallets solution so you can onboard your users into web3 seamlessly.
Learn how to integrate your auth backend with our embedded wallets solution so you can onboard your users into web3 seamlessly.

This guide will show you how to create your own Auth Server. By doing so, you can have full control over user authentication and data security. This allows you to ensure that your application meets specific compliance requirements while also providing a customized sign-in experience.
This guide will show you how to create your own Auth Server that is compatible with the `auth_endpoint` strategy. By doing so, you can have full control over user authentication and data security. This allows you to ensure that your application meets specific compliance requirements while also providing a customized sign-in experience.

:::caution
This guide is simplified for demonstration purposes and is not ready for production use. When modifying it for production, secure your endpoints and avoid hard-coding secrets or sensitive information. We recommend using environment variables and secret managers.
:::

### Setup
### 5 min whirlwind tour

1. Create a new directory for your project and navigate to it in your CLI
### **Integrate Embedded Wallets**

```bash
mkdir jwt-auth-server
cd jwt-auth-server
```
1. Navigate to Wallets > [Embedded Wallets](https://thirdweb.com/dashboard/wallets/embedded) in the thirdweb dashboard.
2. Create a thirdweb API key if you don't have one or select an existing key to use for this project. [Learn more about API keys.](https://portal.thirdweb.com/api-keys)

2. Initialize a new Node.js application
![Embedded wallet dashboard with create key displayed](../assets/ew-create-key.png)

```bash
npm init -y
3. Allowlist domain or bundle ids in Access Restrictions.
4. Navigate to the Configuration view and enable **Custom Auth Endpoint**

yarn init -y
```
![Configuration view for embedded wallet](../assets/ew-configuration.png)

3. Install the necessary packages
5. Set the Auth Endpoint URL to `https://embedded-wallet.thridweb.com/api/2023-11-30/embedded-wallet/auth/test-custom-auth-endpoint`
6. Save the configuration.
7. Copy the client ID.
8. In your preferred thirdweb client SDK, pass the payload you retrieved from logging in to the server.

```bash
npm install express jsonwebtoken
```
You can now auth into the wallet and use it to sign transactions like so (see [bring your own auth for more](/embedded-wallet/custom-auth)):

### **Generate RSA Key Pair:**
<Tabs>
<TabItem value="react" label="React & React Native">

1. To generate a private and a public key run
In React and React Native, the `useEmbeddedWallet()` hook handles authentication and connection states.

```bash
ssh-keygen -t rsa -b 2048 -m PEM -f keys/rsa.key
```
```typescript
import { useEmbeddedWallet } from "@thirdweb-dev/react"; // or /react-native

2. To create the output file run
const embeddedWallet = useEmbeddedWallet();

```bash
openssl rsa -in keys/rsa.key -pubout -outform PEM -out keys/rsa.key.pub
```
const handlePostLogin = async (jwt: string) => {
await embeddedWallet.connect({
strategy: "auth_endpoint",
payload: JSON.stringify({ userId:"ANY_RANDOM_ID_HERE" }),
});
};
```

</TabItem>
<TabItem value="typescript" label="Other Typescript Frameworks">

In other frameworks, use your own instance of the wallet to authenticate and connect.

```typescript
import { EmbeddedWallet } from "@thirdweb-dev/wallets";
import { Goerli } from "@thirdweb-dev/chains";

const embeddedWallet = new EmbeddedWallet({
chain: Goerli, // chain to connect to
clientId: "YOUR_CLIENT_ID", // Your thirdweb client ID
});

### **Convert Public Key to JSON Web Key Set (JWKS):**
const authResult = await embeddedWallet.authenticate({
strategy: "auth_endpoint",
payload: JSON.stringify({ userId:"ANY_RANDOM_ID_HERE" }),
});

1. Display the public key:
const walletAddress = await embeddedWallet.connect({ authResult });
```

</TabItem>
</Tabs>

A persistent, cross-platform wallet is now created for your user!

Of course, you would use your own auth server instead of the one we provided. The rest of this guide will show you how to create your own auth server.

### Setup

1. Create a new directory for your project and navigate to it in your CLI

```bash
cat keys/rsa.key.pub
mkdir custom-auth-server
cd custom-auth-server
```

2. Copy the displayed public key.
3. Convert your public key to a JWK using an online JWK Creator tool. We recommend using [JWK Creator by Russel Davies](https://github.com/russelldavies/jwk-creator).
2. Initialize a new Node.js application

1. Paste the public key, set Key ID as `0` (arbitrary string, must match when signing JWT), and then note down the generated JWK.
```bash
npm init -y

![JWK Creator tool by Russel Davies showing key id of 0](../assets/jwk-creator-tool.png)
yarn init -y
```

4. Create a `jwks.json` in the project root and place the generated JWK in a `keys` array.
3. Install the necessary packages

```bash
{
"keys": [
{
... JWK ...
}
]
}
npm install express jsonwebtoken
```

### **Create the Server:**

1. In the `jw-auth-server` directory, create a file at the root named `server.js` and paste the following:
1. In the `custom-auth-server` directory, create a file at the root named `server.js` and paste the following:

```jsx
const express = require("express");
const fs = require("fs");
const jwt = require("jsonwebtoken");

const app = express();
const PORT = process.env.PORT || 3000;

const PRIVATE_KEY = fs.readFileSync("./keys/rsa.key", "utf8");
const jwks = require("./jwks.json");

const users = [
{ id: 1, email: "[email protected]", password: "password123" },
Expand All @@ -105,33 +129,26 @@ This guide is simplified for demonstration purposes and is not ready for product
);
if (!user) return res.status(401).send({ message: "Invalid credentials" });

const payload = {
iss: "http://your-domain.com",
sub: user.id.toString(),
aud: "EpicGame",
email: user.email,
exp: Math.floor(Date.now() / 1000) + 3600,
};

const token = jwt.sign(payload, PRIVATE_KEY, {
algorithm: "RS256",
keyid: "0",
});

res.send({ token });
res.send({ payload: user.id });
});

app.get("/.well-known/jwks.json", (req, res) => {
res.json(jwks);
app.get("/thirdweb-will-call-this", (req, res) => {
const { payload } = req.body;
if (!payload) return res.status(401).send({ message: "Invalid credentials" });
const user = users.find((u) => u.id === payload);
if (!user) return res.status(401).send({ message: "Invalid credentials" });
return res.send({
userId: user.id,
email: user.email,
exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30,
});
});

app.listen(PORT, () => {
console.log(`Server started on port ${PORT}`);
});
```

2. Replace `http://your-domain.com` with the actual domain for the application.

### **Test Locally**

1. Start the server:
Expand All @@ -146,36 +163,26 @@ This guide is simplified for demonstration purposes and is not ready for product
curl -X POST http://localhost:3000/login -H "Content-Type: application/json" -d '{"email": "[email protected]", "password": "password123"}'
```

3. Test JWKS:

```bash
curl http://localhost:3000/.well-known/jwks.json
```

### **Deploy**

To deploy the server, you can use use services such as [Zeet](https://zeet.co/) or [Docker](https://www.docker.com/).

Once deployed, replace `http://localhost:3000` in the JWT payload with your actual domain

### **Integrate Embedded Wallets**

1. Navigate to Wallets > [Embedded Wallets](https://thirdweb.com/dashboard/wallets/embedded) in the thirdweb dashboard.
2. Create a thirdweb API key if you dont have one or select an existing key to use for this project. [Learn more about API keys.](https://portal.thirdweb.com/api-keys)
2. Create a thirdweb API key if you don't have one or select an existing key to use for this project. [Learn more about API keys.](https://portal.thirdweb.com/api-keys)

![Embedded wallet dashboard with create key displayed](../assets/ew-create-key.png)

3. Allowlist domain or bundle ids in Access Restrictions.
4. Navigate to the Configuration view and enable **Custom JSON Web Token**
4. Navigate to the Configuration view and enable **Custom Auth Endpoint**

![Configuration view for embedded wallet](../assets/ew-configuration.png)

5. Set the JWKS URI to `your-domain/.well-known/jwks.json`
6. Set the AUD to `EpicGame` or the value you set as the aud in the `server.js` file.

![Options for EW Configuration](../assets/ew-configuration-opt.png)

7. Copy the client ID.
8. In your preferred thirdweb client SDK, pass the JWT you retrieved from logging in to the server.
5. Set the Auth Endpoint URL to `https://your-domain/thirdweb-will-call-this`
6. Set any additional headers that you would like to send to your server. For example, you can set the `Authorization` header to with a bearer token to authenticate the request coming to the auth endpoint.
7. Save the configuration.
8. Copy the client ID.
9. In your preferred thirdweb client SDK, pass the payload you retrieved from logging in to the server.

A persistent, cross-platform wallet is now created for your user.
Loading

0 comments on commit ceb02c6

Please sign in to comment.