Users
Enable guests and user accounts in your project.
Appwrite Configuration
Your Appwrite project's Auth dashboard provides various options to customize the user experience. Go to Auth > Settings to enable your preferred sign-in methods. The auth plugin currently supports:
- OAuth2 Providers (Google, Apple, GitHub, Discord, and 35+ more)
- Anonymous (guest sessions)
- Magic URL
- Email OTP (one-time passcode)
- Phone OTP (SMS one-time passcode)
See Appwrite's Auth docs for all configuration details.
Sign-in Methods
With Manifest and Appwrite, a frontend user registration flow (vs. a login flow) is not required. Unrecognized users will have a new account automatically generated, while known users will login to their existing account (from any sign-in method).
In manifest.json, use the auth methods array to define your project's sign-in methods. At least one must be specified here, and enabled in the connected Appwrite project.
manifest.json {
"appwrite": {
"projectId": "your-project-id",
"endpoint": "your-API-endpoint",
"devKey": "your-dev-key",
"auth": {
"methods": [ "oauth", "magic", "guest-manual" ]
}
}
}
| Method | Description |
|---|---|
guest-auto |
Automatically creates anonymous guest sessions for all visitors (guest is an accepted synonym) |
guest-manual |
Allows users to manually create guest sessions via $auth.requestGuest() |
magic |
Enables passwordless login via magic URLs sent to email |
otp |
Enables passwordless login via a one-time passcode sent to email |
phone |
Enables passwordless login via a one-time passcode sent by SMS |
oauth |
Enables OAuth sign-in with providers like Google, GitHub, etc. |
OAuth
OAuth enables sign-in with third-party providers like Google, GitHub, and 35+ other services supported by and configured in Appwrite's Auth > Settings page.
{
"appwrite": {
...
"auth": {
"methods": ["oauth"]
}
}
}
The $auth.loginOAuth('...') method accepts provider names like google, github, and discord. When applicable, the user is redirected to the provider's sign-in page and gets returned when authenticated.
Magic URLs
Magic URLs provide passwordless authentication via email. Users enter their email address and get emailed a sign-in link that's valid for one hour, which can be used once.
{
"appwrite": {
...
"auth": {
"methods": ["magic"]
}
}
}
The button's $auth.sendMagicLink() method automatically finds the email input in the same parent element, form element, or otherwise finds the first email input on the page. To target a specific input, add its element ID like $auth.sendMagicLink('#email-input'). When activated, a magic URL is sent and the email input field is cleared.
When users click the magic URL in their email, they're redirected back to your app. The plugin automatically handles the callback and creates the session.
Email content can be customized in Appwrite under Auth > Templates > Magic URL.
Email OTP
Email OTP provides passwordless authentication via a one-time passcode. Users enter their email address, receive a short code by email, then enter that code to sign in — all on the same page, with no redirect.
{
"appwrite": {
...
"auth": {
"methods": ["otp"]
}
}
}
$auth.sendEmailOTP() finds the email input the same way sendMagicLink() does (nearest input, form, or first on the page), or accepts a selector like $auth.sendEmailOTP('#email-input').
After a code is sent, $auth.otpSent becomes true; $auth.submitOTP() reads the code input (any input[name="otp"], autocomplete="one-time-code", or numeric input) and completes sign-in. Pass { phrase: true } to sendEmailOTP to enable Appwrite's anti-phishing security phrase, then display $auth.otpPhrase alongside the code field.
Email content and code length can be customized in Appwrite under Auth > Templates > OTP.
Phone OTP
Phone OTP provides passwordless authentication via a one-time passcode sent by SMS. Users enter their phone number, receive a short code by text, then enter that code to sign in — all on the same page, with no redirect.
{
"appwrite": {
...
"auth": {
"methods": ["phone"]
}
}
}
$auth.sendPhoneOTP() finds the phone input the same way sendEmailOTP() does (nearest input[type="tel"], form, or first on the page), or accepts a selector like $auth.sendPhoneOTP('#phone-input'). Numbers must include the country code (international E.164 format, e.g. +14155550123); common separators like spaces, dashes, and parentheses are stripped automatically.
The code-entry step is shared with email OTP: the same $auth.submitOTP() and $auth.otpSent/$auth.otpExpired flags drive it, so the verify markup is identical.
Phone OTP requires an SMS provider (Twilio, Vonage, MSG91, or Telesign) connected in Appwrite under Messaging > Providers, and the Phone method enabled under Auth > Settings.
Guest Sessions
Guest sessions allow visitors to browse your app without creating an account, with each session registered in the Appwrite userbase (including repeat visits from the same user). With Manifest, guest sessions can begin automatically or by a user action.
By default, when a guest signs in, a fresh account is created and the guest session is discarded. To instead preserve the guest's account and data when they sign in, enable Guest Upgrade.
Auto Guest Sessions
When guest-auto is enabled in your manifest, all visitors automatically enter a guest session on page load.
manifest.json {
"appwrite": {
...
"auth": {
"methods": ["guest-auto"]
}
}
}
Manual Guest Sessions
When guest-manual is enabled, visitors must explicitly choose to continue as a guest.
{
"appwrite": {
...
"auth": {
"methods": ["guest-manual"]
}
}
}
Guest Upgrade
By default a guest who signs in gets a brand-new account, and anything tied to the guest session (such as guest-created teams) is left behind. Set guestUpgrade to true to instead convert the guest's existing account in place, preserving its data and team memberships.
manifest.json {
"appwrite": {
...
"auth": {
"methods": ["guest-manual", "magic", "oauth"],
"guestUpgrade": true
}
}
}
No markup changes are needed — $auth.sendMagicLink() and $auth.loginOAuth() handle the upgrade automatically when a guest signs in. guestUpgrade defaults to the value of teams.guests, so enabling guest teams turns it on for you.
Guest Team Carryover (OTP)
Because email and phone OTP can't convert a guest in place, guestUpgrade can't preserve a guest's teams for OTP sign-ins. guestMigration covers this case: it carries the guest's teams over to the new account by reassigning team membership. It's the OTP-friendly counterpart to guestUpgrade.
Reassigning team ownership between accounts is privileged — it needs a server API key, so it has to run on a server, not in the browser. To make that turnkey, Manifest provides a ready-to-deploy guest-migration function template. Deploy it to your Appwrite project and point the plugin at it:
manifest.json {
"appwrite": {
...
"auth": {
"methods": ["guest-manual", "otp"],
"teams": { "permanent": ["Workspace"], "guests": true },
"guestMigration": { "functionId": "<your function id>" }
}
}
}
No markup changes — after a guest verifies an OTP code, the plugin transparently moves their teams to the new account. The same function also garbage-collects abandoned guests and their orphaned teams on a schedule.
The template is one ready-made implementation; the plugin just calls a function that speaks a small prepare/commit contract, so you can swap the function's internals for your own backend logic if you ever need to. Its README walks through deploying it.
Combined Methods
Sign-in methods can be stacked to provide optionality to users.
{
"appwrite": {
...
"auth": {
"methods": ["guest-manual", "magic", "oauth"]
}
}
}
Properties
The auth plugin provides an $auth magic property that exposes authentication state and methods.
Authentication State
User Profile ($auth.user)
Current user profile (null if not authenticated). The user object comes directly from Appwrite's account.get().
| Property | Type | Description |
|---|---|---|
$auth.user?.$id |
string | User's unique ID |
$auth.user?.email |
string | User's email address |
$auth.user?.name |
string | User's display name |
$auth.user?.$createdAt |
string | Account creation timestamp |
$auth.user?.$updatedAt |
string | Last update timestamp |
$auth.user?.prefs |
object | User preferences object |
| Other properties | - | All other Appwrite User object properties are available |
Session Information ($auth.session)
Current session details (null if not authenticated). The session object comes directly from Appwrite's session data.
| Property | Type | Description |
|---|---|---|
$auth.session?.$id |
string | Session ID |
$auth.session?.userId |
string | User ID associated with session |
$auth.session?.expire |
string | Session expiration timestamp |
$auth.session?.provider |
string | Authentication provider used ('anonymous', 'magic-url', or OAuth provider name) |
$auth.session?.ip |
string | IP address of session |
$auth.session?.osCode |
string | Operating system code |
$auth.session?.osName |
string | Operating system name |
$auth.session?.osVersion |
string | Operating system version |
$auth.session?.deviceName |
string | Device name |
$auth.session?.deviceBrand |
string | Device brand |
$auth.session?.deviceModel |
string | Device model |
| Other properties | - | All other Appwrite Session object properties are available |
Status Flags
| Property | Type | Description |
|---|---|---|
$auth.isAuthenticated |
boolean | Indicates if user is authenticated |
$auth.isAnonymous |
boolean | Indicates if user is a guest |
$auth.inProgress |
boolean | Indicates if an auth operation is in progress |
$auth.error |
string | null | Error message string (null if no error) |
$auth.magicLinkSent |
boolean | Indicates if magic link was sent |
$auth.magicLinkExpired |
boolean | Indicates if magic link expired |
$auth.otpSent |
boolean | Indicates if an OTP code (email or SMS) was sent and awaits entry |
$auth.otpExpired |
boolean | Indicates if the entered OTP code was invalid or expired |
$auth.otpPhrase |
string | null | Email OTP anti-phishing security phrase (when requested with { phrase: true }) |
$auth.guestManualEnabled |
boolean | Indicates if manual guest creation is enabled |
Computed Properties
| Property | Type | Description |
|---|---|---|
$auth.method |
string | null | Authentication method: 'oauth', 'magic', 'otp', 'phone', 'anonymous', or null |
$auth.provider |
string | null | OAuth provider name (e.g., 'google', 'github') or null for non-OAuth methods |
Available Methods
| Method | Parameters | Description |
|---|---|---|
$auth.loginOAuth(...) |
provider (string), successUrl (optional), failureUrl (optional) |
Sign in with OAuth provider. Redirects to provider. |
$auth.sendMagicLink(...) |
emailInputOrRef (element ID or element, optional), redirectUrl (optional) |
Send magic link to email. |
$auth.sendEmailOTP(...) |
emailInputOrRef (selector or element, optional), options (optional, { phrase: true } for a security phrase) |
Email a one-time passcode. |
$auth.sendPhoneOTP(...) |
phoneInputOrRef (selector or element, optional) |
Text a one-time passcode to a phone number (E.164 format). |
$auth.submitOTP(...) |
codeInputOrRef (selector or element, optional) |
Verify the entered passcode and complete sign-in (email or phone). |
$auth.requestGuest() |
None | Create a manual guest session. |
$auth.logout() |
None | Delete current session and sign out. If automatic guest sessions are enabled, a new guest session will begin after logout. |
$auth.refresh() |
None | Refresh user data from Appwrite. |
$auth.canAuthenticate() |
None | Check if user can authenticate (not already signed in or in progress). |
Session Recovery
Sessions are checked against Appwrite on every page load, and the plugin distinguishes a real sign-out from a connection problem.
Sign-out Across Tabs
Logging out in one tab signs out every open tab (or moves them to the new guest session, with auto guest sessions), as does a session check finding the session gone (a 401). Every Appwrite table and bucket source clears and reloads in every tab, so the previous user's entries never linger. Signing in or switching accounts from another tab reloads them too, and loads that user's teams (see cloud data).
Offline Starts
When a signed-in user opens the app without a connection, the session check fails with a network error rather than a "no session" answer. The tab renders signed out ($auth.isAuthenticated is false) but other tabs are left untouched — only a genuine "no session" answer from Appwrite signs them out. Auto guest sessions are also held back, so no guest account is created over the real one.
The session is rechecked when the connection returns, when the user returns to the tab, and on a timer (2s, 5s, 15s, then every 60s). Once Appwrite answers, either the session is restored — the usual sign-in events fire, and every table and bucket source reloads for the user, including those showing saved rows — or a genuine "no session" answer signs the user out everywhere.
Meanwhile, persisted rows saved for the user last signed in on this device are shown, except from tables with a scope and sources whose queries reference $auth. values, which end up empty while the tab is signed out. A "no session" answer clears them.
Next Steps
See teams to enable shared workspaces between users, including roles and permissions.
Article does not exist
There is no documentation at this path.