I am interested in the best-practice/current best solution for querying graphql APIs from nextjs + auth0. The current documentation specifies proxying your external API requests in a local /api query request once accessing the access_token with getSession(req). This is difficult for several reasons and I feel like a simpler solution.
Ideally, nextjs+auth0 would be able to offer an access_token to attach to external API requests.
Currently, I am tempted to attach the cookie to each request by setting the cookie domain to include sub-domains. If I do this, however, the server will then require Auth0 setup (to decode the cookie attached and use getSession()) and I will not be able to simply verify JWT tokens.
Any input on the matter would be greatly appreciated and I believe would be highly regarded as many setups are pushing to use Next.js + Graphql APIs on the backed. Looking forward to hearing any further suggestions.
Thanks!
I published a template that handle such scenario (auth0 + nextjs + apollo client). Maybe my approach will be good enough for your use case.
Currently, I am using a custom fetch before each request that pulls from /api/getToken to get the accessToken and attaches it to Authorization header.
If anyone comes up with a better method, I'd love to hear it.
Thanks!
https://gist.github.com/BryceAMcDaniel/a710afe4fd877a04e55a921e4e74a21c
@BryceAMcDaniel you can just do:
const { accessToken } = await auth0.getSession(ctx.req)
@BjoernRave
Hey there thanks for the reply!
I didn't make it very clear in my issue, but the issue only arises on next.js after the initial load and making subsequent actions from there like using router links (at this point, you don't have access to the req object and therefore no cookie).
Because the cookie is http-only, I can not access the cookie from code.
Currently, when running server-side, I currently do use the req object to simply pull the user session from the req.cookie, but when the req object doesn't exist, the above gist pulls session from a /api/getSession request.
Hey! Thanks for all the useful information!
Tried it out but I can't seem to get an accessToken back with the rest of the user information, is there something obvious I'm missing here?
@Miz85 Hey I'm not sure what your setup looks like, but it may be that you need to save the accessToken in the Auth0 config settings.
import { initAuth0 } from '@auth0/nextjs-auth0';
export default initAuth0({
domain: '<AUTH0_DOMAIN>'
clientId: '<AUTH0_CLIENT_ID>',
clientSecret: '<AUTH0_CLIENT_SECRET>',
audience: 'https://api.mycompany.com/',
scope: 'openid profile',
redirectUri: 'http://localhost:3000/api/callback',
postLogoutRedirectUri: 'http://localhost:3000/',
session: {
cookieSecret: '<RANDOMLY_GENERATED_SECRET>',
cookieLifetime: 60 * 60 * 8,
cookieDomain: 'https://mycompany.com',
storeAccessToken: true // <--- This is the important bits
}
});
For reference: https://github.com/auth0/nextjs-auth0#calling-an-api
yeah I litterally just realized that! Thank you so much for your help!
just another question, regarding graphql. Is anyone of you by any chance using graphql-shield on their server?
Yep!
Working on the repo now that will have a prisma2 api server with graphql shield.
Using next js and Apollo on the front end!
@BryceAMcDaniel ah cool, I am working on the same thing. Only difference is I use urql on the frontend :D Is it by any change an open source project?
@BryceAMcDaniel @BjoernRave so you guys are just manually fetching access token from the server every time you make graphql request?
@serendipity1004 Yea, in the beginning I was just fetching the accessToken every time I did a request, but then I created a proxy api server, which adds the accesstoken to the request like this:
import { GraphQLClient } from 'graphql-request'
import auth0 from 'lib/auth0'
import { NextApiRequest, NextApiResponse } from 'next'
export default async (req: NextApiRequest, res: NextApiResponse) => {
try {
const tokenCache = await auth0().tokenCache(req, res)
const { accessToken } = await tokenCache.getAccessToken()
const graphQLClient = new GraphQLClient(
`${process.env.BACKEND_URL}/api/graphql`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
)
const response = await graphQLClient.rawRequest(
req.body.query,
req.body.variables
)
res.status(200).send(response)
} catch (error) {
console.error(error)
res.status(error.status || 500).end(error.message)
}
}
but eventually I moved my backend into an api route to reduce latency and everything works quite well for me. It looks something like this:
import { ApolloServer } from 'apollo-server-micro'
import { applyMiddleware } from 'graphql-middleware'
import cors from 'micro-cors'
import { NextApiRequest, NextApiResponse } from 'next'
import auth0 from '../../lib/auth0'
import { createContext } from '../../prisma/context'
import { permissions } from '../../prisma/permissions'
import { schema } from '../../prisma/schema'
require('dotenv').config()
const attachAccessToken = async (req: NextApiRequest, res: NextApiResponse) => {
try {
const tokenCache = auth0(req).tokenCache(req, res)
const response = await tokenCache.getAccessToken()
req.headers.authorization = `Bearer ${response.accessToken}`
} catch (error) {}
}
const apolloServer = new ApolloServer({
schema: applyMiddleware(schema, permissions),
context: createContext,
introspection: true,
})
export const config = {
api: {
bodyParser: false,
},
}
export default cors()(async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'OPTIONS') {
res.end()
return
}
await attachAccessToken(req, res)
return apolloServer.createHandler({ path: '/api/graphql' })(req, res)
})
(I am using prisma2 in the back and deploying to vercel)
Hey @BjoernRave, Any chance you could share your lib/auth0
Hi everyone, with the new v1.0.0-beta.0 release we have included a way to use an access token from the frontend. However, keep in mind that it is less secure than proxying the requests through API routes, as the access token could be stolen via XSS.
Please read Comparison with auth0-react, as auth0-react might be a better fit for your project if that's the primary way of fetching data in your application.
Most helpful comment
Currently, I am using a custom fetch before each request that pulls from /api/getToken to get the accessToken and attaches it to Authorization header.
If anyone comes up with a better method, I'd love to hear it.
Thanks!
https://gist.github.com/BryceAMcDaniel/a710afe4fd877a04e55a921e4e74a21c