Error message: Unable to access the 'username' property in nextjs and Auth.js due to undefined value

When setting up authentication with Auth.js and the next.js framework, my auth.ts file is structured as follows:

import { Client } from 'ldapts';
import NextAuth, { type DefaultSession, type User } from 'next-auth';
import Credentials from 'next-auth/providers/credentials';
import { authConfig } from './auth.config';
import z from 'zod';

const CredentialsSchema = z.object({
  username: z.string().regex(/^\d+$/, 'Username must only contain digits'),
  password: z
    .string()
    .min(6, 'Password must be at least 6 characters long'),
});

declare module 'next-auth' {
  interface Session {
    user: {
      username: string;
      displayName: string;
      memberOf: string[];
    } & DefaultSession['user'];
  }

  interface User {
    username: string;
    displayName: string | string[] | Buffer | Buffer[];
    memberOf: string | string[] | Buffer | Buffer[];
    mail: string | string[] | Buffer | Buffer[];
  }
}

export const { auth, signIn, signOut } = NextAuth({
  ...authConfig,
  providers: [
    Credentials({
      name: 'LDAP',
      credentials: {
        username: { label: 'Username/DN', type: 'text', placeholder: '' },
        displayName: {},
        memberOf: {},
        mail: {},
      },
      authorize: async (credentials) => {
        const result = CredentialsSchema.safeParse(credentials);

        if (!result.success) {
          console.log(result.error.errors);
          return null;
        }

        const { username, password } = result.data;
        const ldapUrl =
          process.env.LDAP_URI || 'ldaps://server.com.es:3269';
        const client = new Client({
          url: ldapUrl,
        });

        try {
          await client.bind(
            `CN=${username}`,
            password,
          );
          const extraInfo = await client.search(
            `CN=${username},DC=InfoDir,DC=Prod`,
            { attributes: ['cn', 'dn', 'displayName', 'memberOf', 'mail'] }, 
          );

          const { cn, dn, displayName, memberOf, mail } =
            extraInfo?.searchEntries?.[0] || {};

          const user: User = {
            username: username,
            displayName: displayName,
            memberOf: memberOf,
            mail: mail,
          };
          return user;
        } catch (error) {
          console.log('LDAP failed', error);
          return null;
        } finally {
          await client.unbind();
        }
      },
    }),
  ],
  callbacks: {
    async jwt({ token, user }) {
      if (user) {
        token.username = user.username;
        token.displayName = user.displayName;
        token.memberOf = user.memberOf;
        token.email = user.email;
      }
      return token;
    },
    async session({ session, token, user }) {
      return {
        ...session,
        user: {
          ...session.user,
          username: user.username,
          displayName: user.displayName,
          memberOf: user.memberOf,
        },
      };
    },
  },
});

However, I am experiencing issues during the authentication process. The authentication goes through, but an error occurs on the server with the following details:

