Next js - Next Auth - Keep having error=OAuthCreateAccount (google provider) - next.js

I have set up next-auth with the GoogleProvider.
Everything works fine locally, however in production, I am having aOAuthCreateAccount error: api/auth/signin?error=OAuthCreateAccount
stating "Try signing in with a different account."
I have provided the ID & Secret of the Provider, I have dropped my DB, tried to log with multiples accounts... I do not understand. Is there something that my production environment is not accessing?
Here's my nextauth.js:
`
import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import CredentialsProvider from "next-auth/providers/credentials";
import { MongoDBAdapter } from "#next-auth/mongodb-adapter";
import clientPromise from "../../../lib/mongodb";
export default NextAuth({
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
}),
// ...add more providers here
],
secret: process.env.NEXTAUTH_SECRET,
// Can custom page & path
pages: {
signOut: "/auth/signout",
error: "/auth/error", // Error code passed in query string as ?error=
verifyRequest: "/auth/verify-request", // (used for check email message)
// newUser: "/auth/new-user", // New users will be directed here on first sign in (leave the property out if not of interest)
newUser: "/recruiter/2", // New users will be directed here on first sign in (leave the property out if not of interest)
},
adapter: MongoDBAdapter(clientPromise),
});
`
And my mongodb.js:
`
import { MongoClient } from "mongodb";
const uri = process.env.MONGODB_URI;
const options = {
useUnifiedTopology: true,
useNewUrlParser: true,
};
let client;
let clientPromise;
if (!process.env.MONGODB_URI) {
throw new Error("Please add your Mongo URI to .env.local");
}
if (process.env.NODE_ENV === "development") {
// In development mode, use a global variable so that the value
// is preserved across module reloads caused by HMR (Hot Module Replacement).
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
// In production mode, it's best to not use a global variable.
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;
`
Thank you!
Read the documentations.
Look on Stackoverflow and github thread, tried all the offered solutions, in vain.

I have managed to fix it reading this thorough article: https://medium.com/geekculture/why-and-how-to-get-started-with-next-auth-61740558b45b
I was missing the database variable in my deployment system (vercel) :)

Related

NextJS Actioncable Proxy

So I'm trying to do two things at the same time and it's not going too well.
I have a NextJS app and a Rails API server this app connects to. For authentication I'm using a JWT token stored in an http-only encrypted cookie that the Rails API sets and the front end should not be touching. Naturally that creates a necessity for the frontend to send all the api requests though the NextJs server which proxies them to the real API.
To do that I have set up a next-http-proxy-middleware in my /pages/api/[...path] in the following way:
export const config = { api: { bodyParser: false, externalResolver: true } }
export default function handler(
req: NextApiRequest,
res: NextApiResponse
) {
httpProxyMiddleware(req, res, {
target: process.env.BACKEND_URL,
pathRewrite: [{ patternStr: "^/?api", replaceStr: "" }],
})
}
Which works great and life would be just great, but turns out I need to do the same thing with ActionCable subscriptions. Not to worry, found some handy tutorials, packed #rails/actioncable into my package list and off we go.
import {useCurrentUser} from "../../../data";
import {useEffect, useState} from "react";
const UserSocket = () => {
const { user } = useCurrentUser()
const [roomSocket, setRoomSocket] = useState<any>(null)
const loadConsumer = async () => {
// #ts-ignore
const { createConsumer } = await import("#rails/actioncable")
const newCable = createConsumer('/api/wsp')
console.log('Cable loaded')
setRoomSocket(newCable.subscriptions.create({
channel: 'RoomsChannel'
},{
connected: () => { console.log('Room Connected') },
received: (data: any) => { console.log(data) },
}))
return newCable
}
useEffect(() => {
if (typeof window !== 'undefined' && user?.id) {
console.log('Cable loading')
loadConsumer().then(() => {
console.log('Cable connected')
})
}
return () => { roomSocket?.disconnect() }
}, [typeof window, user?.id])
return <></>
}
export default UserSocket
Now when I go to load the page with that component, I get the log output all the way to Cable connected however I don't see the Room Connected part.
I tried looking at the requests made and for some reason I see 2 requests made to wsp. First is directed at the Rails backend (which means the proxy worked) but it lacks the Cookie headers and thus gets disconnected like this:
{
"type": "disconnect",
"reason": "unauthorized",
"reconnect": false
}
The second request is just shown as ws://localhost:5000/api/wsp (which is my NextJS dev server) with provisional headers and it just hangs up in pending. So neither actually connect properly to the websocket. But if I just replace the /api/wsp parameter with the actual hardcoded API address (ws://localhost:3000/wsp) it all works at once (that however would not work in production since those will be different domains).
Can anyone help me here? I might be missing something dead obvious but can't figure it out.

How do I read session properties using useSession() in getServerSideProps() using nextjs and next-auth?

I am trying to only show data where the "Heading" is the same as the logged-in user's name. I'm using Next.js and I'm trying to server render the data from my Prisma database, but when I try to filter the data to only show "Segments" where the "Heading" is the same as the currently logged-in user it throws an error:
Server Error
TypeError: Cannot read properties of null (reading 'useContext')
I am using Next-Auth for user authentication and previously I have use this method to access the currently logged in user's data:
import { useSession } from "next-auth/react";
.
.
.
const { data: session } = useSession();
.
.
.
<div>User name: {session.user.name}</div>
But when I use getServerSideProps() that method doesn't work.
This is what I tried so far:
export async function getServerSideProps() {
const { data: session } = useSession();
const segments: Segment[] = await prisma.segment.findMany({
where: {
Heading: session.user.name,
},
});
return {
props: {
initialSegments: segments,
},
};
}
But it shows me the error shown above.
useSession is unavailable on the server side according to next-auth's docs.
You may be able to use unstable_getServerSession(), however do note that it's experimental and its API may change in the future (as noted in the docs).

NextJs - Apollo - First render is not SSR

I am using NextJs(9.3.0) for SSR and graphQL (Apollo).
My app is working well, but when I check what google is seeing, the data from Apollo are not available
If I am doing a curl https://myWebsite.com randomly, I have sometime the content (like google) without the data from Apollo, and sometimes with the data from Apollo.
For SEO purpose, I need to always have the first render (after a refresh) with the data given buy my Backend (Apollo)
Here is my file: apolloClient.tsx
import { ApolloClient } from "apollo-client";
import { AUTH_TOKEN } from "./config";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
import Cookies from "js-cookie";
import fetch from "isomorphic-unfetch";
import nextCookies from "next-cookies";
import { uriBackend } from "./config";
let token = null;
export default function createApolloClient(initialState, ctx) {
// The `ctx` (NextPageContext) will only be present on the server.
// use it to extract auth headers (ctx.req) or similar.
// on server
if (ctx && ctx.req && ctx.req.headers["cookie"]) {
token = nextCookies(ctx)[AUTH_TOKEN];
// on client
} else {
// console.log("with data get client cookie");
token = Cookies.get(AUTH_TOKEN);
}
const headers = token ? { Authorization: `Bearer ${token}` } : {};
return new ApolloClient({
ssrMode: Boolean(ctx),
link: new HttpLink({
uri: uriBackend, // Server URL (must be absolute)
fetch,
headers
}),
cache: new InMemoryCache().restore(initialState)
});
}
Looks to me like your SSR doesn't wait for the data fetching.
One solution for you could be, if your data changes rarely, to staticelly generate you pages with data:
https://nextjs.org/docs/basic-features/pages#scenario-1-your-page-content-depends-on-external-data
If you use SSR, make sure you use an async getServerSideProps that awaits your data requests:
https://nextjs.org/docs/basic-features/pages#server-side-rendering

Next.js returns 500: internal server error in Production

Created a next.js full stack application. After production build when I run next start it returns 500 : internal server. I'm using environment varibles for hitting api.
env.development file
BASE_URL=http://localhost:3000
It was working fine in development
service.ts
import axios from 'axios';
const axiosDefaultConfig = {
baseURL: process.env.BASE_URL, // is this line reason for error?
headers: {
'Access-Control-Allow-Origin': '*'
}
};
const axio = axios.create(axiosDefaultConfig);
export class Steam {
static getGames = async () => {
return await axio.get('/api/getAppList');
};
}
Do you have a next.config.js file?
To add runtime configuration to your app open next.config.js and add the publicRuntimeConfig and serverRuntimeConfig configs:
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // Pass through env variables
},
publicRuntimeConfig: {
// Will be available on both server and client
staticFolder: '/static',
},
}
To get access to the runtime configs in your app use next/config, like so:
import getConfig from 'next/config'
// Only holds serverRuntimeConfig and publicRuntimeConfig
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()
// Will only be available on the server-side
console.log(serverRuntimeConfig.mySecret)
// Will be available on both server-side and client-side
console.log(publicRuntimeConfig.staticFolder)
function MyImage() {
return (
<div>
<img src={`${publicRuntimeConfig.staticFolder}/logo.png`} alt="logo" />
</div>
)
}
export default MyImage
I hope this helps.
I dont think you have setup env.
You need to configure it for it to work. Try it without it and it should work fine!

Disable AccountChooser for Firebase Auth

I'm trying the new FirebaseUI for Web (https://github.com/firebase/FirebaseUI-Web). But when I tried to login with Email, it redirects me to an AccountChooser website.
Is there anyway that I can turn off that AccountChooser?
Thanks
You can disable by adding an entry into the variable uiConfig in Firebase. You have to add this in the uiConfig variable:
'credentialHelper': firebaseui.auth.CredentialHelper.NONE
Here is an example of it inside uiConfig:
var uiConfig = {
callbacks: {
signInSuccess: function (currentUser, credential, redirectUrl) {
return true;
},
uiShown: function () {
document.getElementById('loader').style.display = 'none';
}
},
//Start it here
credentialHelper: firebaseui.auth.CredentialHelper.NONE,
//End it here
signInFlow: 'popup',
signInSuccessUrl: '<url-to-redirect-to-on-success>',
signInOptions: [
// Leave the lines as is for the providers you want to offer your users.
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
firebase.auth.FacebookAuthProvider.PROVIDER_ID,
firebase.auth.TwitterAuthProvider.PROVIDER_ID,
firebase.auth.EmailAuthProvider.PROVIDER_ID
],
// Terms of service url.
tosUrl: '<your-tos-url>'
};
var ui = new firebaseui.auth.AuthUI(firebase.auth());
ui.start('#firebaseui-auth-container', uiConfig);
If anyone isn't bringing in firebaseui (e.g. if you're using react-firebaseui), it could be helpful know thatfirebaseui.auth.CredentialHelper.NONE === 'none'
This answer was provided in this SO question: Disable account chooser FirebaseUI React
Credit to #RafikTighilt and #JeffBergman
I am using /__/firebase/init.js and no explicit initialization and getting
firebaseui not initialized on ,'credentialHelper': firebaseui.auth.CredentialHelper.NONE
Solution, change the order of the statements:
var ui = new ...
var uiConfig = { ...
ui.start('#firebaseui-auth-container', uiConfig);
Found a fix for this here:
https://github.com/firebase/firebaseui-web/issues/42
Download the firebase-ui-auth.js file (you can copy version 0.5 from here). You need to change one character and host the file yourself instead of using the CDN.
In the file, look for: "accountChooserEnabled",!0 and change the !0 to !1.
This did the trick for me!

Resources