Invalid success param when using OAuth2 login
hi i am having issues with using google oauth for login - I am using react native sdk - it all works when on expo go , but when i installed it to testfight it stops working - and when trying to login with google - in get invalid sucess param should be one of - localhost .... etc . here is my sign in code -
let redirectUri = makeRedirectUri({ preferLocalhost: true });
console.log("Redirect URI:", redirectUri);
const url = await account.createOAuth2Token(
"google",
redirectUri,
redirectUri,
[
"profile",
"email",
"https://www.googleapis.com/auth/youtube",
"https://www.googleapis.com/auth/youtube.force-ssl",
"https://www.googleapis.com/auth/youtube.upload",
"https://www.googleapis.com/auth/youtubepartner",
]
);
console.log("URL:", url);
if (!url) {
throw new Error("Failed to create OAuth2 session");
}
const result = await openAuthSessionAsync(url.href, redirectUri);
console.log("Auth session result:", result);
if (result.type === "success") {
if ("url" in result) {
const resultUrl = new URL(result.url);
const secret = resultUrl.searchParams.get("secret");
const userId = resultUrl.searchParams.get("userId");
if (!secret || !userId) return;
await account.createSession(userId, secret);
const user = await account.get().catch((e) => {
console.warn(e);
return null;
});
console.log("user:", user);
see the screen shot for google cloud credentials
Image
@schoolofai, thanks for creating this issue! 🙏🏼 Could you please share exactly what the redirectUri is when running via TestFlight? It's likely the hostname in the URL hasn't been registered in your Appwrite project yet.
So, at the moment, Expo will create deep links like:
- Development and production builds:
<scheme>://path- uses the optional scheme property if provided, and otherwise uses the first scheme defined by your app config - Web (dev):
https://localhost:19006/path - Web (prod):
https://myapp.com/path - Expo Go (dev):
exp://128.0.0.1:8081/--/path
Appwrite will try to validate the host part of the URL against the allowed web platforms to protect against open redirect attacks so you'll get a 400 error like:
Invalid
successparam: URL host must be one of: localhost, cloud.appwrite.io, appwrite.io
It's impossible to change RN to include a hostname or you may run into a path not found error when redirect back into the RN app.
We'll have to discuss internally about how to handle react native.
https://github.com/appwrite/appwrite/pull/9262 was merged but then reverted due to issues during QA. We'll need to fix the issues with another PR.
same issue here general_argument_invalid working fine in ios simulation and expo qr code run issue in android emulator export async function login() { try { // need to generate redirect uri for oauth response (once go to google it has to move back to application again (can use expo module foe handling deep links)) const redirectUri = Linking.createURL("/");
// padding redirect url and auth provider
const response = await account.createOAuth2Token(
OAuthProvider.Google,
redirectUri
);
if (!response) throw new Error("Failed to Login");
const browserResult = await openAuthSessionAsync(
response.toString(),
redirectUri
);
if (browserResult.type !== "success") throw new Error("Failed to login");
const url = new URL(browserResult.url);
I have the same problem, here is my current implementation
import { getQueryParams } from "expo-auth-session/build/QueryParams";
import { openAuthSessionAsync } from "expo-web-browser";
----
const createSessionFromUrl = async (url: string) => {
try {
const { params, errorCode } = getQueryParams(url);
if (errorCode) throw new Error(errorCode);
const { secret, userId } = params;
if (!secret || !userId) return;
return await account.createSession(userId, secret);
} catch (error) {
console.error("Error creating session from URL:", error);
throw error;
}
};
signWithOAuth: async (provider: OAuthProvider) => {
const url = await account.createOAuth2Session(
provider,
"myCoolAppwriteApp://(authenticated)",
"myCoolAppwriteApp://auth",
["openid", "profile"]
);
if (!url) throw new Error("Failed to create OAuth2 session");
const res = await openAuthSessionAsync(
url.toString(),
"myCoolAppwriteApp://home"
);
if (res.type === "success") {
const { url } = res;
if (!url) throw new Error("Failed to create session from URL");
await createSessionFromUrl(url);
}
},
Did u find any solution Is this our implementation problem or appwrite issue in local ecpo its working fine because its localhost the deep link concept is not working
On Fri, 28 Mar, 2025, 5:00 pm Dennis Hundertmark, @.***> wrote:
I have the same problem, here is my current implementation
import { getQueryParams } from "expo-auth-session/build/QueryParams";import { openAuthSessionAsync } from "expo-web-browser";
const createSessionFromUrl = async (url: string) => { try { const { params, errorCode } = getQueryParams(url);
if (errorCode) throw new Error(errorCode); const { secret, userId } = params; if (!secret || !userId) return; return await account.createSession(userId, secret);} catch (error) { console.error("Error creating session from URL:", error); throw error; }};
signWithOAuth: async (provider: OAuthProvider) => { const url = await account.createOAuth2Session( provider, "myCoolAppwriteApp://(authenticated)", "myCoolAppwriteApp://auth", ["openid", "profile"] );
if (!url) throw new Error("Failed to create OAuth2 session"); const res = await openAuthSessionAsync( url.toString(), "myCoolAppwriteApp://home" ); if (res.type === "success") { const { url } = res; if (!url) throw new Error("Failed to create session from URL"); await createSessionFromUrl(url); }},
— Reply to this email directly, view it on GitHub https://github.com/appwrite/sdk-for-react-native/issues/34#issuecomment-2761101935, or unsubscribe https://github.com/notifications/unsubscribe-auth/A2VPJ3C4HUUREW242XTFS5L2WUQDDAVCNFSM6AAAAABQYN6EECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONRRGEYDCOJTGU . You are receiving this because you commented.Message ID: @.***> [image: mnkyjs]mnkyjs left a comment (appwrite/sdk-for-react-native#34) https://github.com/appwrite/sdk-for-react-native/issues/34#issuecomment-2761101935
I have the same problem, here is my current implementation
import { getQueryParams } from "expo-auth-session/build/QueryParams";import { openAuthSessionAsync } from "expo-web-browser";
const createSessionFromUrl = async (url: string) => { try { const { params, errorCode } = getQueryParams(url);
if (errorCode) throw new Error(errorCode); const { secret, userId } = params; if (!secret || !userId) return; return await account.createSession(userId, secret);} catch (error) { console.error("Error creating session from URL:", error); throw error; }};
signWithOAuth: async (provider: OAuthProvider) => { const url = await account.createOAuth2Session( provider, "myCoolAppwriteApp://(authenticated)", "myCoolAppwriteApp://auth", ["openid", "profile"] );
if (!url) throw new Error("Failed to create OAuth2 session"); const res = await openAuthSessionAsync( url.toString(), "myCoolAppwriteApp://home" ); if (res.type === "success") { const { url } = res; if (!url) throw new Error("Failed to create session from URL"); await createSessionFromUrl(url); }},
— Reply to this email directly, view it on GitHub https://github.com/appwrite/sdk-for-react-native/issues/34#issuecomment-2761101935, or unsubscribe https://github.com/notifications/unsubscribe-auth/A2VPJ3C4HUUREW242XTFS5L2WUQDDAVCNFSM6AAAAABQYN6EECVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDONRRGEYDCOJTGU . You are receiving this because you commented.Message ID: @.***>
I having same issue Error 400
Invalid 'success' param: URL host must be one of: localhost, appwrite.io, *.appwrite.io, fra.cloud.appwrite.io, *
Type
general_argument_invalid
appwrite/appwrite#9262 was merged but then reverted due to issues during QA. We'll need to fix the issues with another PR.
@stnguyen90 so what's the solution now?
Has anyone gotten a solution yet?
...
export async function login() {
try {
const redirectUri = Linking.createURL("/");
console.log("Redirect URI:", redirectUri);
const response = await account.createOAuth2Token(
OAuthProvider.Google,
redirectUri
);
...
When launching the project via expo, everything works and is displayed in the console:
Redirect URI: exp://192.168.100.8:8082/--/
And with the native build for Android, error 400 and console output:
Redirect URI: com.varn0r.findroute:///
Maybe this will help you solve the problem somehow.🙏
I found this article quiet helpful and was able to enable OIDC Provider (Keycloak) and get everything to work.
https://bishwajeet-parhi.medium.com/i-built-an-auth-template-powered-by-react-native-and-appwrite-4a0b7ee90ba6
I also ran into this issue in my project. I have been on it for a couple of days and here are my findings:
- createOAuth2Session method will not work for android, iOS or emulators. This is because the result does not persist after redirection. The solution is to use createOAuth2Token.
However, createOAuth2Session works fine on the web. And createOAuth2Token doesn't seem to work on the web for some reason.
- Whether you use
makeRedirectUri({ preferLocalhost: true });or deep-linkingLinking.createURL("/"), authentication would still fail because the redirectUri used is not supported.You might even run into this error countlessly:Invalid success param: URL host must be one of: localhost, appwrite.io, *.appwrite.io, cloud.appwrite.io.
The only solution I came across was to create a new platform for the same project. Web in this case. As you can't add urls like exp://192.168.x.x:8081/--/auth to Google Console. I used JavaScript as the project type.
This will provide you a url - usually http://localhost:5173. This is what you'd add to your Google Console's redirect URI list. Since both platform's share the same project (which is used in creating the account object), during redirection, the redirectUri used under the hood will be the one set in Google Console - http://localhost:5173 in this case.
NB: Ensure to set hostname as * (for testing purposes only).
This solution works for me on Android, iOS, web, and my Android emulator.
Here is the solution that works for me:
export async function login() {
try {
// Creates a success redirect url after authentication is successful
const redirectUri = Linking.createURL("/");
console.log("Platform:", Platform.OS);
console.log("Redirect URI:", redirectUri);
if (Platform.OS === "web") {
// Use createOAuth2Session for web
const response = account.createOAuth2Session(
OAuthProvider.Google,
redirectUri,
redirectUri
);
if (!response) throw new Error("Failed to create OAuth2 session");
const browserResult = await openAuthSessionAsync(
response.toString(),
redirectUri
);
if (browserResult.type !== "success") {
throw new Error("OAuth authentication was cancelled or failed");
}
// For web, session is automatically created
const currentSession = await account.getSession("current");
if (!currentSession) {
throw new Error("No session found after OAuth authentication");
}
return currentSession;
} else {
// Use createOAuth2Token for android and ios to ensure cookies
// are shared between app and in-app browser after redirection
const response = account.createOAuth2Token(
OAuthProvider.Google,
redirectUri
);
if (!response) throw new Error("Create OAuth2 token failed");
const browserResult = await openAuthSessionAsync(
response.toString(),
redirectUri
);
if (browserResult.type !== "success")
throw new Error("Create OAuth2 token failed");
console.log("Browser Result: ", browserResult);
const url = new URL(browserResult.url);
const secret = url.searchParams.get("secret")?.toString();
const userId = url.searchParams.get("userId")?.toString();
if (!secret || !userId) throw new Error("Create OAuth2 token failed");
// Create session manually using userId and secret
await account.createSession(userId, secret);
// Return the newly created session
const currentSession = await account.getSession("current");
if (!currentSession) {
throw new Error("Failed to create session after OAuth authentication");
}
return currentSession;
}
} catch (error) {
console.error("Login error:", error);
return null;
}
}
I hope this solution will be helpful to whoever comes across it. I also believe that it can be improved upon.
We've made some improvements to the OAuth2 flow for React Native. Moving forward, please set the URL scheme to appwrite-callback-<PROJECT_ID> in your app.json file.
{
"expo": {
"scheme": "appwrite-callback-<PROJECT_ID>"
}
}
Then, create a deep link, pass it to account.createOAuth2Token() method to create the login URL, open the URL in a browser, listen for the redirect, and finally create a session with the secret.
import { Client, Account, OAuthProvider } from "appwrite";
import { makeRedirectUri } from 'expo-auth-session'
import * as WebBrowser from 'expo-web-browser';
const client = new Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<PROJECT_ID>'); // Your project ID
const account = new Account(client);
// Create 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 }));
const scheme = `${deepLink.protocol}//`; // e.g. 'exp://' or 'appwrite-callback-<PROJECT_ID>://'
// Start OAuth flow
const loginUrl = await account.createOAuth2Token(
provider,
`${deepLink}`,
`${deepLink}`,
);
// Open loginUrl and listen for the scheme redirect
const result = await WebBrowser.openAuthSessionAsync(`${loginUrl}`, scheme);
// Extract credentials from OAuth redirect URL
const url = new URL(result.url);
const secret = url.searchParams.get('secret');
const userId = url.searchParams.get('userId');
// Create session with OAuth credentials
await account.createSession(userId, secret);
// Redirect as needed