I created a google oauth strategy with passport, I added it to payload and in the login everything works well (you can login, generate a token, and the token is set to the payload-token http-only cookie) but in the admin panel I can't access, also, the api isn't working, i'm getting this error in the console for the admin
My users collection:
import GoogleStrategy from "../auth/google";
import finalise from "../auth/jwt";
import passport from "passport";
const Users = {
slug: "users",
auth: {
tokenExpiration: 60 * 60 * 24 * 7, // 1 week
verify: true,
maxLoginAttempts: 5,
lockTime: 600 * 1000,
useAPIKey: true,
strategies: [
{
name: "google",
strategy: GoogleStrategy,
},
],
},
endpoints: [
{
path: "/google",
method: "get",
handler: async (req, res) => {
passport.authenticate("google", {
scope: ["profile", "email"],
})(req, res);
},
},
{
path: "/google/callback",
method: "get",
handler: async (req, res) => {
req.payload.authenticate(req, res, () => {
if (req?.user) {
const final = finalise(req, res);
return final.res.status(200).send({ token: final.token });
}
return res.status(401).send({ message: "Unauthorized" });
});
},
},
],
};
export default Users;
the google strategy:
import payload from "payload";
import Strategy from "passport-google-oauth20";
import { v4 as uuidv4 } from "uuid";
import { Forbidden, LockedAuth } from "payload/errors";
require("dotenv").config();
const GoogleStrategy = new Strategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/api/users/google/callback",
scope: ["profile", "email"],
},
async (accessToken, refreshToken, profile, done) => {
const { emails } = profile;
const email = emails[0]?.value;
if (!email) {
done(Forbidden, false);
}
try {
let user = await payload.find({
collection: "users",
where: {
email: {
equals: email,
},
},
});
if (user?.totalDocs > 0) {
user = user.docs[0];
}
const isLocked = (date) => !!(date && date > Date.now());
if (user && isLocked(user.lockUntil)) {
throw new LockedAuth();
}
if (user?.totalDocs < 1) {
user = await payload.create({
collection: "users",
data: {
email,
password: uuidv4(),
avatar: "1",
_verified: true,
},
disableVerificationEmail: true,
});
}
if (user) {
user.collection = "users";
user._strategy = "google";
done(null, user);
} else {
done(null, false);
}
} catch (e) {
done(e, false);
}
}
);
export default GoogleStrategy;
token:
import jwt from "jsonwebtoken";
const finalise = (req, res) => {
let user = req.user;
user = JSON.parse(JSON.stringify(user));
user = sanitizeInternalFields(user);
const collections = req.payload.collections;
const userCollection = collections[req.payload.config.admin.user];
const collectionConfig = userCollection.config;
const fieldsToSign = getFieldsToSign(collectionConfig, user);
const token = jwt.sign(fieldsToSign, req.payload.secret, {
expiresIn: collectionConfig.auth.tokenExpiration,
});
const cookieOptions = {
path: "/",
httpOnly: true,
expires: getCookieExpiration(collectionConfig.auth.tokenExpiration),
secure: collectionConfig.auth.cookies.secure,
sameSite: collectionConfig.auth.cookies.sameSite,
domain: undefined,
};
if (collectionConfig.auth.cookies.domain) {
cookieOptions.domain = collectionConfig.auth.cookies.domain;
}
res.cookie(`payload-token`, token, cookieOptions);
req.user = user;
return { req, res, token };
};
export default finalise;
any ideas?
have you set all the relevant origins and callbacks in cloud console?
make sure to add both localhost and localhost:3100 in your case
and by the way, I updated the google-one-tap plugin yesterday so it should work out the box now
how to use it for auth from client?
Its not built for auth from client, just as an auth for payloadcms admin. Auth from client depends a lot on what client but you should be able to quite easily copy the code in my repo and make the necessary adjustments. The main difference would be that I save the jwt token using payloads setToken useAuth whereas you would be wanting to do similar client side:
oh thank you, I made a little fork for my project
@7wonders any toughs on this?
Sorry, been offline a bunch. Have you got the
app.use(express.json())
yes, but it stills not work
Now the problem is when an account does not exits resolves with a 401 code
@7wonders I think i got the problem
seems like the plugin cannot access to accounts that are not created yet
so you can't cerate an account in payload using this method
any thougs in how can i make that?
As soon as I add this plugin to payload, the application does not compile:
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
Any change we can peek inside the
sanitizeInternalFields, getFieldsToSign and getCookieExpiration
functions?
@ScriptDroid was your initial problem solved by entering all origins & callbacks in the cloud console?
@7wonders do you have any suggestions what else might be the problem if I can't access the admin panel? I made sure the URLs are set in the google console. (and once I open any api route in the browser it redirects me to the google sign-up form)
Really sorry, I havent been very active the last couple of months. I will see if I can check the plugins out this week and get some updating done.
But remember that its completely open source so you are welcome to submit pull requests with fixes 🙂
Star
Discord
online
Get help straight from the Payload team with an Enterprise License.