Explore

Auth

Instant comes with support for auth. We currently offer magic codes and Google OAuth. If you want to build your own flow, you can use the Admin SDK.

Magic Codes

Instant supports a "magic-code" flow for auth. Users provide their email, we send them a login code on your behalf, and they authenticate with your app. Here's how you can do it with react.

'use client'

import React, { useState } from 'react'
import { init } from '@instantdb/react'

const APP_ID = 'REPLACE ME'

const db = init({ appId: APP_ID })

function App() {
  const { isLoading, user, error } = db.useAuth()
  if (isLoading) {
    return <div>Loading...</div>
  }
  if (error) {
    return <div>Uh oh! {error.message}</div>
  }
  if (user) {
    return <h1>Hello {user.email}!</h1>
  }
  return <Login />
}

function Login() {
  const [sentEmail, setSentEmail] = useState('')
  return (
    <div style={authStyles.container}>
      {!sentEmail ? (
        <Email setSentEmail={setSentEmail} />
      ) : (
        <MagicCode sentEmail={sentEmail} />
      )}
    </div>
  )
}

function Email({ setSentEmail }) {
  const [email, setEmail] = useState('')

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    if (!email) return
    setSentEmail(email)
    db.auth.sendMagicCode({ email }).catch((err) => {
      alert('Uh oh :' + err.body?.message)
      setSentEmail('')
    })
  }

  return (
    <form onSubmit={handleSubmit} style={authStyles.form}>
      <h2 style={{ color: '#333', marginBottom: '20px' }}>Let's log you in!</h2>
      <div>
        <input
          style={authStyles.input}
          placeholder="Enter your email"
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
      </div>
      <div>
        <button type="submit" style={authStyles.button}>
          Send Code
        </button>
      </div>
    </form>
  )
}

function MagicCode({ sentEmail }) {
  const [code, setCode] = useState('')

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    db.auth.signInWithMagicCode({ email: sentEmail, code }).catch((err) => {
      alert('Uh oh :' + err.body?.message)
      setCode('')
    })
  }

  return (
    <form onSubmit={handleSubmit} style={authStyles.form}>
      <h2 style={{ color: '#333', marginBottom: '20px' }}>
        Okay, we sent you an email! What was the code?
      </h2>
      <div>
        <input
          style={authStyles.input}
          type="text"
          placeholder="123456..."
          value={code}
          onChange={(e) => setCode(e.target.value)}
        />
      </div>
      <button type="submit" style={authStyles.button}>
        Verify
      </button>
    </form>
  )
}

const authStyles: Record<string, React.CSSProperties> = {
  container: {
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
    height: '100vh',
  },
  form: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    height: '100vh',
    fontFamily: 'Arial, sans-serif',
  },
  input: {
    padding: '10px',
    marginBottom: '15px',
    border: '1px solid #ddd',
    borderRadius: '5px',
    width: '300px',
  },
  button: {
    padding: '10px 20px',
    backgroundColor: '#007bff',
    color: 'white',
    border: 'none',
    borderRadius: '5px',
    cursor: 'pointer',
  },
}

export default App

This creates a Login component to handle our auth flow. Of note is auth.sendMagicCode and auth.signInWithMagicCode.

On successful validation, Instant's backend will return a user object with a refresh token. The client SDK will then restart the websocket connection with Instant's sync layer and provide the refresh token.

When doing useQuery or transact, the refresh token will be used to hydrate auth on the backend during permission checks.

On the client, useAuth will set isLoading to false and populate user -- huzzah!

useAuth

function App() {
  const { isLoading, user, error } = db.useAuth()
  if (isLoading) {
    return <div>Loading...</div>
  }
  if (error) {
    return <div>Uh oh! {error.message}</div>
  }
  if (user) {
    return <Main />
  }
  return <Login />
}

Use useAuth to fetch the current user. Here we guard against loading our Main component until a user is logged in

auth.sendMagicCode

db.auth.sendMagicCode({ email }).catch((err) => {
  alert('Uh oh :' + err.body?.message)
  setState({ ...state, sentEmail: '' })
})

Use auth.sendMagicCode to create a magic code on instant's backend and email a login code

auth.signInWithMagicCode

db.auth.signInWithMagicCode({ email: sentEmail, code }).catch((err) => {
  alert('Uh oh :' + err.body?.message)
  setState({ ...state, code: '' })
})

Use auth.signInWithMagicCode to validate codes with instant's backend.

auth.signOut

db.auth.signOut()

Use auth.signOut to sign out users. This will restart the websocket connection and clear out the current user refresh token.

Log in with Google

Instant supports logging in your users with their Google account. We support flows for Web and React Native. Follow the steps below to get started.

Step 1: Create an OAuth client for Google

Go to the Google Console.

Click "+ CREATE CREDENTIALS"

If you haven't already, configure your OAuth consent screen for External users. Once this is done, click "+ CREATE CREDENTIALS" again.

Select "OAuth client ID"

Select "Web application" as the application type.

Add https://api.instantdb.com/runtime/oauth/callback as an Authorized redirect URI.

