Mono-repo with GenericOAuth Plugin

Hey encountering an issue im struggling to get around. I have a generic oauth config setup that authenticates correctly, creates the users and sesison in the DB etc so the server pathway seems okay. But when I trigger the sign in from my front-end vite app (port 3001) with the callback of '/dashboard' after succesful login it redirects me to the hono api (port 3000) '/dashboard' instead. I've setup the trustedOrigins to be http://localhost:3001 right now in development - is there something else im missing with redirect config back to the better-auth client?
Solution:
actually scratch that - just put full url in the callback url ```ts await authClient.signIn.oauth2({ providerId: "generic-sso",...
Jump to solution
13 Replies
!TS JORDAN
!TS JORDANOP5d ago
server config:
import { betterAuth, type BetterAuthOptions } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import prisma from "@acme/db";
import { genericOAuth } from "better-auth/plugins";
import axios from "axios";

export const auth = betterAuth<BetterAuthOptions>({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
trustedOrigins: [process.env.CORS_ORIGIN || ""],
user: {
additionalFields: {
permissions: {
type: "string",
required: true,
},
},
},
plugins: [
genericOAuth({
config: [
{
providerId: "generic-oauth",
clientId: <id>,
clientSecret: <secret>,
authorizationUrl: <auth_url>,
tokenUrl: <token_url>,
tokenUrlParams: {
client_id: <client_id>,
client_secret: <client_secret>,
},
getUserInfo: async (token) => {
var res = await axios.post(`https://<login_server>/auth/sso/user?oauth_token=${token.accessToken}`);
return res.data;
},
mapProfileToUser(profile) {
return {
id: profile.id,
name: profile.info.first_name + " " + profile.info.last_name,
email: profile.info.email,
company_id: profile.info.company_id,
company_name: profile.info.company_name,
};
},
},
],
}),
],
advanced: {
defaultCookieAttributes: {
sameSite: "none",
secure: true,
httpOnly: true,
},
},
});
import { betterAuth, type BetterAuthOptions } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import prisma from "@acme/db";
import { genericOAuth } from "better-auth/plugins";
import axios from "axios";

export const auth = betterAuth<BetterAuthOptions>({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
trustedOrigins: [process.env.CORS_ORIGIN || ""],
user: {
additionalFields: {
permissions: {
type: "string",
required: true,
},
},
},
plugins: [
genericOAuth({
config: [
{
providerId: "generic-oauth",
clientId: <id>,
clientSecret: <secret>,
authorizationUrl: <auth_url>,
tokenUrl: <token_url>,
tokenUrlParams: {
client_id: <client_id>,
client_secret: <client_secret>,
},
getUserInfo: async (token) => {
var res = await axios.post(`https://<login_server>/auth/sso/user?oauth_token=${token.accessToken}`);
return res.data;
},
mapProfileToUser(profile) {
return {
id: profile.id,
name: profile.info.first_name + " " + profile.info.last_name,
email: profile.info.email,
company_id: profile.info.company_id,
company_name: profile.info.company_name,
};
},
},
],
}),
],
advanced: {
defaultCookieAttributes: {
sameSite: "none",
secure: true,
httpOnly: true,
},
},
});
client config:
import type { auth } from "@acme/auth";
import { createAuthClient } from "better-auth/react";
import { genericOAuthClient, inferAdditionalFields } from "better-auth/client/plugins";

export const authClient = createAuthClient({
baseURL: import.meta.env.VITE_SERVER_URL,
plugins: [inferAdditionalFields<typeof auth>(), genericOAuthClient()],
});
import type { auth } from "@acme/auth";
import { createAuthClient } from "better-auth/react";
import { genericOAuthClient, inferAdditionalFields } from "better-auth/client/plugins";

