Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .optimize-cache.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,10 @@
"images/blog/appwrite-1-8-0-self-hosted-release/cover.png": "c15a9d88ccd16c2dc8333dc74e715e1f4a6c7818d3b4a05f4d68342eacdc0523",
"images/blog/appwrite-1-8-1-self-hosted-release/cover.png": "82f0a396c56b6b299b24133079acc6a317c66b2bf02fd91f4862bd3be0f8f373",
"images/blog/appwrite-1.5-now-available-on-cloud/cloud15.png": "a1df7388572a9f08d0e315e4b6bc8c9464c1418768e7efbec22758fd728eb970",
"images/blog/appwrite-auth-methods/cover.png": "361513d8b59de8fde7b294dcc6688aada30c46e11933070c529733e486784690",
"images/blog/appwrite-backups-and-restores/cover.png": "369b5d91f3dc515e7fb86588f8871aa5ffd788b40023e8373ac694840479c1ab",
"images/blog/appwrite-competitor-comparison/cover.png": "e0b98679795c00fd6d2d304b17273eaa6847bb1fc5706efa6cc3f3040ec6b4bb",
"images/blog/appwrite-custom-domains/cover.png": "f1f52235c259731f28241259c66e6e5f3b27940e7e00c9ce67b60e4afb572ec0",
"images/blog/appwrite-decoded-bradley/bradley-cover.png": "73577a2104024a2df85be14a397ca81f8f6130ff4206358b14547a9758dbf344",
"images/blog/appwrite-decoded-dennis/dennis-career-update.png": "0a99617d99b92c60ef9b3d168dd09dc8e7dae167c6d494d9f2f6a845134e1a67",
"images/blog/appwrite-decoded-dennis/dennis-conference.png": "67758d4b193af922d05ee1dd8744a289d2dcdfdf9e2630f19dbf06d62e66fa92",
Expand Down Expand Up @@ -228,30 +230,42 @@
"images/blog/appwrite-decoded-khushboo/khushboo-with-eldad.png": "b358b6a53d2c5de662b7ddf66aeeb6886478d98c5585a5e2f7068422986cba60",
"images/blog/appwrite-decoded/cover-sara.png": "03ef95d81d475dde4caae31c0b442271c8ae904f8655013a2dfe2f8878b97e44",
"images/blog/appwrite-for-startups-ship-faster-without-backend-headaches/cover.png": "02e52496f4ed5a1526d16b7fd98e0b3b5ebc2ed8bcdca9cda84fe68609abb5d6",
"images/blog/appwrite-functions-guide/cover.png": "0f5ee2b51cc0082d1049be19ae8ea6e77f6082c6293a7df6406d53966043889c",
"images/blog/appwrite-generate/cover.png": "01770d4d6124b317a5103ced1d69b791ef0ce1f1e3a47e4b5072a5fd33c4953d",
"images/blog/appwrite-homepage-redesign/cover-image.png": "bc09d91c421f5967c8986eeaae6f7f001380bee686cd3371fd63a8392484647e",
"images/blog/appwrite-homepage-redesign/iterations-top-part.png": "713613e719366db8d271ab58815ce5f6db476c0b6a764ce53b4884ddd483f66c",
"images/blog/appwrite-homepage-redesign/new-homepage.png": "e58cdf775e1f23ab71e205e0a9d1f6a8573d6e55d673b1a6190be6a79e4e43f0",
"images/blog/appwrite-homepage-redesign/old-homepage.png": "78e71a9a71f59c9f872afbfca91eca73dcc932e25cd83ef22505d314d636a26c",
"images/blog/appwrite-homepage-redesign/summary-vs-deepdive1.png": "fbfed43d56afacb1eb3bbaffa26c002e4bd27a072d25783ae823de123b7d71f2",
"images/blog/appwrite-homepage-redesign/summary-vs-deepdive2.png": "9f18d02a03cfe1f5646e6b585bbeafde584d89cd8a55bef72f1137df73c47b73",
"images/blog/appwrite-indexes/cover.png": "176c9662476a854a6d5aa655b562ec761c8c14d31d6ed7ccbbeca1465301448e",
"images/blog/appwrite-magic-link/cover.png": "d69b6ee225594af2fd84ded6bf43275f8c9105d2610ab851e0cd0b1270989841",
"images/blog/appwrite-messaging-push-email/cover.png": "f2f338968087d91ec10d248d37d41ba36c91dce31eaa9bc6c69822986d82cf05",
"images/blog/appwrite-oauth/cover.png": "43963cbfb499a3db937af52d822662cde32fb2a67bab2f7b24b16f7d24342c90",
"images/blog/appwrite-permissions/cover.png": "c63059c6f879d07312905807371fea29b23459cf757539956de4dc3bdcdc6d89",
"images/blog/appwrite-pricing-update/add-ons.png": "7f7cf75b41114b5f14bda99087e6d9a6d3b39667fb4fc4479389ae3b1a666fb7",
"images/blog/appwrite-pricing-update/bandwidth-project.png": "a34a4914fc6eff580267159cabc3110869c89c64bfd9a9ecb93fb3a6335060fd",
"images/blog/appwrite-pricing-update/combined.png": "e0bdc6025ca29acc57423acfa028a3324a3478937226a5e06cf2ef501a320e4a",
"images/blog/appwrite-pricing-update/cover-pricing.png": "6ebfc20da215e51653885c0bb186751dda9e56cd77722952203afabe97a48d3b",
"images/blog/appwrite-pricing-update/large-project.png": "05ef34992cd56650ee121ca00a2ad666b6b65971058c53043afb0ebbe5dccfbd",
"images/blog/appwrite-pricing-update/one-subscription.png": "70f5e8590a9fa96afb90ec24a20bd94fed8acecd07c2c342e08e0215a7c15773",
"images/blog/appwrite-pricing-update/project.png": "862597aa4be7cb9f4dedebc924432882708ff227ae7c2f73d74c1ef60f60049d",
"images/blog/appwrite-query-api/cover.png": "487c4f1c2d7a4e6c06a66afd5f87e63b5bfaaff34cc091e8ca4d6cc03d0bdbb3",
"images/blog/appwrite-realtime-with-flutter/1.png": "15165041f76b8d59f2f4313519a23d9e1a3820d8e1760b6394971babaa8b9709",
"images/blog/appwrite-realtime-with-flutter/2.png": "44740ca35567eb456c922c1af4a4a44a7e22ff3cd5c53e38e83e32518326561a",
"images/blog/appwrite-realtime-with-flutter/3.png": "c4304f0fa8c92e8a6b473e684139034df94ab2dc7732d1c9dccf9240a712f4f1",
"images/blog/appwrite-realtime-with-flutter/4.png": "ea7d6dd933e62fdbd3b1913ce50de91ef3ddc4173915425d5d4db56cb77aaa70",
"images/blog/appwrite-realtime-with-flutter/5.png": "49fe7599941b7f5702c310047d96ac6f664b498001cdd66a5ac335be96f580c0",
"images/blog/appwrite-realtime-with-flutter/cover.png": "99376d2cf9983874f7e9238dee186f5098c9b7a23d6f8ea3550d518580c8bb6e",
"images/blog/appwrite-realtime/cover.png": "db1c1110935b9ad2a5675e80242914ec38e919004011b0e1060c4d8bc93db5d5",
"images/blog/appwrite-server-sdk-vs-client-sdk/cover.png": "3b674e35218dc6f203824b8ee53eb367e79c33755f64a5456f290768ad5db96f",
"images/blog/appwrite-storage-file-manager/cover.png": "11698e50fb864b4ff99d850290556143b281a988c7fabd23c26b98f653b9b305",
"images/blog/appwrite-teams-roles/cover.png": "34f333eb8ec3ef92514f67d365850a2054e9c9990671f6647ea575533e2954d1",
"images/blog/appwrite-vs-auth0-b2c/appwrite-vs-auth0-chart.png": "bba9245370213f15d1d2066260b22a07fccc054b2847596ad66f57bd968e2d63",
"images/blog/appwrite-vs-auth0-b2c/cover.png": "97e405da84a457a567b552dea23f10e2e4cc5894e90c36d386efb414623a1d9e",
"images/blog/appwrite-vs-cloudinary/cover.png": "ce7d9211396f334c7d165458fe07ffa5fa124dd3e1441e8c993fd60126adb04c",
"images/blog/appwrite-vs-vercel-vs-netlify/cover.png": "dbe40ef9cd2308555771129b95a6bfd7c7d6aa31fb88dab3a9071ad8a415284b",
"images/blog/appwrite-webhooks/cover.png": "3dfed85fb2fbe79c894b9f3808ba95a9533d9c3307879582e1e84d842e3d620f",
"images/blog/avif-in-storage/cover.png": "23c26ec1a8f23f5bf6c55b19407d0738aa41cdc502dc3eef14a78f430a14447b",
"images/blog/avoid-backend-overengineering/cover.png": "c586c235dd6d3f992980748ec7b15cd3411edefe2e71dffc080840540f6d3ba3",
"images/blog/baa-explained/cover.png": "a7b144c7549498760cc2bfddda186b8182766ef72e308abc637dc4cbb5a2c853",
Expand Down
152 changes: 152 additions & 0 deletions src/routes/blog/post/appwrite-auth-methods/+page.markdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
---
layout: post
title: "Appwrite Auth explained: every auth method, compared"
description: A complete comparison of every Appwrite auth method, from email/password to OAuth2, magic URLs, OTP, and MFA, with guidance on when to use each.
date: 2026-03-23
cover: /images/blog/appwrite-auth-methods/cover.png
timeToRead: 5
author: aditya-oberai
category: product, tutorial, security
featured: false
unlisted: true
---

Picking the wrong auth method early in a project creates real pain later. You end up bolt-on patching SMS flows onto a system built only for email, or adding OAuth2 to an app that was never designed for external identity providers. Getting the choice right from the start saves you that work.

[Appwrite](/docs/products/auth) supports ten authentication methods out of the box: email/password, phone SMS, magic URL, email OTP, OAuth2, anonymous sessions, JWT, SSR auth, custom tokens, and MFA. Each one fits a different use case. This post breaks them all down so you can choose with confidence.

# Email and password

Email and password is the baseline for most apps. Appwrite stores passwords hashed with Argon2, which is resistant to brute-force attacks and is widely considered the gold standard for password hashing today.

**When to use it:** Any app where users are comfortable managing their own credentials. It works for most B2C and B2B products, especially when you want full control over the login experience without depending on a third-party identity provider.

**Trade-offs:** You take on responsibility for the password reset flow, email verification, and account recovery. Users also have to remember yet another password, which drives adoption of weak credentials. Pairing email/password with MFA significantly mitigates this.

**Security note:** Appwrite handles the Argon2 hashing, but you still need to enforce HTTPS, rate-limit login attempts, and prompt users to verify their email address after registration.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this, but do we cover rate limiting after a few failed attempts?


[Read the Email/password auth docs](/docs/products/auth/email-password).

