Upon successfull sign in using custom credentials provider in the NextAuth.Js v5, obtaining the access_token to make further API calls is unsuccessful. Only a subset of the token is returned, apparently for increased security. But without the access_token, how am I supposed to make API calls which need this in the header? I am using version 5 not 4
The v5 documentation states to use callbacks to store the access_token in a session. This is auth.ts, the console.logs do not output the access token in the callbacks.
I used this resource as further instructions for v5
text
import type { NextAuthConfig } from 'next-auth';
import NextAuth from 'next-auth';
import CredentialsProvider from 'next-auth/providers/credentials';
const credentialsConfig = CredentialsProvider({
name: 'Credentials',
credentials: {
username: {
label: 'Username or Account Number',
},
password: {
label: 'password',
type: 'password',
},
},
async authorize(credentials) {
const postdata = {
userName: credentials.username,
password: credentials.password,
};
let base64encodedData = process.env.LOGIN_BASE64;
const authResponse = await fetch(
'https://my-login-endpoint.com',
{
method: 'POST',
headers: {
Authorization: `Basic ${base64encodedData}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(postdata),
},
);
if (!authResponse.ok) {
return null;
}
const user = await authResponse.json();
if (user) {
console.log('USER', user); // access_token is displayed here ok!
return user;
}
return null;
},
});
const config = {
providers: [credentialsConfig],
trustHost: true,
debug: process.env.NODE_ENV !== 'production',
session: {
strategy: 'jwt',
},
async session({ session, user, token }) {
if (token.access_token) {
session.access_token = token.access_token; // Put the provider's access token in the session so that we can access it client-side and server-side with `auth()`
}
console.log(`Auth Sess = ${JSON.stringify(session)}`); // Auth Sess = {"user":{},"expires":"2024-04-12T09:27:58.960Z"}
console.log(`User = ${JSON.stringify(user)}`); // Undefined
console.log(`Auth Tok = ${JSON.stringify(token)}`); // {"sub":"12345678-1234-4567-1234-123456789111","iat":yyyyyyyyyy,"exp":1712914043,"jti":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
return session;
},
async jwt({ token, user, account, profile, isNewUser }) {
console.log(`Auth JWT Tok = ${JSON.stringify(token)}`); // {"sub":"12345678-1234-4567-1234-123456789111","iat":yyyyyyyyyy,"exp":1712914043,"jti":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
console.log(`USER JWT account = ${JSON.stringify(user)}`); // UNDEFINED
console.log(`Router Auth JWT account = ${JSON.stringify(account)}`); // UNDEFINED
if (account) {
token.accessToken = account.access_token;
}
return token;
},
authorized({ auth, request: { nextUrl } }) {
const { pathname } = nextUrl;
if (pathname === '/middlewareProtected') return !!auth; // return by converting the auth session to a boolean
return true;
},
},
} satisfies NextAuthConfig;
export const { handlers, auth, signIn, signOut } = NextAuth(config);
This a server page
import { H3, UnauthorisedMessage } from '@repo/ui';
import { auth } from 'auth';
import React from 'react';
const Page = async () => {
const session = await auth();
if (!session || !session.user) {
return <UnauthorisedMessage />;
}
return (
<>
<H3>Server page must be protected</H3>
<p>{`${JSON.stringify(session)}`}</p>
</>
);
};
export default Page;
2
Answers
Because I am using v5 with the Credentials Provider, what eventually worked for me was to add access_token to the typescript User interface:
You can use
getServerSession
at server pages:Obviously you have to replace
./path/to/your/authOptions
with the path to your authOptions. Have a look here for further documentation.