Social login for native apps

Hey everyone looking for some guidance for native apps and social signin. My app is built using capacitor. On my signin page I capture the redirect by running the following
const { data } = await authClient.signIn.social({
provider,
callbackURL,
disableRedirect: true,
});
const { data } = await authClient.signIn.social({
provider,
callbackURL,
disableRedirect: true,
});
And then open a webview navigating to the redirect. After that the webview does the redirect dance and bounces through the api that sets the cookie, although in the webview, and finally navigates to the callbackURL, which is set to a deep link to my app. Not sure exactly how to solve this, has anyone ran into the same issue and have a solution? Saw there is a expo plugin so will check into the source code and see what is being done there
6 Replies
Omicrxn
Omicrxn2w ago
hey i struggled with that too, using Tauri. However the setup you are describing sounds good, what is the issue?
Sina
SinaOP2w ago
The problem is that the cookie is set in the webview (used for auth). So subsequent calls to get session does not have cookies set since they where set in the auth webview, confusingly capacitor is essentially a webview running a react app not to be confused with the auth webview. Read a bit in the source for the expo plugin and found this block where they intercept the webview once it gets to the callback, and its quite neat but unfortunately the webview capcitor has does not support this feature
const callbackURL = JSON.parse(context.request.body)?.callbackURL;
const to = callbackURL;
const signInURL = context.data?.url;
const result = await Browser.openAuthSessionAsync(signInURL, to);
if (result.type !== "success") return;
const url = new URL(result.url);
const cookie = String(url.searchParams.get("cookie"));
if (!cookie) return;
storage.setItem(cookieName, getSetCookie(cookie));
const callbackURL = JSON.parse(context.request.body)?.callbackURL;
const to = callbackURL;
const signInURL = context.data?.url;
const result = await Browser.openAuthSessionAsync(signInURL, to);
if (result.type !== "success") return;
const url = new URL(result.url);
const cookie = String(url.searchParams.get("cookie"));
if (!cookie) return;
storage.setItem(cookieName, getSetCookie(cookie));
One idea is to do the oidc flow for the provider in the frontend and then use the id token to do the signin against better auth would result in a lot of code, but since I dont have a browser where I can intercept the callback as in the above code I think my options are limited -- not sure if there is a easy way to pass assets such as a cookie in search params or whatever on callbackURL pointing to the app
Omicrxn
Omicrxn2w ago
when you say auth webview, is the same webview from capacitor or an external browser? also what framework are you using?
Sina
SinaOP2w ago
auth webview I mean another browser spawned by the capacitor app by running await Browser.open({ redirectUrl }); framework if you mean our backend its elysia? Our frontend is react and capacitor but from what I briefley read about tauri it looks similar to capacitor how did you solve social? given the redirect url from better auth what do you do after?
Omicrxn
Omicrxn2w ago
yeah so there are two approaches here, one is spawning a server when you start the oauth flow that will be the redirect route but don't recommend it as it's a plugin of tauri and stuff so don't know the equivalent in capacitor. So what you can do is leave the default redirect url and add a middleware that calls a deeplink which comes back to your app if your auth supports deep linking you can also do it directly but some like google don't support it
Sina
SinaOP2d ago
do you have any code to share? Its easier to follow along then, but from what I'm reading I imagine its something along these lines
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/callback")) {
const { responseHeaders } = ctx.context;
const location = responseHeaders?.get("location");
const cookie = responseHeaders?.get("set-cookie");
if (!cookie || !location) return;

if (location?.startsWith("myapp://")) {
const locationUrl = new URL(location);
locationUrl.searchParams.set("cookie", cookie);
}
}
})
after: createAuthMiddleware(async (ctx) => {
if (ctx.path.startsWith("/callback")) {
const { responseHeaders } = ctx.context;
const location = responseHeaders?.get("location");
const cookie = responseHeaders?.get("set-cookie");
if (!cookie || !location) return;

if (location?.startsWith("myapp://")) {
const locationUrl = new URL(location);
locationUrl.searchParams.set("cookie", cookie);
}
}
})
but what do you do with the cookie I guess you have to set it in search then set it via the client, or make a xhr call from the client with some id that sets the cookie For anyone in the future I ended up adding an endpoint where the cookie could be set and passing the cookie via headers. So essentially the flow is like Sign in as normal Point callback to the native app ie deeplink When hitting the native callback use the above code to add set cookie header to the search params Read the search params on the client Here there are two options Set cookie via document.cookie (would not work for capacitor as its not a secure context and we want to have secure cookies) Or Post the cookie via headers to your backend and let the backend set the cookie on the response A bit hacky but it works -- would probably not improve it until better auth adds more native support right now its a bit lacking tbh

Did you find this page helpful?