# Phone SMS

Phone authentication sends a one-time code via SMS. The user enters the code to confirm ownership of the phone number and complete sign-in.

**When to use it:** Apps where phone number is the primary identifier, such as ride-sharing, food delivery, or any product that needs to tie an account to a real-world person. Also useful when users are unlikely to have or remember an email address.

**Trade-offs:** SMS delivery depends on carrier reliability. Codes can be intercepted via SIM-swapping attacks, which makes SMS OTP less secure than TOTP-based MFA. You also pay per SMS message, so high sign-in frequency adds up.

**Security note:** SMS auth is stronger than no second factor but weaker than authenticator app-based MFA. For high-security applications, layer it with additional verification.

[Read the Phone SMS auth docs](/docs/products/auth/phone-sms).

# Magic URL

Magic URL sends a one-time link to the user's email address. Clicking the link signs them in without a password.

**When to use it:** Apps where friction at login directly hurts retention. SaaS tools, newsletters, developer tools, and internal dashboards all benefit from passwordless auth. If your users reliably check email and you do not want them to manage passwords, magic URL is a strong choice.

**Trade-offs:** Login depends entirely on email access. If a user loses access to their inbox, they lose access to your app. The user also has to switch to their email client to complete login, which adds one extra step compared to entering a password.

**Security note:** Magic links are single-use and expire. Keep expiry times short (under 15 minutes) to reduce the window for link interception.

[Read the Magic URL auth docs](/docs/products/auth/magic-url).

# Email OTP

Email OTP works like magic URL but sends a numeric code instead of a link. The user enters the code in your app to complete sign-in.

**When to use it:** Environments where clicking a link is inconvenient, such as mobile apps where switching to email then returning to the app creates friction. A 6-digit code is faster to transcribe than navigating back from a browser.

**Trade-offs:** Users have to switch to their email app and read the code. This is marginally more friction than magic URL on desktop but often less friction on mobile. Code expiry and single-use constraints are the same as magic URL.

[Read the Email OTP auth docs](/docs/products/auth/email-otp).

# OAuth2

OAuth2 lets users sign in with an existing account from a third-party provider. Appwrite supports over 30 OAuth2 providers, including Google, GitHub, Apple, Microsoft, and Discord.

**When to use it:** Any app where reducing sign-up friction matters. OAuth2 removes the need for users to create and remember new credentials. It also gives you a verified email address and, depending on the provider, additional profile data without asking the user to fill out a form.

**Trade-offs:** You depend on the provider. If Google or GitHub has an outage, users cannot log in. Provider account deletion also means loss of access to your app. Apple Sign-In obfuscates email addresses by default, which complicates email-based communication.

