-
Question 💬Hello, and a huge thanks for the work on this library. My question is quite simple, but I already wasted a lot of time on it, lost in documentations. The use case is simply that I need the refresh token issued by Google, to use API with it. I understand that I will probably need a way to store in database on first connection, but I don't quite get something. When I connect with google with debug, I got this log (obviously not the XXX, but I receive the refresh token) [next-auth][debug][oauth_callback_response] {
account: {
provider: 'google',
type: 'oauth',
id: 'XXXXXXXXXXX',
accessToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
accessTokenExpires: null,
refreshToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
{...} // and more
}, What I would like is get this refreshToken value. What I tried is use the jwt callback
But it looks like this callback is never called, I also tried to get it from the session callback, but could not extract it from it as well. What am I missing here? How to reproduce ☕️"next-auth": "3.27.3" [next-auth][debug][oauth_callback_response] {
account: {
provider: 'google',
type: 'oauth',
id: 'XXXXXXXXXXX',
accessToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
accessTokenExpires: null,
refreshToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
{...} // and more
},
Contributing 🙌🏽Yes, I am willing to help answer this question in a PR |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 4 replies
-
since refresh tokens are very powerful, you might want to use a database instead, to persist it, but at the very minimum you should NEVER expose it to the client and encrypt the jwt. https://next-auth.js.org/configuration/options#jwt without seeing your code, it's hard to tell why it doesn't work, but if I had to guess, you might have already configured an adapter, which means the jwt callback won't be used. |
Beta Was this translation helpful? Give feedback.
-
Hey @balazsorban44, I found the solution myself after a lot of research. I post it here if that can help somebody. The prisma adapter is generating an Account entity, with the refreshToken and accessToken stored in it, but to use an API you have to add the good scopes to the Google Provider. Here's an example to use create a Google event for the user: import NextAuth from "next-auth";
import Providers from "next-auth/providers";
import Adapters from "next-auth/adapters";
import prisma from "../../../lib/prisma";
const scopes = [
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
];
const authorizationUrl = new URL(
"https://accounts.google.com/o/oauth2/v2/auth"
);
authorizationUrl.searchParams.set("prompt", "consent");
authorizationUrl.searchParams.set("access_type", "offline");
authorizationUrl.searchParams.set("response_type", "code");
export default NextAuth({
providers: [
Providers.Google({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
authorizationUrl: authorizationUrl.toString(),
scope: scopes.join(" "),
}),
],
adapter: Adapters.Prisma.Adapter({ prisma }),
debug: process.env.NODE_ENV === "development",
secret: process.env.SECRET,
database: process.env.DATABASE_URL,
}); And here is an example of how to call a Google API with that import { getSession } from "next-auth/client";
import { google } from "googleapis";
import prisma from "../../lib/prisma";
import { Account } from "@prisma/client";
export default async function handle(req, res) {
var event = {
summary: "Google I/O 2022",
location: "800 Howard St., San Francisco, CA 94103",
description: "A chance to hear more about Google's developer products.",
start: {
dateTime: "2022-05-28T09:00:00-07:00",
timeZone: "America/Los_Angeles",
},
end: {
dateTime: "2022-05-28T17:00:00-07:00",
timeZone: "America/Los_Angeles",
},
recurrence: ["RRULE:FREQ=DAILY;COUNT=2"],
attendees: [
{ email: "[email protected]" },
],
reminders: {
useDefault: false,
overrides: [
{ method: "email", minutes: 24 * 60 },
{ method: "popup", minutes: 10 },
],
},
};
const session = await getSession({ req });
if (!session) {
res.status(401);
}
const clientId = process.env.GOOGLE_CLIENT_ID;
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
const account: Account = await prisma.account.findUnique({
where: {
id: 1,
},
});
const auth = new google.auth.OAuth2({
clientId,
clientSecret,
});
auth.setCredentials({
access_token: account.accessToken,
refresh_token: account.refreshToken,
});
const calendar = google.calendar({
auth,
version: "v3",
});
const data = await calendar.events.insert({
calendarId: "primary",
requestBody: event,
});
res.json("hello");
} |
Beta Was this translation helpful? Give feedback.
Hey @balazsorban44, I found the solution myself after a lot of research. I post it here if that can help somebody.
The prisma adapter is generating an Account entity, with the refreshToken and accessToken stored in it, but to use an API you have to add the good scopes to the Google Provider.
Here's an example to use create a Google event for the user: