Skip to content
Back

account.get() 401 (Unauthorized) in React Native for Web

  • 1
  • 6
  • React Native
  • Web
  • Auth
Jacob
4 Sep, 2024, 05:47

Hi all, I'm following the repo https://github.com/adrianhajdin/aora to make the app work in browser with react-native-web. The sign-in feature works well on mobile devices, but not in web browsers.

In https://github.com/adrianhajdin/aora/blob/main/app/(auth)/sign-in.jsx, after clinking Sign In button with correct credentials, I got an error ```GET https://cloud.appwrite.io/v1/account 401 (Unauthorized)

AppwriteException: User (role: guests) missing scope (account) at Client.<anonymous> (http://localhost:8081/node_modules/expo-router/entry.bundle?platform=web&amp;dev=true&amp;hot=false&amp;lazy=true&amp;transform.routerRoot=app&amp;resolver.environment=client&amp;transform.environment=client:93245:19) at Generator.next (<anonymous>) at fulfilled (http://localhost:8081/node_modules/expo-router/entry.bundle?platform=web&amp;dev=true&amp;hot=false&amp;lazy=true&amp;transform.routerRoot=app&amp;resolver.environment=client&amp;transform.environment=client:92875:26)``` I've tried to add some debug code around the signIn call in sign-in.jsx:

TypeScript
      const session = await signIn(form.email, form.password);
      console.log(`User signed in: ${form.email}`);
      console.log(`Session: ${JSON.stringify(session)}`);
      const result = await getCurrentUser();```
and also in the `getAccount` method in https://github.com/adrianhajdin/aora/blob/main/lib/appwrite.js :```    console.log("Getting current account");
    const currentAccount = await account.get();
    console.log(`Current account: ${JSON.stringify(currentAccount)}`);```
I'll paste the whole console output I got from the browser below, since Discord says "Message is too long".

Any help/advice would be greatly appreciated.
TL;DR
Error 401 (Unauthorized) when using `account.get()` in React Native for Web. Issue related to session not being set correctly. Possible fixes include checking localStorage, clearing cookies, and clock skew; particularly challenging in Flutter / Dart due to handling of web functionalities. One proposed solution involves separating the Appwrite initialization for web and mobile platforms.
Jacob
4 Sep, 2024, 05:52
TypeScript
entry.bundle?platfor…onment=client:30573 props.pointerEvents is deprecated. Use style.pointerEvents
entry.bundle?platfor…onment=client:93249 Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.
entry.bundle?platfor…onment=client:17566 User signed in: ******@*****.com
entry.bundle?platfor…onment=client:17567 Session: {"$id":"66d7f502c71f38ad8662","$createdAt":"2024-09-04T05:49:54.820+00:00","$updatedAt":"2024-09-04T05:49:54.820+00:00","userId":"66d6631300029d264ea3","expire":"2025-09-04T05:49:54.815+00:00","provider":"email","providerUid":"*******@*****.com","providerAccessToken":"","providerAccessTokenExpiry":"","providerRefreshToken":"","ip":"192.168.65.1","osCode":"MAC","osName":"Mac","osVersion":"10.15","clientType":"browser","clientCode":"CH","clientName":"Chrome","clientVersion":"128.0","clientEngine":"Blink","clientEngineVersion":"128.0.0.0","deviceName":"desktop","deviceBrand":"Apple","deviceModel":"","countryCode":"--","countryName":"Unknown","current":true,"factors":["password"],"secret":"","mfaUpdatedAt":""}
entry.bundle?platfor…onment=client:21499 Getting current account
entry.bundle?platfor…onment=client:93236 
 GET https://cloud.appwrite.io/v1/account 401 (Unauthorized)
entry.bundle?platfor…onment=client:21511 AppwriteException: User (role: guests) missing scope (account)
    at Client.<anonymous> (http://localhost:8081/node_modules/expo-router/entry.bundle?platform=web&de…Root=app&resolver.environment=client&transform.environment=client:93245:19)
    at Generator.next (<anonymous>)
    at fulfilled (http://localhost:8081/node_modules/expo-router/entry.bundle?platform=web&de…Root=app&resolver.environment=client&transform.environment=client:92875:26)```
trashcoder
4 Sep, 2024, 06:59

do you have add platform "localhost" as web app in your appwrite instance?

trashcoder
4 Sep, 2024, 07:01

But i don't know if it's a good behaviour for a public appwrite instance to add "localhost"

Jacob
4 Sep, 2024, 14:15

I thought "as long as it works, I don't care whether it's a good behaviour"😂 . I've even tried to put a wildcard * for both iOS and web platform, but the error persists.

Jacob
4 Sep, 2024, 14:20

Actually I don't have the web platform at first; I created it only because I was hoping it could fix the error. As I'm using Appwrite React Native SDK, I don't think it really matters whether I have a web app platform in my appwrite instance.

ideclon
5 Sep, 2024, 09:58

localhost is automatically allowed - there’s no need to set a Platform for it

ideclon
5 Sep, 2024, 10:01

How are you accessing the account object?

Jacob
5 Sep, 2024, 12:59

I'm accessing the account object by creating an instance of the Account class from the react-native-appwrite library. This instance is initialized with the client object, which is configured with the Appwrite endpoint, project ID, and platform.

Here is my step-by-step process:

  1. Importing the Account class:
TypeScript
import { Account } from "react-native-appwrite";
  1. Creating and configuring the client object:
TypeScript
const client = new Client();

client
  .setEndpoint(config.endpoint) 
  .setProject(config.projectId) 
  .setPlatform(config.platform); 
  1. Creating an instance of the Account class:
TypeScript
const account = new Account(client);
  1. Using the account object to call methods:
  • Creating a user:
TypeScript
const newAccount = await account.create(ID.unique(), email, password, username);
  • Signing in a user:
TypeScript
const session = await account.createEmailPasswordSession(email, password);
  • Getting the current user:
TypeScript
const currentAccount = await account.get();

Currently the account object works fine for users signup and signin on both mobile and web platforms, and it could get the correct session after verifying credentials. However, the account.get() would get an error after that.

5 Sep, 2024, 13:53

This is an LLM response, isn’t it

6 Sep, 2024, 01:26

Yes, sorry about that, as I haven't quite got your question about accessing the account object. I've followed the docs of sdk-for-react-native to create the account object in the first 3 steps above, and after a user signed in with correct credentials, it would get the user's session. Then I'm trying to get the current account with account.get(), and the error pops up.

6 Sep, 2024, 02:11

Are you using the same account instance in your account.get() as in your account.createEmailPasswordSession()?

6 Sep, 2024, 08:07

Yes, I can confirm I've followed the example from sdk-for-react-native, declared only one account instance at the same scale of client instance, then using it in both signIn and getCurrentUser methods. Also, I don't think the program could work as expected on mobile devices if I didn't use the same account.

Below is related code snippet from my @/lib/appwrite.ts:

TypeScript
import {
  Account,
  Avatars,
  Client,
  Databases,
  ID,
  Query,
} from "react-native-appwrite";

const client = new Client();

client
  .setEndpoint(config.endpoint)
  .setProject(config.projectId)
  .setPlatform(config.platform)

const account = new Account(client);
const avatars = new Avatars(client);
const databases = new Databases(client);

export const signIn = async (email: string, password: string) => {
  try {
    const session = await account.createEmailPasswordSession(email, password);
    if (!session) {
      throw new Error("Failed to create session");
    }
    return session;
  } catch (e) {
    console.log(e);
    throw new Error((e as Error).message);
  }
};

export const getCurrentUser = async () => {
  try {
    console.log("Getting current user");
    const currentAccount = await account.get();
    console.log(`Current account: ${JSON.stringify(currentAccount)}`);
    if (!currentAccount) {
      throw new Error("Failed to get account data");
    }
    const currentUser = await databases.listDocuments(
      config.databaseId,
      config.userCollectionId,
      [Query.equal("accountId", currentAccount.$id)],
    );
    if (!currentUser) {
      throw new Error("Failed to get user data");
    }
    return currentUser.documents[0];
  } catch (e) {
    throw new Error((e as Error).message);
  }
};

The code from https://github.com/adrianhajdin/aora would get the same error. The differences between that repo and mine are just I've used TypeScript and newer appwrite SDK (0.4.0).

6 Sep, 2024, 11:53

Hmm. So the session is clearly being created - createEmailPasswordSession() is returning a session. My best guess is that the cookie isn’t being set, for some reason

6 Sep, 2024, 12:34

There is a warning when createEmailPasswordSession() is called in sign-in process:

TypeScript
appwrite.ts:69 
 Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.
Promise.then        
signIn    @    appwrite.ts:69
submit    @    sign-in.tsx:35

But the warning doesn't pop up in the log of mobile devices.

Could it have anything to do with the matter?

6 Sep, 2024, 12:38

It’s possible - if you dump localStorage, do you see the Appwrite session key there?

6 Sep, 2024, 12:48

Sorry I'm not sure what a session key is... Below is my localStorage dump with the error, would you please take a look? Thanks.

TypeScript
appwrite.ts:69 
 Appwrite is using localStorage for session management. Increase your security by adding a custom domain as your API endpoint.
sign-in.tsx:36 User signed in: **@**.com
sign-in.tsx:37 Session: {"$id":"66daf8969a0fb5c0d597","$createdAt":"2024-09-06T12:41:58.646+00:00","$updatedAt":"2024-09-06T12:41:58.646+00:00","userId":"66d6631300029d264ea3","expire":"2025-09-06T12:41:58.631+00:00","provider":"email","providerUid":"**@**.com","providerAccessToken":"","providerAccessTokenExpiry":"","providerRefreshToken":"","ip":"192.168.65.1","osCode":"MAC","osName":"Mac","osVersion":"10.15","clientType":"browser","clientCode":"PS","clientName":"Microsoft Edge","clientVersion":"128.0","clientEngine":"Blink","clientEngineVersion":"128.0.0.0","deviceName":"desktop","deviceBrand":"Apple","deviceModel":"","countryCode":"--","countryName":"Unknown","current":true,"factors":["password"],"secret":"","mfaUpdatedAt":""}
appwrite.ts:82 Getting current user
appwrite.ts:83 
 
 GET https://cloud.appwrite.io/v1/account 401 (Unauthorized)
appwrite.ts:98 AppwriteException: User (role: guests) missing scope (account)
    at Client.<anonymous> 
    at Generator.next (<anonymous>)
    at fulfilled 
sign-in.tsx:54 
 Error signing in: Error: User (role: guests) missing scope (account)
console.log(JSON.stringify(localStorage, null, 2));
VM269:1 {
  "cookieFallback": "{\"a_session_66d5c07300176a742026\":\"eyJpZCI6IjY2ZDY2MzEzMDAwMjlkMjY0ZWEzIiwic2VjcmV0IjoiZGY1YTAyMWVhODg1NzRiY2E5NGNjYjAxZWQ0YzYwODA0YmYxNzA0ZGIyZmJhYWU5YTExM2E0YTBmMTQ4ZWRkYmRlYjNjYzg4YmU5ZmNjNzZlMDEyNDdjZGZlNzkwMTEzYTJkYmY3MzNkNjNlYzI4ODY2ZTNlZWZlMmVhZGZkNzQzN2ZmZTZjZDE4Zjk4NzdiYmIzMmFkZWI1YTA0MDA4MjAxMGZkZGZlZmQ0MmE1OTJiZjk2YzhiNjk2YzNjNzEyMDBmMzAwNWU2ZDI3MGM5ZTIwZGJmOWYwOWQ5ZmMyM2VjZGZiN2Q0ZTUwMjFiOTY2ZjY3NjFlZmY5MjdjMWZkZCJ9\"}"
}
6 Sep, 2024, 12:58

That looks correct…

6 Sep, 2024, 18:52

maybe try clearing your cookies and deleting the sessions for the user via the Appwrite Console?

Also, does your device have any sort of clock skew?

6 Mar, 2026, 04:51

<@462046107556511744> I am also facing the same thing.... it is sad that in 2026 this issue has been forgotten 🥲 but is ok your team must be busy making appwrite more and more amazing so you guyrs have a lot on your plate... anyhow here is how to fix it...

In the beginning, I thought I would just hack my own cookieFallback into localStorage. But somehow after a page refresh, the session just disappears, and I get kicked back to the login screen!

After digging into it, I realized that the react-native-appwrite SDK relies heavily on native AsyncStorage (for mobile) and defaults to HTTP-only cookies for web. Because of strict browser CORS and third-party cookie blocking, those cookies get rejected on local web development, so the session is never saved.

The fix is to split your Appwrite initialization so that iOS/Android continue using react-native-appwrite, but the Web platform uses the pure appwrite web SDK (which has a built-in, automatic localStorage fallback mechanism for when cookies fail).

Here is exactly how to fix it in an Expo project:

Step 1: Install the pure web SDK Run npm install appwrite alongside your react-native-appwrite package.

6 Mar, 2026, 04:51

Step 2: Create

src/appwriteConfig.native.ts This handles iOS and Android using the React Native SDK exactly as you normally would.

TypeScript
import { Account, Client, Functions, Storage, TablesDB,  } from 'react-native-appwrite';
export const appwriteClient = new Client();
appwriteClient
  .setEndpoint(process.env.EXPO_PUBLIC_APPWRITE_END_POINT || "")
  .setProject(process.env.EXPO_PUBLIC_APPWRITE_PROJECT_ID || "")
  .setPlatform(process.env.EXPO_PUBLIC_APP_ID || "");
if (process.env.APPWRITE_PROJECT_DEV_KEY) {
  console.log("[Appwrite] init service using Dev key to bypass CORS");
  appwriteClient.setDevKey(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_DEV_KEY);
}
export const appwriteAccount = new Account(appwriteClient);
export const appwriteTables = new TablesDB(appwriteClient);
export const appwriteFunctions = new Functions(appwriteClient);
export const appwriteStorage = new Storage(appwriteClient);
console.log('[AppWrite] init service initialized')
export { ID } from "react-native-appwrite";```
6 Mar, 2026, 04:52

Step 3: Create

src/appwriteConfig.web.ts This handles the Web browser using the pure Web SDK. (Note: The Web SDK handles the platform natively via cookies/localstorage, so you drop the .setPlatform() call here)

TypeScript
export const appwriteClient = new Client();
appwriteClient
    .setEndpoint(process.env.EXPO_PUBLIC_APPWRITE_END_POINT || "")
    .setProject(process.env.EXPO_PUBLIC_APPWRITE_PROJECT_ID || "");
// The web SDK determines the platform internally (cookies/localstorage).
// So no need for setPlatform() on web.
export const appwriteAccount = new Account(appwriteClient);
export const appwriteTables = new TablesDB(appwriteClient) as any;
export const appwriteFunctions = new Functions(appwriteClient);
export const appwriteStorage = new Storage(appwriteClient);
console.log('[AppWrite - Web] init service initialized');
export { ID };```
6 Mar, 2026, 04:53

Step 4: Create a platform resolver

src/appwriteConfig.ts While Metro bundler is usually smart enough to resolve

.web.ts vs

.native.ts automatically, having a strict wrapper prevents "require cycle" bugs in Metro and keeps your TypeScript types happy across the whole app!

TypeScript
import * as NativeAppwrite from "./appwriteConfig.native";
import * as WebAppwrite from "./appwriteConfig.web";
// Metro normally resolves appwriteConfig.web.ts or appwriteConfig.native.ts automatically, 
// but for strict TypeScript typechecking, we need this wrapper file
// to ensure @/appwriteConfig resolves to something concrete without Require Cycles.
export const appwriteClient = Platform.OS === "web" ? WebAppwrite.appwriteClient : NativeAppwrite.appwriteClient;
export const appwriteAccount = Platform.OS === "web" ? WebAppwrite.appwriteAccount : NativeAppwrite.appwriteAccount;
export const appwriteTables = Platform.OS === "web" ? WebAppwrite.appwriteTables : NativeAppwrite.appwriteTables;
export const appwriteFunctions = Platform.OS === "web" ? WebAppwrite.appwriteFunctions : NativeAppwrite.appwriteFunctions;
export const appwriteStorage = Platform.OS === "web" ? WebAppwrite.appwriteStorage : NativeAppwrite.appwriteStorage;```
6 Mar, 2026, 04:55

Step 5: Update your imports! Go through your app components and change your Appwrite imports so they look at the wrapper file we just made: import { appwriteClient } from '@/appwriteConfig'.

12 Mar, 2026, 22:34

I believe I have the same problem with Flutter / Dart.

Reply

Reply to this thread by joining our Discord

Reply on Discord

Need support?

Join our Discord

Get community support by joining our Discord server.

Join Discord

Get premium support

Join Appwrite Pro and get email support from our team.

Learn more