**Security note:** Validate the OAuth2 state parameter to prevent CSRF. Let Appwrite handle the token exchange; do not expose your OAuth2 client secret in client-side code.

[Read the OAuth2 auth docs](/docs/products/auth/oauth2).

# Anonymous sessions

Anonymous sessions create an account without any credentials. Users can interact with your app before committing to registration.

**When to use it:** E-commerce carts, games, or any flow where you want users to start before they sign up. Anonymous sessions lower the barrier to entry significantly.

**Trade-offs:** Anonymous accounts are not recoverable if the session is lost. You need to handle the conversion flow from anonymous to a named account, prompting the user to add credentials at the right moment before they lose data.

[Read the Anonymous auth docs](/docs/products/auth/anonymous).

# JWT auth

JWT auth lets you attach a signed JSON Web Token to requests from your backend. Appwrite validates the token and executes the request in the context of the associated user.

**When to use it:** Server-rendered apps or custom backends that need to make Appwrite requests on behalf of a specific user. JWTs bridge your existing auth layer with Appwrite when you are not using Appwrite's own session management.

**Trade-offs:** JWTs carry an expiry risk. A compromised token remains valid until expiry unless you implement a revocation mechanism. Keep JWT lifetimes short and store them securely.

[Read the JWT auth docs](/docs/products/auth/jwt).

# SSR auth

SSR auth is designed for server-side rendering frameworks like Next.js, SvelteKit, and Nuxt. It allows you to read and write session cookies on the server, keeping session management consistent between server and client renders.

**When to use it:** Any SSR or hybrid app where session cookies need to be available during the initial server render. Without SSR auth, server-rendered pages do not have access to the client's session, causing hydration mismatches and requiring extra client-side fetches.

[Read the SSR auth docs](/docs/products/auth/server-side-rendering).

# Custom tokens

Custom tokens let your backend generate a short-lived token that a client can exchange for a full Appwrite session. You control who gets a token and under what conditions.

**When to use it:** Migrating users from an existing auth system without forcing a password reset. Also useful for auth flows not covered by the built-in methods, such as biometrics handled outside Appwrite or a proprietary SSO system.

**Trade-offs:** You are building and maintaining the token issuance logic. Security is your responsibility on the issuance side.

[Read the Custom token auth docs](/docs/products/auth/custom-token).

# Multi-factor authentication (MFA)

MFA adds a second verification step on top of any primary auth method. Appwrite supports TOTP-based authenticator apps and email OTP as MFA factors.

**When to use it:** Any app handling sensitive data, financial information, or user accounts with elevated privileges. For B2B SaaS, offering MFA is often a requirement for enterprise customers.

**Trade-offs:** MFA adds a step to the login flow. Some users will find it annoying. Making MFA optional but encouraged (rather than mandatory) often works better for consumer apps. For admin accounts, mandatory MFA is worth the friction.

[Read the MFA auth docs](/docs/products/auth/mfa).

# Teams and labels for access control

Authentication is about proving identity. Authorization is about what that identity can do. Appwrite separates the two cleanly.

Teams let you group users and assign roles within the group. A user can belong to multiple teams with different roles in each. Labels let you tag individual users with arbitrary strings and then use those tags in permission rules. Together, teams and labels give you a flexible access control layer without writing custom middleware.

[Read the Teams docs](/docs/products/auth/teams). [Read the Labels docs](/docs/products/auth/labels).

# Choosing the right method

Here is a quick reference:

- **Email/password:** Solid default for most apps. Add MFA for sensitive accounts.
- **Phone SMS:** Best when phone number is the primary identifier.
- **Magic URL:** Low-friction desktop web flows where users check email.
- **Email OTP:** Mobile apps where switching to a browser link is inconvenient.
- **OAuth2:** Fastest sign-up experience. Use when third-party provider dependency is acceptable.
- **Anonymous sessions:** Pre-registration flows, shopping carts, demos.
- **JWT:** Server-to-Appwrite requests on behalf of a user.
- **SSR auth:** Server-rendered frameworks requiring session access on first render.
- **Custom tokens:** Auth migrations and external SSO integrations.
- **MFA:** Second layer for any method, strongly recommended for sensitive data.

# Start building with Appwrite Auth

Appwrite Auth handles the complexity of credential storage, session management, and provider integrations so you can focus on your product. Every method described here is available in Appwrite Cloud with no additional setup.

- [Appwrite Auth overview](/docs/products/auth)
- [Sign up for Appwrite Cloud](https://cloud.appwrite.io)
Loading
Loading