You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We recently switched to next-auth because we are now using Keycloak instead of Auth0 to handle user reg/login on our Next.JS site. Previously, we had used Auth0's Next.JS package for handling sessions and it worked great because the session was handled by the package and the Auth0 JWT never left the Next.JS server. This also allowed us to use Next.JS as a proxy for requests to our C# backend API. The sequence diagram for any request would be:
User makes request
Request would hit middleware and would attempt to get session
If fails to get session, middleware would redirect to login page
If got session but request was not an API route (page route), it would continue the request
If got session and request was an API route:
Middleware would get server session (which has the auth0 JWT) and inject the JWT as an authorization header to request
Backend API would receive original request from user's browser with JWT added on.
We are trying to achieve the same functionality with next-auth. We'd love to use the auth() wrapper which seems to be the preferred method to handle this however we can't seem to extract the token from the auth() function. Any idea on how to achieve this?
I did manage to get a solution working but it used getToken() which is now said to be deprecated in v5. Other than that, i saw no way of getting the token.
EDIT: I also wanted to note I've seen that you can store the provider JWT in the session JWT by utilizing the session callback but I assume this now means the client can access that JWT on their browser. Is this true and if so is it discouraged?
auth.ts
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
Keycloak({
clientId: [ID],
clientSecret: [],
issuer: [],
authorization: {
params: {
scope: 'openid profile email offline_access',
prompt: 'login', // to force logout to require actually logging back into keycloak to gain access again
},
},
}),
],
callbacks: {
async jwt({ token, account }) {
if (account) {
// First login, save the `access_token`, `refresh_token`, and `expires_at`
return {
...token,
access_token: account.access_token,
access_token_expires: account.expires_at,
refresh_token: account.refresh_token,
};
} else if (Date.now() < token.access_token_expires * 1000) {
// Subsequent logins, if the `access_token` is still valid, return the JWT
return token;
} else {
// Subsequent logins, if the `access_token` has expired, try to refresh it
if (!token.refresh_token) throw new Error('Missing refresh token');
try {
const response = await fetch([OIDC_URL], {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
client_id: [ID],
client_secret:[ID],
grant_type: 'refresh_token',
refresh_token: token.refresh_token!,
}),
method: 'POST',
});
const responseTokens = await response.json();
if (!response.ok) throw responseTokens;
return {
// Keep the previous token properties
...token,
access_token: responseTokens.access_token,
access_token_expires: Math.floor(
Date.now() / 1000 + (responseTokens.expires_in as number),
),
// Fall back to old refresh token, but note that
// many providers may only allow using a refresh token once.
refresh_token: responseTokens.refresh_token ?? token.refresh_token,
};
} catch (error) {
console.error('Error refreshing access token', error);
// The error property can be used client-side to handle the refresh token error
return { ...token, error: 'RefreshAccessTokenError' as const };
}
}
},
},
});
middleware.ts
import { NextResponse } from 'next/server';
import { auth } from './auth';
export default auth((req) => {
const { pathname, search, origin } = req.nextUrl;
if (pathname.startsWith('/api/v1/stripe/webhooks')) {
// Unauthenticated stripe webhook
return NextResponse.next();
} else {
if (req.auth) {
// Has auth/session
if (pathname.startsWith('/api/v1')) {
// REST API handler
const session = ''; // <---------------- NEED TO OBTAIN KEYCLOAK JWT HERE ------------
const requestHeaders = new Headers(req.headers);
requestHeaders.set('Authorization', `Bearer ${session}`);
const url = new URL(`${global.process.env.REST_API}${pathname}${search}`);
return NextResponse.rewrite(url, {
request: {
headers: requestHeaders,
},
});
} else if (pathname == '/api/graphql') {
// GQL API handler
const session = ''; // <---------------- NEED TO OBTAIN KEYCLOAK JWT HERE ------------
const requestHeaders = new Headers(req.headers);
requestHeaders.set('Authorization', `Bearer ${session}`);
const url = new URL(
`${global.process.env.GRAPH_API}`,
);
return NextResponse.rewrite(url, {
request: {
headers: requestHeaders,
},
});
} else {
// Everything else handler
return NextResponse.next();
}
} else {
// No auth/session
if (pathname.startsWith('/api'))
return NextResponse.json(
{
error: 'not_authenticated',
description: 'The user does not have an active session or is not authenticated',
},
{ status: 401 },
);
else return NextResponse.redirect(new URL(origin));
}
}
});
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
We recently switched to next-auth because we are now using Keycloak instead of Auth0 to handle user reg/login on our Next.JS site. Previously, we had used Auth0's Next.JS package for handling sessions and it worked great because the session was handled by the package and the Auth0 JWT never left the Next.JS server. This also allowed us to use Next.JS as a proxy for requests to our C# backend API. The sequence diagram for any request would be:
We are trying to achieve the same functionality with next-auth. We'd love to use the auth() wrapper which seems to be the preferred method to handle this however we can't seem to extract the token from the auth() function. Any idea on how to achieve this?
I did manage to get a solution working but it used getToken() which is now said to be deprecated in v5. Other than that, i saw no way of getting the token.
EDIT: I also wanted to note I've seen that you can store the provider JWT in the session JWT by utilizing the
session
callback but I assume this now means the client can access that JWT on their browser. Is this true and if so is it discouraged?auth.ts
middleware.ts
Beta Was this translation helpful? Give feedback.
All reactions