How do I setup bearer auth for social logins?

As I understand the current bearer docs are only for email/password sign ins, right? How do I setup and save bearer tokens in the client when the user signs in via social login ? I have a basic hono api, and a react spa. Both are on different subdomains so I can’t use cookies for session easily. Also the cors is giving me a nightmare lmao. Anyways, so I’m trying to use bearer based auth but I don’t how to setup for social logins. What I would imagine should happen is that my hono api redirects me to my callback url with the code in the url which I can then store when my spa boots up. Does it make sense? I realize there might be security issues with this and I should prefer cookies but this is just a toy project of mine.
11 Replies
shahreaz
shahreaz7d ago
I have this same issue @bekacru I need the solution very badly @roguesherlock hey man. Have you been able to find a solution??
lonelyplanet
lonelyplanet7d ago
The docs show an EXAMPLE of email password sign in but the concept is the same for all signing in. the bearer plugin is simply adding two hooks before any request is sent to the endpoint it basically transforms the authorization header into a cookie so the server reads the cookie. and after hook which does the reversed takes when the endpoint tries to set a cookie grabs it and instead sends it as a header
lonelyplanet
lonelyplanet7d ago
on any request that is sending a session token grab it with a onSuccess callback passed into the call options and the ctx arg:
onSuccess: (ctx)=>{
const authToken = ctx.response.headers.get("set-auth-token") // get the token from the response headers
// Store the token securely (e.g., in localStorage)
localStorage.setItem("bearer_token", authToken);
}
onSuccess: (ctx)=>{
const authToken = ctx.response.headers.get("set-auth-token") // get the token from the response headers
// Store the token securely (e.g., in localStorage)
localStorage.setItem("bearer_token", authToken);
}
@shahreaz @roguesherlock
shahreaz
shahreaz7d ago
I will use only REST APIs in frontend
lonelyplanet
lonelyplanet7d ago
That should work after the response is recieved from your call you can just get the header set-auth-token whether it be a fetch() call instead or using the authClient just get the header from it set-auth-token
shahreaz
shahreaz5d ago
on successful login with google oauth. it redirects me to the redirect URI and sets a token on http-only cookie. there is no set-auth-token.
No description
No description
shahreaz
shahreaz5d ago
the callback uri called by google. so there is no authorization header. so it will fail the matcher
No description
lonelyplanet
lonelyplanet5d ago
Your might need to use a hook that after signin you grab the cookie its trying to set use the bearer token plugin source as reference how to do this and set to set-auth-token header and redirect the user to a custom endpoint where you can use that bearer either using js to set to local storage or use it server side somehow
pltoledo
pltoledo5d ago
@lonelyplanet can you elaborate on this custom injection of the set-auth-token header? I am fairly new to Javascript and am facing this issue as well I actually tried to add a hook to the authentication service in the backend, but the .responseHeaders prop is not present in the context:
betterAuth({
plugins: [openAPI({ path: "/docs" }), bearer()],
database: drizzleAdapter(database, {
provider: "pg",
schema: { user, session, verification, account },
}),
trustedOrigins: trustedOrigins,
basePath: `${process.env.API_BASE_PATH}/auth`,
emailAndPassword: {
enabled: true,
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
hooks: {
after: createAuthMiddleware(async (ctx) => {
console.log(ctx.path);
if (ctx.path.startsWith("/callback")) {
// the bewlow line returns undefined
console.log(ctx.context.responseHeaders);
const setCookie = ctx.context.responseHeaders?.get("set-cookie");
console.log(setCookie);
if (!setCookie) {
return;
}
const parsedCookies = parseSetCookieHeader(setCookie);
const cookieName = ctx.context.authCookies.sessionToken.name;
const sessionCookie = parsedCookies.get(cookieName);
if (
!sessionCookie ||
!sessionCookie.value ||
sessionCookie["max-age"] === 0
) {
return;
}
const token = sessionCookie.value;
ctx.setHeader("set-auth-token", token);
ctx.setHeader("Access-Control-Expose-Headers", "set-auth-token");
}
}),
},
});
betterAuth({
plugins: [openAPI({ path: "/docs" }), bearer()],
database: drizzleAdapter(database, {
provider: "pg",
schema: { user, session, verification, account },
}),
trustedOrigins: trustedOrigins,
basePath: `${process.env.API_BASE_PATH}/auth`,
emailAndPassword: {
enabled: true,
},
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
hooks: {
after: createAuthMiddleware(async (ctx) => {
console.log(ctx.path);
if (ctx.path.startsWith("/callback")) {
// the bewlow line returns undefined
console.log(ctx.context.responseHeaders);
const setCookie = ctx.context.responseHeaders?.get("set-cookie");
console.log(setCookie);
if (!setCookie) {
return;
}
const parsedCookies = parseSetCookieHeader(setCookie);
const cookieName = ctx.context.authCookies.sessionToken.name;
const sessionCookie = parsedCookies.get(cookieName);
if (
!sessionCookie ||
!sessionCookie.value ||
sessionCookie["max-age"] === 0
) {
return;
}
const token = sessionCookie.value;
ctx.setHeader("set-auth-token", token);
ctx.setHeader("Access-Control-Expose-Headers", "set-auth-token");
}
}),
},
});
roguesherlock
roguesherlockOP3d ago
sorry I have not worked with this in a while, I think i ended up not using better auth. iirc better auth's bearer token wasn't a standalone authentication mechansim, rather a nice to have for the existing session based auth. And so you still have to go through session based login flow first to create a session, I think that's where I was having trouble with cause both my api and frontend were hosted on different domains.

Did you find this page helpful?