export const authClient = createAuthClient({
baseURL: import.meta.env.VITE_SERVER_URL,
plugins: [inferAdditionalFields<typeof auth>(), genericOAuthClient()],
});
signin trigger:
await authClient.signIn.oauth2({
providerId: "generic-oauth",
callbackURL: '/dashboard'
});
await authClient.signIn.oauth2({
providerId: "generic-oauth",
callbackURL: '/dashboard'
});
VITE_SERVER_URL = "http://localhost:3000" -> my hono server @Better Auth
Better Auth
Better Auth5d ago
Hi there! I’ve noticed a few common questions in our community regarding Better Auth. Here’s an aggregated summary with some tips and best practices: 1. Discord Consent & Prompt Options
Many users have discussed controlling the consent prompt for Discord logins. There was a feature to add a consent option so that the OAuth prompt can be set to "none" by default, minimizing re-authorization prompts [1], [16]. This can provide a smoother login experience similar to the GitHub provider. 2. Bot Permissions with Discord OAuth
For those looking to integrate Discord bot capabilities, Better Auth now supports an optional permissions parameter when using the bot scope. This was introduced to allow specifying Discord bot permissions during the OAuth flow, making it easier to configure bot functionalities simply by setting the proper parameter [5], [6]. 3. Privacy Concerns Around Email
Some community members have raised privacy issues with collecting real email addresses via Discord OAuth. To address this, there’s now an option to replace the real email with a dummy address to alleviate concerns while still using the provider [11]. This way, users can enjoy the convenience without exposing their sensitive data. 4. Redirect URI and URL Validity
There have been discussions about invalid redirect URIs generated by Better Auth, particularly around the need for a specific prefix that Discord requires (the "++" prefix). The team has addressed this to ensure that the OAuth URLs generated meet Discord’s requirements, avoiding errors like “Invalid OAuth2 redirect_uri”
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
Build software better, together
GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.
From An unknown user
From An unknown user
From An unknown user
GitHub
Build software better, together
GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.
From An unknown user
From An unknown user
From An unknown user
Better Auth
Better Auth5d ago
[13]. 5. Profile Hooks & Image Updates
Some developers want to update user profile images on each login (e.g., when their Discord avatar changes). While the default flow stores the profile image on creation, you might need to implement custom profile hooks (see the proposal in document [20]) to keep user images in sync. Document [21] also highlights related inquiries about image updates. 6. Handling OAuth Errors
Errors like the state_mismatch have been noted, which typically indicate a configuration or synchronization issue in the OAuth flow [14]. Double-checking your settings and ensuring that all parameters (such as client IDs, secrets, and redirect URIs) are correctly configured can help avoid such issues. These insights are grounded in our ongoing discussions and the recent updates and pull requests. I hope this helps clarify some common topics! Is there a specific part of your Better Auth configuration you’d like to dive deeper into or any particular issue you’re facing right now?
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
Updating Discord image everytime the user logs in. · Issue #2016 ...
I was trying to do something which I think is fairly simple in theory : I want the user&#39;s profile picture to update when they log in. The user may change his profile picture, which will make th...
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
Better Auth
Better Auth5d ago
GitHub
feat(discord): add consent as an option by Bekacru · Pull Request ...
closes #739 adds a consent option to Discord, defaulting to none as suggested in the linked issue.
GitHub
feat: add Discord bot permissions parameter support by TheUntraceab...
When using the Discord social plugin, you can set the bot scope, and this scope can have an additional permissions scope, referring to the permissions of the Discord Bot once authorized. This pull ...
GitHub
feat(discord): allow specification of permissions by TheUntraceable...
Reopening of #3163 as I was told it was closed by mistake. Summary by cubic Adds a new permissions option to the Discord provider so apps can request specific bot permissions during OAuth. Update...
GitHub
feat:Add Discord OAuth email scope configuration field by Summerlyt...
Collecting the real email address is a privacy concern. By implementing this simple fix, it allows users to replace said address with a dummy address easily. I understand you can write over the ema...
GitHub
Discord OAuth redirect_uri requires double plus signs (++) prefix -...
Is this suited for github? Yes, this is suited for github To Reproduce Create Expo app with Better Auth Configure Better Auth with Discord OAuth provider Set redirect URL in Discord Developer Dashb...
!TS JORDAN
!TS JORDANOP5d ago
@Better Auth how do i setup generic oauth on different front-end back-end domains, currrently my betterauth server keep redirecting to localhost:3000/dashboard (server) instead of localhost:3001/dashboard (frontend) - ive tried updating my .signIn to have a callback url of localhost:3001/dashboard but no luc
Better Auth
Better Auth5d ago
It sounds like your Better Auth instance is defaulting the redirect to the backend’s base URL rather than your frontend. This behavior is similar to what was reported in one of our GitHub issues where the callbackURL wasn’t correctly applied [1]. One approach to resolve this is to use the OAuth Proxy plugin. By adding the proxy to your auth config and specifying the productionURL (in your case, set it to http://localhost:3001), Better Auth will use that to correctly form your callback destination [2]. For example, in your auth.ts you can add:
import { betterAuth } from "better-auth";
import { oAuthProxy } from "better-auth/plugins";

export const auth = betterAuth({
plugins: [
oAuthProxy({
productionURL: "http://localhost:3001",
currentURL: "http://localhost:3000",
}),
],
});
import { betterAuth } from "better-auth";
import { oAuthProxy } from "better-auth/plugins";

export const auth = betterAuth({
plugins: [
oAuthProxy({
productionURL: "http://localhost:3001",
currentURL: "http://localhost:3000",
}),
],
});
This should lead to your signin flow redirecting to http://localhost:3001/dashboard as expected. Have you had a chance to try configuring the OAuth Proxy plugin with these settings? Sources: [1] callbackURL does not work, google sign in [2] OAuth Proxy | Better Auth — Better Auth is powered by https://clarm.com
GitHub
better-auth/better-auth
The most comprehensive authentication framework for TypeScript - better-auth/better-auth
GitHub
callbackURL does not work, google sign in · Issue #3407 · better-...
Is this suited for github? Yes, this is suited for github To Reproduce use better-t-stack to create a monorepo with tanstack-start/hono/drizzle add google social provider add button with google soc...
!TS JORDAN
!TS JORDANOP5d ago
@Better Auth oauthproxy still redirects to after signin http://localhost:3000/dashboard
Better Auth
Better Auth5d ago
It sounds like your OAuthProxy is still redirecting to the localhost URL (http://localhost:3000/dashboard) after sign-in rather than the intended production URL. In Better Auth, the OAuthProxy plugin relies on the proper configuration of both the productionURL option and the redirect details in your social provider settings. For example, the documentation recommends setting the plugin like this:
oAuthProxy({
productionURL: "https://my-main-app.com", // Proper production URL
currentURL: "http://localhost:3000", // Used as fallback if needed
})
oAuthProxy({
productionURL: "https://my-main-app.com", // Proper production URL
currentURL: "http://localhost:3000", // Used as fallback if needed
})
and then configuring your social provider with the correct redirectURI (not callbackURL) as shown in the docs [1]. Additionally, make sure that when you initiate the sign in, you use the callbackURL option (which should match your production app’s intended entry point) as described in the documentation update [11]. Could you check if your auth configuration includes the correct productionURL and that your social provider’s redirectURI is set to your production domain rather than localhost? Let me know what your current settings are, or if you’d like to tag @bekacru or @ping__ for more detailed troubleshooting! Sources: [1] OAuth Proxy | Better Auth [11] fix oauth-proxy docs - redirectURL — Better Auth is powered by https://clarm.com
GitHub
Build software better, together
GitHub is where people build software. More than 150 million people use GitHub to discover, fork, and contribute to over 420 million projects.
From An unknown user
From An unknown user
From An unknown user
OAuth Proxy | Better Auth
OAuth Proxy plugin for Better Auth
GitHub
fix oauth-proxy docs - redirectURL by rychlis · Pull Request #1322...
docs mention redirectURL in both socialProviders option and authClient.signIn.social call which don&amp;#39;t exist. Fixing this by using redirectURI for socialProviders and callbackURL for client ...
!TS JORDAN
!TS JORDANOP5d ago
temporary workaround is to setup a redirect in the server for the callback route and push it to the FE]
Ata Sanchez
Ata Sanchez3d ago
@!TS JORDAN did you find a solution to your problem? I have the same issue
!TS JORDAN
!TS JORDANOP3d ago
@Ata Sanchez I had to just create a route on the hono server side that handled the redirect to the front-end callback In my case I was passing callbackurl as /dashboard to I created a hono route to redirect to process.env.frontend/dashboard and it worked
Solution
!TS JORDAN
!TS JORDAN3d ago
actually scratch that - just put full url in the callback url
await authClient.signIn.oauth2({
providerId: "generic-sso",
callbackURL: "http://localhost:3001/dashboard",
});
await authClient.signIn.oauth2({
providerId: "generic-sso",
callbackURL: "http://localhost:3001/dashboard",
});
Ata Sanchez
Ata Sanchez3d ago
Thanks!

Did you find this page helpful?