Authentication and Permissions
Magic Code Auth
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.
Choose the platform you're building for to see a full example.
#Full Magic Code Example
Here's a full example of magic code auth in a React app. Open up your app/page.tsx file, and replace the entirety of it with the following code:
'use client';import React, { useState } from 'react';import { init } from '@instantdb/react';const APP_ID = '__APP_ID__';const db = init({ appId: APP_ID });function App() {return (<><db.SignedIn><Main /></db.SignedIn><db.SignedOut><Login /></db.SignedOut></>);}function Main() {const user = db.useUser();return (<div className="space-y-4 p-4"><h1 className="text-2xl font-bold">Hello {user.email}!</h1><buttononClick={() => db.auth.signOut()}className="bg-blue-600 px-3 py-1 font-bold text-white hover:bg-blue-700">Sign out</button></div>);}function Login() {const [sentEmail, setSentEmail] = useState('');return (<div className="flex min-h-screen items-center justify-center"><div className="max-w-sm">{!sentEmail ? (<EmailStep onSendEmail={setSentEmail} />) : (<CodeStep sentEmail={sentEmail} />)}</div></div>);}function EmailStep({ onSendEmail }: { onSendEmail: (email: string) => void }) {const inputRef = React.useRef<HTMLInputElement>(null);const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {e.preventDefault();const inputEl = inputRef.current!;const email = inputEl.value;onSendEmail(email);db.auth.sendMagicCode({ email }).catch((err) => {alert('Uh oh :' + err.body?.message);onSendEmail('');});};return (<formkey="email"onSubmit={handleSubmit}className="flex flex-col space-y-4"><h2 className="text-xl font-bold">Let's log you in</h2><p className="text-gray-700">Enter your email, and we'll send you a verification code. We'll createan account for you too if you don't already have one.</p><inputref={inputRef}type="email"className="w-full border border-gray-300 px-3 py-1"placeholder="Enter your email"requiredautoFocus/><buttontype="submit"className="w-full bg-blue-600 px-3 py-1 font-bold text-white hover:bg-blue-700">Send Code</button></form>);}function CodeStep({ sentEmail }: { sentEmail: string }) {const inputRef = React.useRef<HTMLInputElement>(null);const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {e.preventDefault();const inputEl = inputRef.current!;const code = inputEl.value;db.auth.signInWithMagicCode({ email: sentEmail, code }).catch((err) => {inputEl.value = '';alert('Uh oh :' + err.body?.message);});};return (<formkey="code"onSubmit={handleSubmit}className="flex flex-col space-y-4"><h2 className="text-xl font-bold">Enter your code</h2><p className="text-gray-700">We sent an email to <strong>{sentEmail}</strong>. Check your email, andpaste the code you see.</p><inputref={inputRef}type="text"className="w-full border border-gray-300 px-3 py-1"placeholder="123456..."requiredautoFocus/><buttontype="submit"className="w-full bg-blue-600 px-3 py-1 font-bold text-white hover:bg-blue-700">Verify Code</button></form>);}export default App;
Let's dig deeper.
We created a login flow to handle magic code auth. 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 queries or transactions, the refresh token will be used to hydrate auth on the backend during permission checks.
On the client, auth will now be populated with a user -- huzzah!
#Send a Magic Code
db.auth.sendMagicCode({ email }).catch((err) => {alert('Uh oh :' + err.body?.message);onSendEmail('');});
Use auth.sendMagicCode to generate a magic code on instant's backend and email it to the user.
#Sign in with Magic Code
db.auth.signInWithMagicCode({ email: sentEmail, code }).catch((err) => {inputEl.value = '';alert('Uh oh :' + err.body?.message);});
You can then use auth.signInWithMagicCode to authenticate the user with the magic code they provided.
#Setting properties at signup
Pass extraFields to signInWithMagicCode to set custom $users properties when a user is first created. Fields are only written on first signup; returning users are unaffected.
const { user, created } = await db.auth.signInWithMagicCode({email: sentEmail,code,extraFields: { nickname: 'nezaj' },});if (created) {// Scaffold default data for new usersdb.transact([db.tx.settings[id()].update({ theme: 'light' }).link({ user: user.id }),]);}
The fields must be defined as optional attributes on $users in your schema. A create rule on $users is also required. See Setting properties at signup for the full guide.
#Test users
If you need to create a user with a pre-defined code for app store review or testing, you can assign a magic code to an email from the Auth page of the Dashboard.
When a test user signs in, they can use the static code instead of receiving the code an email. The static code will never expire and will always be valid until it is deleted from the dashboard.