Step 2: Register your OAuth client with Instant

Go to the Instant dashboard and select the Auth tab for your app.

Register a Google client and enter the client id and client secret from the OAuth client that you created.

Step 3: Register your website with Instant

In the Auth tab, add the url of the websites where you are using Instant to the Redirect Origins.

If you're creating a React Native app, add your app scheme as an "App scheme" type origin. Add exp:// if you're using expo in development.

The next sections will show you how to use your configured OAuth client with Instant.

Native button for Web

You can use Google's Sign in Button with Instant. You'll use db.auth.SignInWithIdToken to authenticate your user. The benefit of using Google's button is that you can display your app's name in the consent screen.

First, make sure that your website is in the list of "Authorized JavaScript origins" for your Google client on the Google console.

If you're testing from localhost, add both http://localhost and http://localhost:3000 on the Google console, replacing 3000 with the port you use.

If you're using React, the easiest way to include the signin button is through the @react-oauth/google package.

npm install @react-oauth/google

Include the button and use db.auth.signInWithIdToken to complete sign in:

import { GoogleOAuthProvider, GoogleLogin } from '@react-oauth/google'

// e.g. 89602129-cuf0j.apps.googleusercontent.com
const GOOGLE_CLIENT_ID = 'YOUR_GOOGLE_CLIENT_ID'

function LoginButton() {
  const [nonce] = useState(crypto.randomUUID())

  return (
    <GoogleOAuthProvider clientId={GOOGLE_CLIENT_ID}>
      <GoogleLogin
        nonce={nonce}
        onError={() => alert('Login failed')}
        onSuccess={({ credential }) => {
          db.auth
            .signInWithIdToken({
              // Use the name you created when you registered the client
              // on the Instant dashboad
              clientName: 'google-web',
              idToken: credential,
              // Make sure this is the same nonce you passed as a prop
              // to the GoogleLogin button
              nonce,
            })
            .catch((err) => {
              alert('Uh oh: ' + err.body?.message)
            })
        }}
      />
    </GoogleOAuthProvider>
  )
}

If you're not using React or prefer to embed the button yourself, refer to Google's docs on how to create the button and load their client library. When creating your button, make sure to set the data-ux_mode="popup". Your data-callback function should look like:

async function handleSignInWithGoogle(response) {
  await db.auth.signInWithIdToken({
    // Use the name you created when you registered the client
    // on the Instant dashboad
    clientName: 'google-web',
    idToken: response.credential,
    // make sure this is the same nonce you set in data-nonce
    nonce: 'YOUR_NONCE',
  })
}

Redirect flow for Web

If you don't want to use the google styled buttons, you can use the redirect flow instead.

Simply create an authorization URL via db.auth.createAuthorizationURL

const url = db.auth.createAuthorizationURL({
  // The name of the client you chose when you created it on the
  // Instant dashboard
  clientName: 'google-web',
  redirectURL: window.location.href,
})

And then use the url to create a link:

<a href={url}>Log in with Google</a>

When your users clicks on the link, they'll be redirected to Google to start the OAuth flow and then back to your site.

Instant will automatically log them in to your app when they are redirected.

You can also use this to create a button:

Webview flow on React Native

Instant comes with support for Expo's AuthSession library. If you haven't already, follow the AuthSession installation instructions from the Expo docs.

Next, add the following dependencies:

npx expo install expo-auth-session expo-crypto

Update your app.json with your scheme:

{
  "expo": {
    "scheme": "mycoolredirect"
  }
}

From the Auth tab on the Instant dashboard, add a redirect origin of type "App scheme". For development with expo add exp:// and your scheme, e.g. mycoolredirect://.

Now you're ready to add a login button to your expo app:

import { Button } from "react-native";
import { init } from "@instantdb/react-native";
import {
  makeRedirectUri,
  useAuthRequest,
  useAutoDiscovery,
} from "expo-auth-session";

const APP_ID = "YOUR_APP_ID";
const db = init({  appId: APP_ID });

function LoginButton() {
  const discovery = useAutoDiscovery(db.auth.issuerURI());
  const [request, _response, promptAsync] = useAuthRequest(
    {
      // The unique name you gave the OAuth client when you
      // registered it on the Instant dashboard
      clientId: "google-web",
      redirectUri: makeRedirectUri(),
    },
    discovery,
  );

  return (
    <Button
      title="Log in"
      disabled={!request}
      onPress={async () => {
        try {
          const res = await promptAsync();
          if (res.type === 'error') {
            alert(res.error || 'Something went wrong');
          }
          if (res.type === 'success') {
            await db.auth
              .exchangeOAuthCode({
                code: res.params.code,
                codeVerifier: request.codeVerifier,
              })
              .catch((e) => alert(e.body?.message || 'Something went wrong'));
          } else {
          }
        } catch (e) {
          console.error(e);
        }
      }}
    ></Button>
  );
}

Custom Auth

Want to do something more custom? You can roll your own authentication flows using the Admin SDK!

More methods coming

In the future we will provide more mechanisms for auth. If you have any requests, we're all ears!