# Clerk Changelog — Page 29

# Clerk Expo v2
URL: https://clerk.com/changelog/2024-07-26-clerk-expo-v2.md
Date: 2024-07-26
Category: SDK
Description: Introducing Clerk Expo SDK v2 with support for Expo Web

We are excited to announce that we have released `@clerk/clerk-expo` v2 with support for Expo Web! This means that you can create universal apps that run on Android, iOS, and the web all with a single codebase!

## Getting started

If you haven't already created an Expo app with Clerk you can follow the [Expo quickstart guide](/docs/quickstarts/expo).

Otherwise, you can update your existing Expo app to the latest version of `@clerk/clerk-expo` by following the [upgrade guide](/docs/upgrade-guides/expo-v2/upgrade).

## Use Clerk's prebuilt components on the web

Adding a sign-in page to your web app is now as easy as adding a [single component](/docs/components/overview):

```tsx filename="/app/sign-in.web.tsx"
import { SignIn } from '@clerk/clerk-expo/web'

export default function Page() {
  return <SignIn />
}
```

## Build universal authentication flows from one codebase

Leverage our hooks to build universal sign-in and sign-up views for Android, iOS, and web all from one codebase 🤯.

Here's an example of a OAuth sign-in flow, using the SDK's `useOAuth` hook:

```tsx {{ title: '/app/sign-in-oauth.tsx', collapsible: true }}
import React from 'react'
import * as WebBrowser from 'expo-web-browser'
import { Text, View, Button } from 'react-native'
import { Link } from 'expo-router'
import { useOAuth } from '@clerk/clerk-expo'
import * as Linking from 'expo-linking'

export const useWarmUpBrowser = () => {
  React.useEffect(() => {
    void WebBrowser.warmUpAsync()
    return () => {
      void WebBrowser.coolDownAsync()
    }
  }, [])
}

const SignInWithOAuth = () => {
  useWarmUpBrowser()

  const { startOAuthFlow } = useOAuth({ strategy: 'oauth_google' })

  const onPress = React.useCallback(async () => {
    try {
      const { createdSessionId, signIn, signUp, setActive } = await startOAuthFlow({
        redirectUrl: Linking.createURL('/'),
      })

      if (createdSessionId) {
        setActive!({ session: createdSessionId })
      } else {
        // Use signIn or signUp for next steps such as MFA
      }
    } catch (err) {
      console.error('OAuth error', err)
    }
  }, [])

  return (
    <View>
      <Link href="/">
        <Text>Home</Text>
      </Link>
      <Button title="Sign in with Google" onPress={onPress} />
    </View>
  )
}
export default SignInWithOAuth
```

