# Clerk Blog — Engineering — Page 2

# Stable Support for the Next.js App Router, plus a Middleware Update!
URL: https://clerk.com/blog/nextjs-13-4.md
Date: 2023-05-04
Category: Engineering
Description: App Router support is out of beta, plus we've launched a major middleware update.

## @clerk/nextjs\@4.17.0 is released

Clerk has updated our SDK to support Next.js version 13.4.0. We've added stable support for the App Router, which is the default for new applications. We've also improved the ergonomics of our middleware helper for more composability and to mitigate common pitfalls.

[See the updates in our new Next.js documentation](/docs/nextjs/get-started-with-nextjs), or read on for more details.

### Stable App Router Support

Next.js version 13.4.0 launched today and the App Router is now stable. In turn, Clerk's support for the App Router is also now stable in `@clerk/nextjs` version 4.17.0.

If you previously adopted `@clerk/nextjs/app-beta`, there have been very few changes:

- The `auth()` and `currentUser()` helpers have been moved to a permanent home in `@clerk/nextjs`
- React imports from `@clerk/nextjs/app-beta/client` are no longer necessary, and you can import from `@clerk/nextjs` intstead. The package now automatically detects if components are being used from a client component or a server component, and loads the proper form.

That's all! Our documentation has been updated to [reflect the changes](/docs/nextjs/get-started-with-nextjs).

### Middleware Update

Along with today's launch, we've also released a new middleware helper to make things a little easier and more composable.

In its simplest form, these few lines are all you need to [integrate Clerk](/nextjs-authentication):

```typescript
import { authMiddleware } from '@clerk/nextjs'

export default authMiddleware()

export const config = {
  matcher: ['/((?!.*\\..*|_next).*)'],
}
```

This sets your application in a protected mode – if users are signed out the will be automatically redirected to a sign in. Unprotected pages need to be explicitly listed in the `publicRoutes` argument:

```typescript
export default authMiddleware({
  // Make the homepage accessible while signed out
  publicRoutes: ['/'],
})
```

This new helper also has `beforeAuth` and `afterAuth` arguments to enable more composability with libraries like `next-intl`. For more details, checkout the updated [middleware documentation](/docs/nextjs/middleware).

---

# Refactoring our frontend API key: Familiar DX is the best DX
URL: https://clerk.com/blog/refactoring-our-api-keys.md
Date: 2023-01-27
Category: Engineering
Description: We switched to the familiar Publishable Key, but we changed less than you'd think

Like most other developer tools, Clerk's SDKs are configured with two "keys," one for the backend and one for the frontend.

And we share the same core requirements:

- The backend key must have significantly random so it cannot be guessed
- The frontend key is public, so it only needs to be a unique identifier

Although there's no security benefit in doing so, many tools have their frontend key mirror the format and length of their backend key. Take Stripe, for example:

!\[Although there's no security benefit in doing so, many tools have their frontend key mirror the format and length of their backend key. Take Stripe, for example: screenshot]\(./995856b7b27f199531ec648ab53d2866eaeae372-814x332.png '(Don't worry, the secret key has been rolled.)

But as an authentication company, Clerk has an extra requirement for our frontend key, and it meant that mirroring our secret key would cause *performance* issues.

Wait, what? How could a key cause performance issues?

The purpose of a frontend key is to be a unique identifier when interacting with a frontend-facing API. Here's an example of how Stripe's SDK uses the publishable key:

![The purpose of a frontend key is to be a unique identifier when interacting with a frontend-facing API. Here's an example of how Stripe's SDK uses the publishable key: screenshot](./6de4356a8cc28037f37729a941cdfb6e483ce6ef-689x175.png "That's the same publishable key as above!")

Notice how this request is being sent to a **stripe.com** domain? Stripe SDKs always make requests to **stripe.com**, even if you're embedding their elements into your own website.

But since Clerk runs an authentication API and since we're responsible for maintaining sessions, we can't securely do the same. We need to set [HttpOnly cookies](https://owasp.org/www-community/HttpOnly) from a first-party context, which means our API needs to be accessible through our customers' domains. *(Developers configure this by setting a CNAME in their DNS records.)*

When we launched, our frontend key was simply the hostname where our frontend API is hosted. Developers configured it like this in their React apps:

```jsx {{ prettier: false }}
<ClerkProvider frontendApi="clerk.example.com">
```

By passing the API hostname directly, we avoided making an extra, waterfalled API request to exchange a traditional random key with the hostname. This led to faster overall loading speeds.

But we hit an unexpected problem with this strategy: it *really* confused developers. It was a common complaint in friction logs, and when we watched developers integrate Clerk we could see the confusion wash over their face.

A hostname as a frontend key is completely unfamiliar, and no matter what we tried with design and naming, we couldn't get over the hurdle.

So this week, we finally threw in the towel. Our new frontend API keys look just like Stripes:

![So this week, we finally threw in the towel. Our new frontend API keys look just like Stripes: screenshot](./483632fdf53ea7aa1f455e10d9ca7faa463384e5-1006x197.png "Clerk's new publishable key")

But we refuse to exchange developer experience for performance, so there's a not-so-secret subtlety to our new publishable key. Take a closer look:

`pk_test_Y2xlcmsuZXhhbXBsZS5jb20k`

Now, base64-decode the part after `pk_test_`:

`clerk.example.com$`

Indeed, we just base64-encoded the old value and started calling it a publishable key. We added a $ as a simple stop character so we can detect when keys are malformed.

As a final step, we changed the prop name for React:

```jsx {{ prettier: false }}
<ClerkProvider publishableKey="pk_test_Y2xlcmsuZXhhbXBsZS5jb20k">
```

Quick, dirty, and a little silly – but it works! We haven't sacrificed performance and our new publishable key feels much more familiar. Developers have stopped raising their eyebrows and breeze through initial setup.

---

# How to skip Next.js middleware for static and public files
URL: https://clerk.com/blog/skip-nextjs-middleware-static-and-public-files.md
Date: 2022-10-06
Category: Engineering
Description: Stop your Next.js middleware from running on static assets like images and Next.js internals

[Next.js middleware](https://nextjs.org/docs/advanced-features/middleware) is incredibly powerful, but by default it runs on more requests than is normally necessary. To see this in action, you can add a simple logger:

```javascript {{ title: 'middleware.js' }}
export default function middleware(req) {
  console.log(req.url)
}
```

Here's the log for loading [http://localhost:3000/](http://localhost:3000) on a brand new Next.js application:

```text
http://localhost:3000/
http://localhost:3000/_next/static/chunks/webpack.js?ts=1665116452838
http://localhost:3000/_next/static/chunks/main.js?ts=1665116452838
http://localhost:3000/_next/static/chunks/react-refresh.js?ts=1665116452838
http://localhost:3000/_next/static/chunks/pages/_app.js?ts=1665116452838
http://localhost:3000/_next/static/development/_buildManifest.js?ts=1665116452838
http://localhost:3000/_next/static/development/_ssgManifest.js?ts=1665116452838
http://localhost:3000/_next/static/chunks/pages/index.js?ts=1665116452838
http://localhost:3000/favicon.ico
http://localhost:3000/_next/static/development/_devMiddlewareManifest.json
http://localhost:3000/_next/static/development/_devPagesManifest.json
http://localhost:3000/vercel.svg
```

The log shows several static assets that you probably don't want to process in your middleware, and doing so could break your application. To solve this, you can configure a [matcher](https://nextjs.org/docs/advanced-features/middleware#matcher), which tells your middleware to only run on requests that match a certain pattern.

To prevent middleware from running on static files, you can leverage a simple trick: static files have a **`.`** in the path, while dynamic files do not.

With a regular expression, you can configure middleware to run on every file that does not contain a **`.`**:

```javascript {{ title: 'middleware.js' }}
export default function middleware(req) {
  console.log(req.url)
}

export const config = { matcher: '/((?!.*\\.).*)' }
```

With this matcher, the log only shows one request:

```text
http://localhost:3000/
```

This matcher is a great starting point that minimizes middleware invocation. As your application grows, though, you may need to tweak it. Below are the two most common revisions.

### Including *some* static assets

The easiest way to include some static assets in middleware is to retain the exclusionary regular expression, but define an *additional* matcher. Here's a sample that excludes all static assets from middleware except `favicon.ico`:

```javascript {{ title: 'middleware.js' }}
export const config = {
  matcher: ['/((?!.*\\.).*)', '/favicon.ico'],
}
```

### Excluding more paths from middleware

Sometimes you will want to filter more than just static files. This can be done in two ways:

#### 1. Expanding the regular expression

Expanding the regular expression prevents additional middleware invocations, but regular expressions are also harder to read and write. Here's an example that excludes API routes in addition to static assets:

```javascript {{ title: 'middleware.js' }}
export const config = { matcher: '/((?!.*\\.|api\\).*)' }
```

#### 2. Adding a conditional statement

A more readable approach is to create a conditional statement, but this will waste compute resources since your middleware will be unnecessarily invoked. Here's an example:

```javascript {{ title: 'middleware.js' }}
import { NextResponse } from 'next/server'

export default function middleware(req) {
  if (req.nextUrl.pathname.startsWith('/api/')) {
    return NextResponse.next()
  }
  // ... your middleware
}

export const config = { matcher: '/((?!.*\\.).*)' }
```

This should be everything you need to get started on the right foot with middleware!

---

# Let's stop arguing about JWTs and just fix them
URL: https://clerk.com/blog/lets-stop-arguing-about-jwts-and-just-fix-them.md
Date: 2022-10-05
Category: Engineering
Description: JWTs have won. It's time we embrace them and fix the dangerous implementations.

This week there was a [fresh](https://news.ycombinator.com/item?id=33019960) [batch](https://news.ycombinator.com/item?id=33061873) of debates about JWTs as session tokens on Hacker News. For the uninitiated, this happens incredibly frequently on HN, to the point where moderator dang has posted roundups:

![Lets Stop Arguing About Jwts And Just Fix Them guide illustration](./5e84204a848495c412d2cf8d45a8b193b3417bcd-1258x476.png)

Just about every thread goes the same way:

1. Everyone agrees that infrequently-refreshed, stateless JWTs should not be used as session tokens because they're irrevocable
2. Everyone agrees that it's pointless to use long-lived, stateless JWTs in combination with a stateful, database-backed blocklist of revoked JWTs
3. Everyone agrees that database-backed, stateful session tokens are easy to build and sufficient for the 99% case
4. With trepidation, everyone agrees that frequently-refreshed, stateless JWTs are acceptable as session tokens because the short expiration serves as a revocation mechanism

Why the trepidation on 4? Usually, it's because 3 is easier. Here's [one viral post's](https://apibakery.com/blog/tech/no-jwt) rationale (they refer to stateful session tokens as bearer tokens):

> \[...] you've just reintroduced a bearer token, because that's exactly what the refresh token is. Looking at JWTs from that perspective, you've introduced a client-side cache of user identity (the JWT) and added a bunch of complexity (involving the creation, verification, and token refresh) for the hope of optimizing part of the work you used to do on the server (checking user identity using a bearer token). Was it worth it?

The author is right: The complexity of 4 is high and the benefits for the 99% case are minimal.

Yet, JWTs are clearly winning. Their usage has grown, not dwindled, while two major trends in software development have increased their demand.

### Trend 1: Developers are relentlessly focused on efficiency

This has been a trend for decades. It's *impressive* that today's developers care about a 10ms query vs a \<1ms JWT, but it's not *surprising*.

The simple reality is that Google Lighthouse scores – and the wealth of evidence supporting that users prefer fast applications – have placed an unprecedented emphasis on loading speed.

The developers who care most are no stranger to complexity, as they're often thinking about problems like distributed storage and operating at the edge. It's no surprise they're eager to treat one less query as an easy win.

### Trend 2: Modern integrations often require a synced session

This trend is more recent. Third-party integrations are sweetening the buy-vs-build deal by doing more for their customers. If an integration knows which user is signed in and their permissions, then it can expose APIs directly to the frontend, and even offer user-facing UIs as part of their service:

- New database tools like Supabase, Hasura, Grafbase, Convex all allow querying from the frontend, and use JWTs to know which user is signed in
- Embeddable help desk and community tools like Zendesk and Canny use JWTs to know which user is signed in
- Stripe's user-facing UIs (Checkout, Customer Portal, Payment Element) use a backend API request and session token to know which user is signed in (not a JWT, but still part of the trend!)

The newer a tool is, the more likely it is to allow syncing sessions by JWT.

### It's time to embrace JWTs and disarm the footguns

These trends aren't going anywhere. It's time we embrace JWTs and fix the bad implementations that have stained their reputation:

#### For web developers

Check your application code. If you use stateless JWTs (no database check) and they don't expire in 5 minutes or less, report it to your security team.

#### For authentication tools

Don't generate session JWTs with a lifetime greater than 5 minutes. If developers want to configure a longer lifetime, warn that it's bad practice for XSS attacks.

Provide a refresh mechanism that depends on a HttpOnly cookie in the browser.

#### For integrations

Don't accept session JWTs with a lifetime greater than 5 minutes. If you must, warn developers that it's bad practice for XSS attacks.

Critically, provide developers with a mechanism to send a new JWT after the first JWT expires – don't receive a JWT once and then manage an independent session.

### Really, just expiration?

Yes, long expiration is the #1 most common security mistake with JWTs. It leaves many sites especially vulnerable when XSS attacks or account takeovers occur.

#### Does Clerk do this?

Yes! Clerk's session JWTs default to a 1 minute lifetime, and our refresh mechanism depends on an HttpOnly cookie. We even offer "Active Device" management in our `<UserProfile/>` component so end-users can revoke their own sessions.

---

# How to pass a value from Next.js middleware to API routes and getServerSideProps
URL: https://clerk.com/blog/nextjs-pass-value-from-middleware-to-api-routes-and-getserversideprops.md
Date: 2022-10-05
Category: Engineering
Description: Compute a value in middleware and pass it to your API route or getServerSideProps. Works in both Node and Edge runtimes.

Unlike many web frameworks, [Next.js middleware](https://nextjs.org/docs/advanced-features/middleware) doesn't have a built-in mechanism for passing values from middleware to other parts of the application.

> For authentication-specific middleware patterns in Next.js, see our [Next.js Authentication](/nextjs-authentication) solution.

Instead, middleware has a feature called "rewrites" that we can leverage to pass data.

The high-level idea is to "rewrite" requests to the same URL, but modify the request's metadata to include the data we want to pass. Then, we can read the metadata from our API route or getServerSideProps.

Unfortunately, there are inconsistencies across runtimes that make it difficult to get this working. We hope these snippets help save you save you some headaches.

**License: MIT**

**[Live Demo](https://nextjs-context-demo.vercel.app) | [Source Code](https://github.com/clerkinc/nextjs-context-example)**

**Usage: middleware.js**

```javascript
import { NextResponse } from 'next/server'
import { withContext } from './context'

// Pre-define the possible context keys to prevent spoofing
const allowedContextKeys = ['foo']

export default withContext(allowedContextKeys, (setContext, req) => {
  setContext('foo', 'bar')
  return NextResponse.next()
})
```

**Usage: API route (Node)**

```javascript
import { getContext } from '../../context'

export default function handler(req, res) {
  res.status(200).json({ foo: getContext(req, 'foo') })
}
```

**Usage API route (Edge)**

```javascript
import { getContext } from '../../context'

export default function handler(req) {
  return new Response(JSON.stringify({ foo: getContext(req, 'foo') }))
}
```

**Usage: getServerSideProps (Edge and Node)**

```javascript
import { getContext } from '../context'

export const getServerSideProps = ({ req }) => {
  return { props: { foo: getContext(req, 'foo') } }
}
```

**Source: (saved to context.js on your root)**

```javascript
import { NextResponse } from 'next/server'

const ctxKey = (key) => `ctx-${key.toLowerCase()}`

export const getContext = (req, rawKey) => {
  const key = ctxKey(rawKey)

  let headerValue =
    typeof req.headers.get === 'function'
      ? req.headers.get(key) // Edge
      : req.headers[key] // Node;

  // Necessary for node in development environment
  if (!headerValue) {
    headerValue = req.socket?._httpMessage?.getHeader(key)
  }

  if (headerValue) {
    return headerValue
  }

  // Use a dummy url because some environments only return
  // a path, not the full url
  const reqURL = new URL(req.url, 'http://dummy.url')

  return reqURL.searchParams.get(key)
}

export const withContext = (allowedKeys, middleware) => {
  // Normalize allowed keys
  for (let i = 0; i < allowedKeys.length; i++) {
    if (typeof allowedKeys[i] !== 'string') {
      throw new Error('All keys must be strings')
    }
    allowedKeys[i] = ctxKey(allowedKeys[i])
  }

  return (req, evt) => {
    const reqURL = new URL(req.url)

    // First, make sure allowedKeys aren't being spoofed.
    // Reliably overriding spoofed keys is a tricky problem and
    // different hosts may behave different behavior - it's best
    // just to safelist "allowedKeys" and block if they're being
    // spoofed
    for (const allowedKey of allowedKeys) {
      if (req.headers.get(allowedKey) || reqURL.searchParams.get(allowedKey)) {
        throw new Error(`Key ${allowedKey.substring(4)} is being spoofed. Blocking this request.`)
      }
    }

    const data = {}

    const setContext = (rawKey, value) => {
      const key = ctxKey(rawKey)
      if (!allowedKeys.includes(key)) {
        throw new Error(`Key ${rawKey} is not allowed. Add it to withContext's first argument.`)
      }
      if (typeof value !== 'string') {
        throw new Error(`Value for ${rawKey} must be a string, received ${typeof value}`)
      }
      data[key] = value
    }

    let res = middleware(setContext, req, evt) || NextResponse.next()

    // setContext wasn't called, passthrough
    if (Object.keys(data).length === 0) {
      return res
    }

    // Don't modify redirects
    if (res.headers.get('Location')) {
      return res
    }

    const rewriteURL = new URL(res.headers.get('x-middleware-rewrite') || req.url)

    // Don't modify cross-origin rewrites
    if (reqURL.origin !== rewriteURL.origin) {
      return res
    }

    // Set context directly on the res object (headers)
    // and on the rewrite url (query string)
    for (const key in data) {
      res.headers.set(key, data[key])
      rewriteURL.searchParams.set(key, data[key])
    }

    // set the updated rewrite url
    res.headers.set('x-middleware-rewrite', rewriteURL.href)

    return res
  }
}
```

**Known limitations:**

Depending on the runtime, your data will be transmitted as either an HTTP header or a URL query string. This leads to several limitations:

- Headers and query strings only accept strings for key/value pairs. If you'd like to use non-strings, you'll need to bring your own serializer
- Keys are lowercases because headers are case-insensitive
- Your host likely limits the total overall length of headers and query strings. [Here are the limits for Vercel's edge runtime](https://vercel.com/docs/concepts/functions/edge-functions/limitations#limits-on-requests), for example

---

# @clerk/nextjs v4.5
URL: https://clerk.com/blog/clerk-nextjs-4-5.md
Date: 2022-10-04
Category: Engineering
Description: New in 4.5: Authentication moves to middleware, switchable runtime support, improved developer experience, preparation for Layouts

Version 4.5 of **@clerk/nextjs** brings sweeping improvements to server-side authentication in Next.js.

Get started with `npm i @clerk/nextjs@latest`

## Authentication moves to middleware

Going forward, developers will authenticate requests once in [Next.js middleware](https://nextjs.org/docs/advanced-features/middleware), then simply read the authentication state in endpoints (API routes and getServerSideProps).

**middleware.js example:**

```javascript
import { withClerkMiddleware } from '@clerk/nextjs/server'

export default withClerkMiddleware((req) => {
  // Your own middleware
})
```

**API routes example:**

```javascript
import { getAuth } from '@clerk/nextjs/server'

export default function handler(req, res) {
  const { userId } = getAuth(req)
  // ...
}
```

**getServerSideProps example:**

```javascript
import { getAuth } from '@clerk/nextjs/server'

export const getServerSideProps = ({ req }) => {
  const { userId } = getAuth(req)
  // ...
}
```

With this change, [authentication in Next.js](/nextjs-authentication) will finally feel familiar for developers who have worked with frameworks like Express or Ruby on Rails, where authentication is normally handled within middleware.

## Switchable runtime support

Next.js 12.2 brought a switchable runtime, so developers could choose between a node runtime or an edge runtime for each of their API routes and server-rendered pages.

Our new **getAuth()** helper is isomorphic, so it works regardless of the runtime you choose.

## Improved developer experience

If you've used Clerk in the past, you'll notice three small but delightful improvements to our developer experience:

1. All server-side imports are now from **@clerk/nextjs/server** instead of having import paths specific to the endpoint-type
2. Wrapper functions are no longer required inside endpoints, only once in middleware
3. **getAuth(req)** works everywhere there's a request object

```javascript {{ title: '@clerk/nextjs v4.5', prettier: false }}
// pages/api/foo.js
import { getAuth } from '@clerk/nextjs/server'

export default function handler(req, res) {
  const { userId } = getAuth(req)
  // ...
}


// pages/bar.js
import { getAuth } from '@clerk/nextjs/server'

export const getServerSideProps = ({ req }) => {
  const { userId } = getAuth(req)
  // ...
}


// middleware.js
import { withClerkMiddleware, getAuth } from '@clerk/nextjs/server'

export default withClerkMiddleware((req) => {
  const { userId } = getAuth(req)
  // ...
})
```

```javascript {{ title: 'Previous' }}
// pages/api/foo.js
import { withAuth } from '@clerk/nextjs/api'

export default withAuth((req, res) => {
  const { userId } = req.auth
  // ...
})

// pages/bar.js
import { withServerSideAuth } from '@clerk/nextjs/ssr'

export const getServerSideProps = withServerSideAuth(({ req }) => {
  const { userId } = req.auth
  // ...
})

// middleware.js
// Clerk hasn't supported Next.js 12.2+ middleware until today
```

## Preparation for Layouts

Our team has been watching the [Next.js Layouts RFC](https://nextjs.org/blog/layouts-rfc) closely, and we designed the new helpers in anticipation of layouts support.

We expect that by computing the authentication state in middleware, we'll be able to share it with each of your parallel-loading layout files.

## Get started

Get started right away with our [guide to Next.js authentication](/docs/quickstarts/get-started-with-nextjs), or [join our community Discord](https://clerk.com/discord) to discuss with our team.

Thanks to the contributors: Mark Pitsilos, Nikos Douvlis

---

# Refactoring Stripe's API for frontend access
URL: https://clerk.com/blog/refactoring-stripes-api-for-frontend-access.md
Date: 2022-06-10
Category: Engineering
Description: We built `use-stripe-subscription` to make it easier for React developers to implement Stripe Billing

Today we launched [`use-stripe-subscription`](https://github.com/clerkinc/use-stripe-subscription), a package that makes it easier for frontend developers to implement Stripe billing. It features:

- `useSubscription()` - a React hook that returns:
  - `products` - an array of Product objects available for subscription
  - `redirectToCheckout()` - Redirects to Stripe Checkout to purchase a subscription to one of the `products`
  - `subscription` - the current customer’s active Subscription object, if it exists
  - `redirectToCustomerPortal()` - Redirects to Stripe Billing’s Customer Portal so the customer can manage their subscription
- `<Gate>` - a component that selectively renders children based on the customer’s subscription

`use-stripe-subscription` is open-source and was built to work with any authentication and user management solution, not just Clerk.

## Why did Clerk build this?

Clerk is a Customer Identity *Platform.* We don’t just handle authentication, we also make it easier to sync and leverage customer identity with developers’ favorite tools.

`use-stripe-subscription` leverages customer identity to add a new authorization layer to Stripe’s API. By default, Stripe’s API is only designed for backend access, since it relies on a secret key for authorization that cannot be exposed to the frontend.

We added a per-customer authorization layer, which allows frontend developers to securely retrieve subscription information about the signed-in customer, without exposing the secret key to the frontend.

This sounds fancier than it is: most teams using Stripe are effectively building this in-house. We just packaged the solution to save in-house teams from reinventing the wheel.

## Securing Stripe’s API for frontend access

To secure an API for frontend access, developers can refer to one, simple question:

> *What actions can a signed-in user perform on their own?*

Frontend APIs should be designed to power self-serve user interfaces. If the API is granted broader permissions, then a malicious actor may make unauthorized requests.

Luckily, Stripe’s API contains two objects that `use-stripe-subscription` leverages to determine which actions a user can perform on their own.

### The Customer object

In Stripe, every Subscription object belongs to a Customer object. The Customer object can represent an individual or a business.

As a long as an API can map the signed-in user to their Customer object, it’s trivial to restrict endpoints

- If a user *does not* have a Subscription, allow them to initialize a Checkout Session with their Customer ID to begin a new subscription
- If a user *does* have a Subscription, allow them to read the object, and to start a Customer Portal session to manage the subscription

### The Customer Portal Configuration object

Allowing users to start a Checkout Session from the frontend might sound unsafe – how can the API know which products a user is allowed to purchase on their own?

For this, we leverage Stripe’s Customer Portal product, which requires developers to specify which subscriptions a customer can switch between on their own:

![Refactoring Stripes Api For Frontend Access setup guide](./28f3676c57c3089778598df7cb781aa66675edb3-1764x948.png)

*Stripe’s Customer Portal settings page requires developers to configure which products a customer can switch between on their own*

Before `use-stripe-subscription` creates a Checkout Session, it verifies that the product is listed in the Customer Portal Configuration object. We assume that, if the configuration shows a customer is able to switch to a product, they should also be allowed to purchase that product new.

To make things easy for developers, the list of available subscription products is always accessible in the `products` attribute of the `useSubscription()` hook. This list is derived directly from the Customer Portal Configuration object.

## Passing in the Stripe Customer ID

To configure `use-stripe-subscription`, developers must create an endpoint on their server that communicates with Stripe’s API. The endpoint is responsible for retrieving the product list and current subscription information, as well as for generating Checkout and the Customer Portal sessions.

The package provides a complete Javascript implementation for this endpoint, except that developers must build their own function to determine the Stripe Customer ID associated with the request.

```javascript
import { subscriptionHandler } from 'use-stripe-subscription'

const handler = async (req, res) => {
  // Build your own findOrCreateCustomerId
  const customerId = await findOrCreateCustomerId(req)

  res.json(await subscriptionHandler({ customerId, query: req.query, body: req.body }))
}
```

This implementation is ideal because it works for both B2C and B2B subscription companies. The package doesn’t know (and therefore, is not opinionated about) whether the user is operating on behalf of a personal Customer object, or on behalf of a business’s Customer object.

## What about webhooks?

We know that frontend developers prefer to avoid webhooks, so `use-stripe-subscription` does not require them. Instead, it makes just-in-time API requests to Stripe to ensure it always has the latest data.

For very high-traffic websites, this strategy unfortunately has the potential to run into to Stripe’s API rate limit (100 read operations per second).

From our perspective, it’s quite unfortunate that Stripe asks developers to configure webhooks and setup a cache just to have access to updated data. It’s much simpler to query data directly from Stripe as it’s needed.

To alleviate this limitation, we investigating ways to add a robust caching solution to the package. Discussions and PRs toward this end are very much appreciated.

---

# Three best practices for building React REST SDKs
URL: https://clerk.com/blog/best-practices-for-building-react-rest-sdks.md
Date: 2022-05-20
Category: Engineering
Description: For optimal developer experience, React SDKs require completely different patterns than Node

## 1. No secret keys allowed

This may be obvious but it must be stated as #1. Since React hooks run in the browser, SDKs cannot use secret keys for API access.

Instead, the API should be designed to scope access based on the currently signed-in user. Then, a session token or a JWT can be used to authorize requests to the API.

## 2. GETs should be Hooks

This is the critical change that turns a Node SDK into a React SDK. In Node SDKs, GET methods usually return a Promise:

```jsx
import { getUser } from '@clerk/nextjs'

const user = await getUser()
```

Unfortunately, using a Promise in a React Component is a big headache. The developer needs to add `useEffect` and `useState` hooks to render a loading state while the Promise is pending, then update when the resolves.

The end result is quite verbose and hard to decipher:

```jsx
import { useEffect, useState } from 'react'
import { getUser } from '@clerk/nextjs'

const UserProfile = () => {
  const [user, setUser] = useState(null)
  useEffect(() => {
    const load = async () => {
      const res = await getUser()
      setUser(res)
    }
    load()
  }, [getUser, setData])
  if (!user) {
    return <div>Loading</div>
  }
  return <div>Name: {user.name}</div>
}
```

The solution is to provide developers with a hook instead of a Promise. Hooks are composable, so under the hood this is still built with `useEffect` and `useState`, it just doesn't burden the developer with setting them up manually:

```jsx
import { useUser } from '@clerk/nextjs'

const UserProfile = () => {
  const { user } = useUser()
  if (!user) {
    return <div>Loading</div>
  }
  return <div>Name: {user.name}</div>
}
```

That's much easier to use!

## 3. Hooks should "react" to mutations

There is still a problem in the example above. What if the user wants to change their name and the developer triggers an update:

```jsx
user.update({ name: 'Ben Bitdiddle' })
```

By default, the `useUser` hook in our `<UserProfile/>` component won't automatically refresh. But since it's a hook, developers will expect it to – that's the whole point of React!

There are two high-level strategies to refreshing the hook, **eager refresh** and **sequential refresh**.

### Eager refresh

Eager refresh is the most performant solution, but it can be hard to configure. The idea is that the API endpoint behind `user.update()` should return the updated User object in its response body. When the response is received, `user.update()` can propogate the new value to any components calling `useUser()`.

This example isn't particularly hard to configure because the mutation is contained to the `User` object. It can be achieved with a globally-scoped React context to store the value of the User object, instead of using `useState` directly in the `useUser` hook.

Eager refresh is much harder to configure when there are side effects involved. For example, at Clerk we have a `SignIn` object that is responsible for tracking the state of a sign-in flow while the user completes their first and second factor. Once the user successfully signs in, it has the side effect of generating a `Session` object, which changes the application's state from signed-out to signed-in.

We achieve eager refresh when a sign in completes by returning both the `SignIn` object and `Session` object from the server, but establishing a clean pattern for this has proven easier-said-than-done.

### Sequential refresh

The alternative to eager refresh is sequential refresh, which is less performant but can be easier to configure, especially when side effects are possible.

Using our example above, instead of trying to return both `SignIn` and the new `Session` at once, the final `SignIn` endpoint can instead return only the `SignIn` resource.

When the client sees that the `SignIn` is complete, though, it knows that a new `Session` must exist. So, it can trigger a second request to retrieve the new `Session`.

Two round-trips to the server will inherently be slower than one, but the development burden of eager refresh may make sequential refresh a viable alternative – especially as edge compute has made round-trips less costly over time.

---

# Next.js SSR authentication with Clerk
URL: https://clerk.com/blog/next-js-ssr-authentication-with-clerk.md
Date: 2022-05-07
Category: Engineering
Description: Next.js SSR authentication is easy with Clerk – just a few lines of code to get started.

## What is Server-Side Rendering (SSR) for React?

\*\*\
Update (11/2/2023):\*\* The code examples shown in this post have been deprecated. For the most up-to-date code examples on how to use Clerk with Next.js SSR, [read the documentation](/docs/references/nextjs/read-session-data#pages-router). Additionally we have a [new blog](/blog/nextjs-auth-clerk-streamlined-ssr-efficiency).

*Updated: 25/08/2022*

React was originally built to run on the client. Once React started, hooks would run to load data, and eventually a full page would be generated.

But since React is just a Javascript library, there was no reason it couldn't run on a server, too. **Server-side rendering** (SSR) runs React on the server to generate a page's initial HTML (a.k.a the first *render*), then runs React again on the client to provide reactivity.

Server-side rendering is particularly helpful for pages that must be indexed in search engines, since search engines cannot index pages that are rendered client-side.

The bigger benefit, though, is that server-side render can reduce the complexity of an application and lead to fewer lines of code. This is especially true in the modern era, where frameworks like Next.js provide helpers that drastically reduce the setup time for SSR.

### How to use SSR with Next.js?

Server-side rendering can be used by including `export async function getServerSideProps()` on any pages you need SSR. Below is an example of how a page would look when using SSR:

```jsx
function Page({ data }) {
  // use the data on our page
  ;<div>{data.content}</div>
}

export async function getServerSideProps() {
  // Fetch data from an API
  const res = await fetch(`https://api.example.com/data`)
  const data = await res.json()

  // Pass data to the page via props
  return { props: { data } }
}

export default Page
```

This example retrieves some data from api.example.com. Then, we pass the data to the UI using the return statement. Finally, in the UI, we present the data to the user.

*You can read more about Server-side rendering in the [Next.js SSR documentation](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props).*

Now that you have a basic understanding of how SSR works, let us investigate how Clerk and SSR can work together.

## How to use Clerk with SSR?

Clerk allows you to verify a user is authenticated and to retrieve user profile data when using SSR. Below, we will cover how to implement both.

### Securing pages with SSR

With Clerk and Next.js SSR, we can check if the user is authenticated and, if not, redirect them to the sign-in page without rendering anything on the client. Clerk provides a helper called `withServerSideAuth`, which allows you to access authentication information:

```jsx
import { withServerSideAuth } from '@clerk/nextjs/ssr'

export const getServerSideProps = withServerSideAuth(({ req, resolvedUrl }) => {
  const { sessionId } = req.auth

  if (!sessionId) {
    return { redirect: { destination: '/sign-in?redirect_url=' + resolvedUrl } }
  }

  return { props: {} }
})
```

The snippet above checks to see if there is a session. If not, it will redirect the user to the sign-in page. Once the user has successfully authenticated, Clerk will redirect the user back to the page they were initially trying to access. Here is a quick GIF showing the process in action.

![Next Js Ssr Authentication With Clerk guide illustration](./5db59e3e9f8e6c84c2ff95e84b0c21439ceeea8c-2560x1440.png)

*If you want to see it in action, check out this [fully functional example](https://replit.com/@perkinsjr/Clerk-SSR-Auth-Example) that contains all the code you need for SSR authentication with a redirect back.*

### Retrieving userId or JWT templates

Server-side rendering gives you the opportunity to retrieve data from 3rd party APIs and your own database. When using Clerk, you have the option of retrieving the user ID, or if you are using a Clerk integration such as Hasura you can also retrieve the JWT ready for use.

Below is an example of retrieving a Hasura JWT token ready to retrieve data before sending the page to the user.

```jsx
import { withServerSideAuth } from '@clerk/nextjs/ssr'

export const getServerSideProps = withServerSideAuth(async ({ req }) => {
  const { sessionId, getToken } = req.auth

  if (!sessionId) {
    return { redirect: { destination: '/sign-in?redirect_url=' + resolvedUrl } }
  }
  // use a token for your Clerk integrations
  const hasuraToken = await getToken({ template: 'hasura' })

  // retrieve data from your Hasura integration

  return { props: {} }
})
```

If you aren’t using a JWT template or a Clerk integration you can just retrieve the userId and use that against your own database.

```jsx
import { withServerSideAuth } from '@clerk/nextjs/ssr'

export const getServerSideProps = withServerSideAuth(async ({ req }) => {
  const { sessionId, userId } = req.auth

  if (!sessionId) {
    return { redirect: { destination: '/sign-in?redirect_url=' + resolvedUrl } }
  }

  // use the userId to retrieve your own data

  return { props: {} }
})
```

## Enabling Full SSR Mode

In some cases, you may need the full User object available to you. For example, if you need to retrieve the user’s primary email address

Clerk can use an additional network request to retrieve the full User object. To enable it, you will need to add `{ loadUser: true }` to your SSR request. Then, the complete User object will be available:

```jsx
import { withServerSideAuth } from '@clerk/nextjs/ssr'

export const getServerSideProps = withServerSideAuth(
  async ({ req, resolvedUrl }) => {
    const { sessionId, getToken, userId } = req.auth
    // retrieve the user object
    const { user } = req
    // return the users primary email address.
    const email = user.emailAddresses.find((email) => {
      return email.id === user.primaryEmailAddressId
    })

    // retrieve data using the email address.
    const data = getDataFromEmail(email)

    return { props: { data } }
  },
  { loadUser: true },
)
```

## **Ready to add auth to your app?**

Be sure to visit our [Next.js authentication with Clerk page](/nextjs-authentication) today to better understand how you can add authentication in minutes - not weeks.

Want to connect with other developers? Join our [Discord community](https://clerk.com/discord) or follow [@clerk on X](https://x.com/clerk) to stay up to date with the latest features, improvements, and sneak peeks to Clerk.

---

# How to skip CORS preflights and speed up your API with polyfills
URL: https://clerk.com/blog/skip-cors-options-preflight.md
Date: 2022-04-29
Category: Engineering
Description: CORS preflights add unnecessary latency to requests. Learn to use "simple" requests to skip the preflight entirely.

At Clerk, we have an API that is directly accessible from the frontend (we call it the Frontend API). It exclusively handles cross-origin requests, but none of those requests trigger a CORS preflight.

This is by design. CORS preflights do not add security for modern applications and they add an extra network round-trip, so we made sure that every API request is considered a "simple request."

## What do you mean CORS preflights do not add security?

It's a common misconception that CORS preflight requests add security to modern applications. Why else would they exist?

Surprisingly, CORS preflights exist to protect old applications, not new ones.

Specifically, the CORS designers were concerned about old applications that incorrectly assumed that browsers would never allow request methods besides GET or POST, or would never allow custom HTTP headers.

When browsers added the capability to send alternative request methods and custom headers via `fetch` (and its older sibling, `XMLHttpRequest`), suddenly applications that made this assumption were at risk.

To mitigate the risk to old applications, an extra "preflight" request was added to requests with PATCH, PUT, DELETE methods, and to requests with custom headers. The idea is that, if those applications fail to respond to the preflight in a very specific way, then the actual request will never be dispatched.

It's dirty and it adds latency, but it works.

The annoying part is: modern applications that anticipate PATCH, PUT, DELETE requests and custom headers don't gain any security from CORS preflights, it's just extra latency they need to incur to protect legacy applications. In 2022, it's like robbing Peter to pay an exceptionally stubborn Paul who won't update their decades old codebase, but we digress...

## How can CORS preflights be skipped?

Certain cross-origin requests are classified as "simple requests" and do not require a successful preflight before being dispatched.

Based on the section above, it might be easy to guess which requests qualify as simple: GET or POST requests without custom headers. *(Note: This is a slight simplification, the full details are [available on MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).)*

To build an API that doesn't trigger preflights, we need to design polyfills for modern request methods and custom headers.

### One critical point first

The polyfills below assume you have configured your CORS middleware to outright reject requests that should not be processed.

As an example, consider CORS middleware running on `api.example.com` that is configured to allow the Origin of `https://www.example.com`.

Now, consider a request comes in with the Origin of `https://randomattacker.com`

Does your CORS middleware reject this request, or does it allow the request to be processed?

**It depends on your middleware.**

Some middleware might simply add an access-control header (below), then allow the request to continue:

```text
Access-Control-Allow-Origin: https://www.example.com
```

This header doesn't stop the request from being processed, but it does stop the browser from reading your server's response.

**This is not the behavior you want.**

Instead, you want your middleware compare the received Origin to the allowed Origin, and immediately cancel the request if they don't match.

**The only way to confirm your middleware's behavior is to write your own tests.** Clerk needed to write our own middleware to reject requests with undesirable CORS options (origin, credentials, etc).

### Polyfilling request methods

Polyfilling the request method is trivial - and we were fortunate to have inspiration [from Ruby on Rails](https://guides.rubyonrails.org/form_helpers.html#how-do-forms-with-patch-put-or-delete-methods-work-questionmark). Every mutation request to our frontend API is dispatched as a POST, but the method can be overridden using a query string like `?_method=PATCH`. In our backend, we run middleware to ensure that the request is treated as a PATCH when this query string is present.

### Polyfilling custom headers

Custom headers can be more challenging to polyfill. It really depends on what type of content you're putting in the header:

- If the header *does not* contain sensitive information, the polyfill can use the same query string approach used above for request methods
- If the header *does* contain sensitive information, the polyfill should be handled within the the request body

Typically, developers want to customize two headers:

1. **Content-Type:** To set it to **application/json**. This is not sensitive and can be polyfilled using the query string.
2. **Authorization:** To include an access token. This is sensitive and should not be polyfilled using the query string.

It's important that sensitive information is not added to the query string because the request path is often logged to tools like bug trackers and analytics software. To obscure this information from those tools, it's better to add the field to the request body. In the case of the Authorization header, an extra form value or JSON attribute will suffice.

## That's everything!

These simple changes will eliminate CORS preflight requests from a frontend talking to a frontend API. In the process, it eliminates a round trip, which can easily take over 100ms if your user is geographically far from your server. Even in the best case of edge computing, this strategy will likely shave off \~20ms from your overall response time.

For the modern web, every millisecond counts!

---

# It's the little things: Three developer experience delights of our Remix authentication package
URL: https://clerk.com/blog/remix-delightful-developer-experiences.md
Date: 2022-04-23
Category: Engineering
Description: We integrate with a lot of React frameworks - here's what we love most about our Remix authentication package

Clerk is building authentication for the **modern web**. That means we don't just offer SDKs for different programming languages (Javascript, Ruby, Go), we offer SDKs for each modern React framework, too. We're proud to have first-class support for Next.js, Redwood, Gatsby, Expo, and – of course – Remix.

For every framework, we challenge ourselves to make Clerk's installation and usage as straightforward as possible. In this post, we highlight two developer experiences of [our Remix authentication package](/solutions/remix-authentication) that we absolutely love.

## 1. getAuth(request)

When handling a server-side request, there's only two theoretical ways developers can retrieve authentication data from Clerk.

First, with a wrapper function like `withAuth()`:

```javascript
const handler = withAuth(async (request) => {
  // withAuth adds the `auth` property to request
  const { auth } = request
})
```

Second, with a direct accessor like `getAuth()`:

```javascript
const handler = async (request) => {
  const auth = await getAuth(request)
}
```

Call us crazy, but we like `getAuth(request)` better. It feels more natural to access the data "just-in-time" instead of configuring it as a wrapper.

Fortunately, Remix enables us to provide this developer experience. After some upfront [configuration in root.tsx](/docs/get-started/remix#initialize-clerk-in-app-root-tsx), developers can use [`getAuth()` in the loaders and actions](/docs/get-started/remix#loaders-and-actions) of any route. It's really easy!

## 2. Splats ($.tsx)

We like to say splats are money.

Name a route $.tsx and it will serve all sub-routes. Clerk relies on this wildcard functionality when developers [mount our components directly in their application](/docs/get-started/remix#using-clerk-components).

Specifically, when a developer mounts `<SignIn/>` on the **/sign-in** route, we actually mount several sub-paths:

- **/sign-in** - to start the process
- **/sign-in/factor-one** - to verify the first factor
- **/sign-in/factor-two** - to verify the second factor
- **/sign-in/verify** - to handle [magic links](/blog/magic-links) clicked in an email

These subpaths are nice because it helps us handle the refresh button. If a user is entering the second factor and they click the refresh button, we don't want them to lose their progress. Storing some state in the URL bar helps us provide the best possible user experience.

We love splats because their fun, intuitive, and easy. Next.js calls the same concept "Optional Catch-all Routes" and has the syntax **/\[\[...slug]].tsx**, which we find a little cumbersome in comparison.

## 3. Edge-by-default

We'd be remiss if we didn't include that Remix runs on the edge by default.

In this case, it's really the absence of code we're showing off. There is no "adding" edge support, it all just works.

This is great because Clerk is optimized for the edge. We include [stateless authentication with JWTs](/features/session-management) in every plan, which are perfect for edge-based applications where georgraphy-bound network requests should be avoided. (Don't worry, our JWTs expire every minute so sessions are still revocable!)

The edge is the future, and we're thankful Remix's defaults will help speed up adoption and the web.

---

# Unicorn or Chameleon? Two strategies for exporting customizable React components
URL: https://clerk.com/blog/exporting-customizable-react-components.md
Date: 2022-04-15
Category: Engineering
Description: React Components are the future of APIs – but how can developer tools companies enable robust customization? We explore two strategies.

Clerk's React library exports [`<SignUp/>`](/components/sign-up), [`<SignIn/>`](/components/sign-in), and [`<UserProfile/>`](/components/user-profile) components. They come styled and fully-featured so developers can focus on building their application:

![Exporting Customizable React Components guide illustration](./3faabd62184abfaa71b1a810d56f82596e3d93ac-2000x1016.png)

Unsurprisingly, this leads to the question: *How can I customize the components to match my brand?*

Whitelabeling software is a famously hard and unsolved problem - it's extremely common to find widgets or portions of websites that have completely different styling.

One example is this chat widget from Alaska Airlines, which shows different form field styling (rounded vs square), different buttons (huge text, not capitalized), and a different font (Arial vs Circular).

![Exporting Customizable React Components guide illustration](./63848098c405f0be95f8a961520e83c4be036f83-2880x1596.png)

This quarter at Clerk, we're revisiting our customization strategy. We want to truly solve this problem with perfect matching styles instead of just "close enough" styles. Internally, we say we're switching from a "unicorn" strategy to a "chameleon" strategy.

While we haven't finalized the chameleon strategy yet, we do have a proof of concept running and are excited about the developer experience it produces.

## Unicorn strategy

![Exporting Customizable React Components guide illustration](./3b751ff2967063abbbfe2320254217991a362204-656x350.png)

Our initial approach to theming is a "unicorn" strategy because we came up with the system ourselves – developers have to learn our specific way of applying styles.

We drew inspiration from others, so you've probably seen something like it before. Developers simply pass a `theme` prop to `<ClerkProvider>` to customize aspects of the design:

```json
{
  "general": {
    "color": "#f1f1f1",
    "backgroundColor": "#f2f2f2",
    "fontColor": "#f3f3f3",
    "fontFamily": "Inter, sans serif",
    "labelFontWeight": "500",
    "padding": "1em",
    "borderRadius": "20px",
    "boxShadow": "0 2px 8px rgba(0, 0, 0, 0.2)"
  },
  "buttons": {
    "fontColor": "#f4f4f4",
    "fontFamily": "Inter, sans serif",
    "fontWeight": "300"
  }
}
```

While this system is great for quickly getting close styles, it suffers in the last mile. There simply aren't enough options to provide developers with the complete customization capabilities they desire.

## Chameleon strategy

![Exporting Customizable React Components guide illustration](./bde3d2490d7628fb2febd01d27101894bfae501c-1000x680.png)

Our next iteration approaches customization with a new mindset. Instead of asking developers to learn our strategy, we will integrate with any strategy they already use.

If you've been around the frontend ecosystem for a while, you know there are *several, very popular* styling systems that all work *completely differently.* Because they're so diverse and we want to blend in with all of them, we call this a "chameleon" strategy.

Let's work through an example to explain how it works.

Consider that one of our components has a "primary button." By default, that button renders to this HTML:

```html
<button class="clerk-button-primary">Action</button>
```

*Note: in this post, we're only focused on styles. We'll discuss customizing the "Action" string in the future.*

To change the style of this button, developers will still pass a `theme` prop, but now the selector will be for this specific element:

```jsx
<SignIn
  theme={{
    primaryButton: customButton,
  }}
/>
```

In this snippet, `customButton` can have one of three values:

1. A string with one or many class names. If passed, the value will replace the default `clerk-button-primary` class.
2. A React component that renders a `<button>` and forwards all props (including children). If passed, the default element will not be rendered at all, and instead the passed component will be rendered.
3. A dictionary that adheres to the `CSSStyleInterface` type. This is for completeness more than anything else. If passed, the value will be forwarded to the `style` prop, and the the default `clerk-button-primary` class will be omitted.

Now, let's see how it works for different styling libraries.

### Tailwind

Simply pass in Tailwind classes as a string:

```jsx
<SignIn
  theme={{
    primaryButton: 'p-4 rounded',
  }}
/>
```

### CSS modules

When a CSS module is imported, the object automatically returns class names. Simply pass it in:

```jsx
import styles from './Styles.css'
;<SignIn
  theme={{
    primaryButton: styles.customButton,
  }}
/>
```

### styled-components

styled-components works by returning a React component that automatically forwards props to a `<button>` element – exactly as specified by Clerk:

```jsx {{ prettier: false }}
const CustomButton = styled.button`
  border-radius: 1rem;
  padding: 1rem;
`

<SignIn
  theme={{
    primaryButton: CustomButton
  }}
/>
```

### Chakra

Chakra also provides React components, but they are modified with props, which makes the setup slightly more complex, but still quite simple:

```jsx
<SignIn
  theme={{
    primaryButton: (props) => <Button size="lg" {...props} />,
  }}
/>
```

Since the chameleon strategy ultimately hooks into HTML and React primitives, we're confident that we can make *every* styling library work with this strategy, not just the four we've listed above.

Thoughts, comments, questions? We're eager for your feedback! Please reach out to [@clerk on X](https://x.com/clerk) or [contact support](https://clerk.com/contact/support).

---

# Introducing Web3 Authentication
URL: https://clerk.com/blog/introducing-web3-authentication.md
Date: 2022-01-21
Category: Engineering
Description: Clerk is saving Web3 developers from the greatest evils of the Web2 platform: cookies, multifactor authentication, and profile enrichment

Clerk is launching our first Web3 authentication factor - Sign in with Metamask!

![Introducing Web3 Authentication guide illustration](./adca3d5c16282cbf8af17d8664bd4bb82d2ece4a-1040x452.png)

This launch is the result of dozens of developer interviews, focused on understanding if and how Clerk can contribute to the Web3 ecosystem.

It didn't take long before we discovered three common challenges that we can help Web3 developers with immediately: securing sessions, multifactor authentication, and profile enrichment.

## Securing Sessions

First and foremost - we found a near ubiquitous challenge around securing sessions. It's a two-part problem:

1. How do you verify a user is owns of a Web3 account?
2. How do you safely create a session to persist the users account information?

### Verifying the owner of a Web3 account

It's easy to *insecurely* determine the Web3 account address of a user visiting your website with Metamask connected, just run the following Javascript:

```javascript
await ethereum.request({ method: 'eth_accounts' })
```

Verifying that the returned address is accurate, however, is significantly more challenging. Developers must ask users to sign a transaction, which is a process that undergone several protocol revisions and is hard to keep up with.

This is where Clerk steps in - all the work of signing a transaction and verifying the signature is abstracted away, and wrapped in a `<SignInWithMetamask/>` button.

### Persisting a session

Let's be honest - persisting a session isn't a Web3 challenge at all, but it is one that Web3 developers must endure by virtue of operating in Web2 browsers.

We know Web3 developers don't want to think about things like httpOnly cookies, XSS attacks, and session revocation. Web2 developers don't either, and that's why built-in [session management](/features/session-management) is the foundation of every authentication product at Clerk. We use stateless JWTs that enable authentication in under 1 millisecond, and revocation in under 1 minute. We follow all the best practices so you can focus on building your application.

## Multifactor authentication

Sign in with Metamask uses the same abstraction as our other authentication factors like passwords or [magic links](/blog/magic-links).

Because of this, Clerk's [multifactor authentication](/features/multifactor-authentication) works with Metamask users out-of-the-box. Users simply need to navigate to their user profile and opt-in to multifactor authentication. There's no extra work for the developer beyond mounting a [`<UserProfile/>`](/docs/components/user/user-profile) component, or redirecting to the Clerk-hosted component.

## Profile enrichment

Off-chain profile enrichment is a topic of much debate in the Web3 community. Ideally, data like email addresses and phone numbers could be retrieved on-chain following the principles of [self sovereign identity](https://en.wikipedia.org/wiki/Self-sovereign_identity).

But as of today, there are no standard protocols for retrieving this data. As a result, top Web3 companies like OpenSea still collect and verify email addresses off-chain.

Clerk enables developers to easily do the same. We provide simple helpers for collecting and verifying phone numbers, email addresses, and even OAuth accounts. Beyond that, we accept structured data likes names and profile photos, as well as provide a generic metadata field for bespoke profile enrichment.

In the future, we look forward to enriching profiles in a more decentralized manner. Today, we hope this mechanism can help bridge the gap from Web2 to Web3.

## Try it out!

[Try out our guide for installing Web3 authentication.](/docs/users/web3-wallets) The guide will get you started with a new Next.js application with Metamask authentication.

## Future roadmap

This launch is the first of many upcoming Web3 launches. Our rough roadmap ahead includes:

- **Sign in with Ethereum** - we know that Metamask alone is a little limiting and will add generic Ethereum support soon
- **Authorization via Token Gating** - In the Web2 realm, our team is actively building authorization via Roles and Permissions. We see many corollaries to Web3 authorization via token gating are approaching the primitives in a way that will support both.
- **Multi-chain support** - Because we fully anticipate a multi-chain future

Need something we didn't mention? Please reach out through any of our [support channels](https://clerk.com/contact/support) - we're still defining this roadmap and very interested to hear how we can better meet your needs.