Back

OAuth2 Giving 404

  • 0
  • React Native
  • Auth
  • Cloud
amianthus
14 Mar, 2025, 20:10

I am trying to implement oauth2 with Google, but it keeps giving this weird 404 error.

TL;DR
Developers are having trouble implementing OAuth2 with Google due to a deep linking issue. OAuth2 with React Native is not fully supported, and there is more information in a GitHub comment. The console logs show the process of trying to retrieve credentials from the redirect URL, but it's not successful. The goal is to use Google for OAuth2, but deep linking and magic URLs are causing a 404 error.
amianthus
14 Mar, 2025, 20:10
TypeScript
// index.tsx
// ...
<Button
                            className="bg-white flex flex-row gap-2"
                            variant="outline"
                            size="lg"

                            onTouchEnd={() => {
                                auth.signIn.google();
                            }}
                        >
                            <AntDesign name="google" size={24} color="black" />
                            <Label className="text-black">
                                Sign in with Google
                            </Label>
                        </Button>
// ...
amianthus
14 Mar, 2025, 20:10
TypeScript
// AuthContext.tsx
import { useContext, createContext, useState, ReactNode } from "react";
import { makeRedirectUri } from "expo-auth-session";
import * as WebBrowser from "expo-web-browser";
import { account } from "@/lib/appwrite";
import { OAuthProvider, Models } from "react-native-appwrite";
import { Text, SafeAreaView } from "react-native";
import { AuthContextType } from "~/types/AuthContextType";

const AuthContext = createContext<AuthContextType>({
    session: null,
    user: null,
    signIn: {
        google: () => {},
    },
    signOut: () => {},
});

const AuthProvider = ({ children }: { children: ReactNode }) => {
    const [loading, setLoading] = useState(false);
    const [session, setSession] = useState<Models.Session | null>(null);
    const [user, setUser] = useState<Models.Preferences | null>(null);

    const signIn = {
        google: async () => {
            // Create a deep link that works across Expo environments
            // Ensure localhost is used for the hostname to validation error for success/failure URLs
            const deepLink = new URL(
                makeRedirectUri({ preferLocalhost: true })
            );
            if (!deepLink.hostname) {
                deepLink.hostname = "localhost";
            }
            const scheme = `${deepLink.protocol}//`; // e.g. 'exp://' or 'playground://'
amianthus
14 Mar, 2025, 20:10
TypeScript
            // Explicitly URL-encode the redirect URLs
            const successRedirect = encodeURIComponent(deepLink.toString());
            const failureRedirect = encodeURIComponent(deepLink.toString() + "/fail");

            // Start OAuth flow
            const loginUrl = await account.createOAuth2Session(
                OAuthProvider.Google,
                successRedirect, // Use the encoded URL
                failureRedirect  // Use the encoded URL
            );

            console.log("Scheme: ", scheme);
            console.log("Deep Link: ", deepLink);
            console.log("Success Redirect: ", successRedirect);
            console.log("Failure Redirect: ", failureRedirect);
            console.log("Login URL: ", loginUrl);

            // Open loginUrl and listen for the scheme redirect
            const result = await WebBrowser.openAuthSessionAsync(
                `${loginUrl}`,
                scheme
            );

            console.log("Result: ", result);

            // Extract credentials from OAuth redirect URL
            if('url' in result) {
                const url = new URL(result.url);
                const secret = url.searchParams.get("secret");
                const userId = url.searchParams.get("userId");
                if(secret && userId) {
                   let session = await account.createSession(userId, secret);
                   setSession(session);
                   let user = await account.get();
                    setUser(user);
                }
                console.log(result, url, secret, userId, session);
            } else {
                throw new Error("OAuth login failed.");
            }

        },
    };

    const signOut = async (): Promise<boolean> => {
        if(session) {
            await account.deleteSession(session.$id);
            setSession(null);
        } else {
            setSession(null);
        }

        return true;
    };
amianthus
14 Mar, 2025, 20:11
TypeScript
    const contextData: AuthContextType = { session, user, signIn, signOut };
    return (
        <AuthContext.Provider value={contextData}>
            {loading ? (
                <SafeAreaView>
                    <Text>Loading...</Text>
                </SafeAreaView>
            ) : (
                children
            )}
        </AuthContext.Provider>
    );
};

const useAuth = () => {
    return useContext(AuthContext);
};

export { useAuth, AuthContext, AuthProvider };
amianthus
14 Mar, 2025, 20:11

heres the console logs

amianthus
14 Mar, 2025, 20:12

I've tried account#createOAuth2Token and that doesnt change anything

Steven
14 Mar, 2025, 20:45

Weird. What URL are you ending up at?

Steven
14 Mar, 2025, 20:45

OAuth2 with React Native is not fully supported. The GitHub comment explains the current state: https://github.com/appwrite/sdk-for-react-native/issues/34#issuecomment-2654940715

amianthus
14 Mar, 2025, 20:47

https://appwrite.io/v1/account/tokens/oauth2/google?success=exp%3A%2F%2F192.168.1.106%3A8081&amp;failure=exp%3A%2F%2F192.168.1.106%3A8081&amp;project=[PROJECTNAME]

but since oauth2 isnt support ig that doesnt matter - do you know if magic urls are supported either? im guessing the deeplinking also applies to that

Steven
14 Mar, 2025, 20:50

Correct, deep linking is the problem so anything related to that will be an issue

Steven
14 Mar, 2025, 20:50

Unless you use universal links

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