[auth][error] JWTSessionError: Read more at https://errors.authjs.dev#jwtsessionerror
[auth][cause]: TypeError: Cannot read properties of undefined (reading 'username')
    at Object.session (webpack-internal:///(rsc)/./auth.ts:90:36)
    ...

After making a substitution to 'token', the following error message appears:

Type '...' is not assignable to type '...'. ... Type 'unknown' is not assignable to type 'string | null | undefined'.ts(2322)

Answer №1

It appears that you are extracting the username property from the user parameter in your session callback, even though your sessions are managed using JWT (even if LDAP authentication is used). As stated in the documentation: When database sessions are used, the User (user) object is passed as an argument. When JSON Web Tokens are used for sessions, the JWT payload (token) is provided instead.

In your jwt callback, you are already mapping the user values to your token property. You just need to update your session callback to:

async session({ session, token, user }) {
  return {
    ...session,
    user: {
      ...session.user,
      username: token.username as string,
      displayName: token.displayName as string,
      memberOf: token.memberOf as string,
    },
  };
}

Take note of the casting used to resolve the second error encountered, which appeared to be related to the fact that the values within token were resolving as unknown.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Aligning the React Navigation header component's bottom shadow/border width with the bottom tabs border-top width

Currently, I am working on achieving a uniform width for the top border of the React Navigation bottom tabs to match that of the top header. Despite my efforts, I am unable to achieve the exact width and I am uncertain whether it is due to the width or sha ...

Template literal types in TypeScript and Visual Studio Code: An unbeatable duo

I'm encountering an issue while attempting to utilize literal types in Visual Studio Code. When following the example from the documentation, https://i.stack.imgur.com/V6njl.png eslint is flagging an error in the code (Parsing error: Type expected.e ...

Inconsistency with Angular 4 instance variables causes ambiguity within a function

Here is the code snippet: @Component({ selector: 'unb-navbar', templateUrl: './navbar.html' }) export class NavbarComponent implements OnInit { @Input() brand: string; controlador:boolean=false; overlay:string=""; @Input() menu ...

Encountering an issue when trying to download a PDF from an Angular 6 frontend using a Spring Boot API - receiving an error related to

When I directly call the Spring Boot API in the browser, it successfully creates and downloads a PDF report. However, when I try to make the same GET request from Angular 6, I encounter the following error: Here is the code snippet for the Spring Boot (Ja ...

The error message "result.subscribe is not a function" indicates that there was a problem

I encountered an issue with the following error message: Uncaught TypeError: result.subscribe is not a function Here's a screenshot of the error for reference: https://i.sstatic.net/yfhy0.png Despite attempting to handle the error, I'm still s ...

Customize the datepicker locale in Valor

Currently, I am working with Angular2 and typescript alongside the Valor datepicker. Unfortunately, the datepicker does not have the necessary locale built-in. After some research, I discovered that the essential JavaScript file containing the locale infor ...

Incorporating AngularFire2 in the latest Angular 11.0.5 framework

I have been attempting to utilize Firebase as a database for my angular application. Following the guidance provided in these instructions (located on the official developers Github page), I first installed npm install angularfire2 firebase --save in my p ...

Navigate to the logout page automatically when closing the final tab

In order to comply with the requirement, I need to log out the user when they close the last tab on the browser. ngOnInit() { let counter: any = this.cookieService.get('screenCounterCookie'); counter ? ++counter : (counter = & ...

Node.js project: The client does not support the authentication protocol requested by the server

Currently facing an obstacle in connecting to a MySQL database that is locally stored on my machine using a node server (also localized). Context / Setup My node project is utilizing typescript, however, I am executing it by utilizing tsc followed by npm ...

Perform an Angular HTTP request and await responses from multiple sources

I'm currently working with Angular 11 and looking to make an HTTP call to an API that will trigger a server-side process. Here's the code for the HTTP call: processData(data) { return this.httpClient.post('https://myurl/api/process&apos ...

React: Eliminate the reliance on two interconnected contexts by implementing a globally accessible constant object

Working on a new significant update for react-xarrows, I encountered a complex situation that needs resolution. To help explain, let's visualize with an example - two draggable boxes connected by an arrow within a wrapping context. https://i.sstatic ...

Unable to locate the module '@vitejs/plugin-react' or its associated type

After creating the project with npm create vite@latest and selecting ts-react, everything seemed to work fine when I ran npm run dev. However, in my vs code editor, I encountered the error message "Cannot find module '@vitejs/plugin-react' or its ...

The active class functions properly with errors, but does not respond to messages or warnings

Within my component, there is a member named capsLockIsOn. This member interacts perfectly with the following code: <div class="error" [class.active]="capsLockIsOn">Caps is on!</div> Surprisingly, a switch to either class=& ...

How can I display a modal with image options and image selection using Ionic 4?

Currently, I am developing an Ionic 4 Angular application and implementing an Ionic modal feature. I would like to include images in the modal, so that when a user clicks on them, they are displayed. ...

Error: A stream was expected, but you provided 'undefined'. Please provide either an Observable, Promise, Array, or Iterable instead

I'm encountering an error while trying to catch errors in my Ionic-based application with Angular. In the create() method, I am attempting to create a new User. If the username already exists, I receive a response from the backend, but my method thro ...

Ensuring TypeORM constraint validations work seamlessly with MySQL and MariaDB

I recently started using TypeORM and I'm trying to incorporate the check decorator in my MySQL/MariaDB database. However, after doing some research on the documentation and online, it seems that the check decorator is not supported for MySQL. I'v ...

Trouble updating React Context state when attempting to utilize token from cookies

From my understanding, the typical method of maintaining context state in a React web application involves storing the user's information in a token within local storage or a cookie. Upon each page load, this token is retrieved to reset the context st ...

How can I emphasize the React Material UI TextField "Cell" within a React Material UI Table?

Currently, I am working on a project using React Material UI along with TypeScript. In one part of the application, there is a Material UI Table that includes a column of Material TextFields in each row. The goal is to highlight the entire table cell when ...

Can a client component in NextJs retrieve data from a server component?

Apologies for the way the question is phrased. I have a server component named auth.ts that retrieves user details after they log in. This server side component is located at //auth.ts export const validateRequest = cache( async (): Promise< { use ...

The error in React TypeScript with react-markdown: "No matching overload found for this call

While I'm open to trying out different libraries, I've heard good things about react-markdown. Unfortunately, I'm encountering an issue when attempting to use it with TypeScript in a functional component. import React from 'react' ...