Want to learn more about using Clerk with Expo? Check out [**@clerk/clerk-expo**](https://github.com/clerk/javascript/tree/main/packages/expo).

Excited specifically about Expo Web? Check out our [Expo Web support](/docs/references/expo/web-support/overview) guide.

---

# Passkeys are now Generally Available
URL: https://clerk.com/changelog/2024-07-24-passkeys-ga.md
Date: 2024-07-24
Category: GA
Description: Passkeys are now generally available for all Clerk users

After a thorough beta period, we're excited to announce that Passkeys are now generally available for all Clerk users. Passkeys are a simple-to-use and secure passwordless way to authenticate your users.

Passkeys are available as part of the Pro plan. Head to the [Clerk Dashboard](https://dashboard.clerk.com/last-active?path=user-authentication/email-phone-username) to activate Passkeys for your users or read through the [Passkeys documentation](/docs/authentication/configuration/sign-up-sign-in-options#passkeys) to get started.

---

# Improved support for Cypress testing
URL: https://clerk.com/changelog/2024-07-24-improved-cypress-support.md
Date: 2024-07-24
Category: E2E
Description: Enhanced end-to-end testing with Clerk using Cypress

We are thrilled to announce significant enhancements to our `@clerk/testing` package, making it easier to use Cypress with Clerk!

`@clerk/testing@1.2.0` includes the following improvements:

- **Full browser support**:  We have resolved existing issues with Cypress and now support all Cypress-supported browsers, including Chrome, Electron, and Firefox.
- **Testing Tokens**: The [testing tokens](/changelog/2024-04-24-testing-tokens) mechanism that was introduced in the Playwright integration is now available in Cypress as well. This feature allows you to bypass bot detection mechanisms effortlessly, eliminating frustrating "Bot traffic detected" errors and enabling uninterrupted testing workflows.
- **Cypress Custom Commands**: We've added custom Clerk commands that you can use inside your tests. These commands, like `cy.clerkSignIn()` and `cy.clerkSignOut()`, make it easy to handle sign-in and sign-out actions within your tests without interacting with the UI.

To learn more and get detailed setup instructions, visit our [Cypress documentation](/docs/testing/cypress).

---

# Official SDK for Astro
URL: https://clerk.com/changelog/2024-07-18-clerk-astro.md
Date: 2024-07-18
Category: SDK
Description: Our community SDK is all grown up 🧑‍🚀

[Astro](https://astro.build) is one of the most loved web frameworks for the past couple of years, it's a modern framework for fast content-driven websites, while also making it trivial to create dynamic web applications.

Today, we're proud to announce [`@clerk/astro`](/docs/quickstarts/astro), a new *official* SDK that allows developers to add authentication and authorization into their Astro application in matter of minutes.

The SDK comes fully equiped with Clerk's UI components, middleware, and low level utilities for your custom flows.

## Use Clerk UI components

Clerk's pre-built UI components give you a beautiful, fully-functional user and organization management experience in minutes. Here's an example on how to use the `<SignIn />` component in Astro.

```astro {{ title: 'src/pages/sign-in/[...signIn].astro' }}
---
import { SignIn } from '@clerk/astro/components'
---

<SignIn path="/sign-in" />
```

## Protect routes with Clerk Middleware

Use `clerkMiddleware` and the `auth` function to restrict logged out users from accessing the `/user` routes.

```tsx {{ title: 'src/middleware.ts' }}
import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server'

const isProtectedPage = createRouteMatcher(['/user(.*)'])

export const onRequest = clerkMiddleware((auth, context, next) => {
  if (isProtectedPage(context.request) && !auth().userId) {
    return auth().redirectToSignIn()
  }

  return next()
})
```

## Individual page protection

If the `/me` page is not protected by the middleware, you can still protect the page directly. The code below uses `Astro.locals.auth()` in order redirect the user the sign-in page or render their `userId`.

```astro {{ title: 'src/pages/me.astro' }}
---
const { userId, redirectToSignIn } = Astro.locals.auth()

if (!userId) {
  return redirectToSignIn()
}
---

<p>My user id is {userId}</p>
```

## Usage with React

Astro [offers a way](https://docs.astro.build/en/guides/integrations-guide/react) to use React inside your Astro application. `@clerk/astro` takes advantage of that and exposes components, hooks, and utilities for those cases.

```tsx {{ title: 'src/components/Header.tsx' }}
import { SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/astro/react'

export default function Header() {
  return (
    <>
      <p>My App</p>
      <SignedOut>
        <SignInButton />
      </SignedOut>
      <SignedIn>
        <UserButton />
      </SignedIn>
    </>
  )
}
```

This is only a quick preview of all that `@clerk/astro` offers.

For more information on the available API and how to get started building Astro applications with Clerk, check out our [Astro Quickstart guide](/docs/quickstarts/astro).

And last but not least, we would like to acknowledge and thank all of the contributors of the previous [community SDK for Astro](https://github.com/panteliselef/astro-with-clerk-auth), which was a great source of inspiration for us.

---

# Remix SPA mode
URL: https://clerk.com/changelog/2024-07-17-remix-spa-mode.md
Date: 2024-07-17
Category: SDK
Description: @clerk/remix now supports Remix SPA Mode

Starting with `@clerk/remix@4.2.0` our Remix SDK now supports [Remix SPA mode](https://remix.run/docs/en/main/guides/spa-mode). This means that you can now use Clerk in your Remix app without server-side rendering.

After creating a Remix app with SPA mode enabled, install the latest `@clerk/remix` package:

```bash {{ filename: 'terminal' }}
npm install @clerk/remix@latest
```

```bash {{ filename: 'terminal' }}
yarn add @clerk/remix@latest
```

```bash {{ filename: 'terminal' }}
pnpm add @clerk/remix@latest
```

You can then use `ClerkApp` inside your root route and use Clerk's [control components](/docs/components/overview) to protect your pages. Clerk will automatically detect that your Remix app is running in SPA mode and will take care of the rest.

To read the full guide and learn more about Clerk and Remix SPA Mode, head over to the [Remix SPA mode reference guide](/docs/references/remix/spa-mode).

---

# Next.js Dynamic Keys
URL: https://clerk.com/changelog/2024-07-16-dynamic-keys.md
Date: 2024-07-16
Category: SDK
Description: Keys and options passed to `clerkMiddleware()` at runtime are available in Clerk’s server-side helpers.

Users building a multi-tenant application might need to provide different Clerk keys depending on the incoming request. Previously, you would need to pass these keys to all of Clerk’s Next.js server-side helpers. With Dynamic Keys support, keys passed to [`clerkMiddleware()`](/docs/references/nextjs/clerk-middleware) are made available to [`auth()`](/docs/references/nextjs/auth#auth)  and other server-side helpers.

```typescript {{ title: 'middleware.ts' }}
import { clerkMiddleware } from '@clerk/nextjs/server'

export default clerkMiddleware({
  secretKey: '<YOUR_SECRET_KEY>',
  publishableKey: '<YOUR_PUBLISHABLE_KEY>',
  signInUrl: '/my-sign-in',
  signUpUrl: '/my-sign-up',
})

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

With a centralized place for passing server-side options, implementing a multi-tenant application that requires dynamic Clerk keys should be much more straightforward. This feature is available as of `@clerk/nextjs@5.2.x`.

Check out the [documentation](/docs/references/nextjs/clerk-middleware#dynamic-keys) for additional details and happy building!