skip to Main Content

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


  1. Chosen as BEST ANSWER

    Because I am using v5 with the Credentials Provider, what eventually worked for me was to add access_token to the typescript User interface:

    import NextAuth, { DefaultSession } from 'next-auth';
    import { DefaultJWT } from '@auth/core/jwt';
    
    declare module 'next-auth' {
    
      // Extend user to reveal access_token
      interface User {
        access_token: string | null;
      }
    
      // Extend session to hold the access_token
      interface Session {
        access_token: (string & DefaultSession) | any;
      }
    
      // Extend token to hold the access_token before it gets put into session
      interface JWT {
        access_token: string & DefaultJWT;
      }
    }
    

  2. You can use getServerSession at server pages:

    import { getServerSession } from 'next-auth';
    import { H3, UnauthorisedMessage } from '@repo/ui';
    import { authOptions } from './path/to/your/authOptions';
    
    const Page = async () => {
      const session = await getServerSession(authOptions);
    
      if (!session || !session.user) {
        return <UnauthorisedMessage />;
      }
      return (
        <>
          <H3>Server page must be protected</H3>
          <p>{`${JSON.stringify(session)}`}</p>
        </>
      );
    };
    
    export default Page;
    

    Obviously you have to replace ./path/to/your/authOptions with the path to your authOptions. Have a look here for further documentation.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search