It took me a while to understand. The documentation is not very clear.

However, it is always good to read it first -> https://next-auth.js.org/providers/credentials

After reading that part…

For NextAuth to work with Signin.js custom pages ( https://next-auth.js.org/configuration/pages ), the following should be added to the API:

//pages/api/auth/[...nextauth].js
...
pages: {
signIn: '/auth/signin',
//signOut: '/auth/signout',
error: '/auth/error', // Error code passed in query string as ?error=
// verifyRequest: '/auth/verify-request', // (used for check email message)
// newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest)
}
...

At the front, we can create a custom panel with textfields and labels, but the what we would like to focus is the button using Next-Auth:

//pages/auth/signin.js
import { getProviders} from "next-auth/react"
//Some react form structure... but in the button
...
onClick={async (event) => {
const x = signIn("credentials",
{
redirect: false,
username, password,
callbackUrl: 'http://localhost:3000'
})
.then((data) => {
console.log("****signin ok: ", data)
if (data.error) {
console.log("ERRROR: ", data.error)
}
//Some front logic here...
})
.catch((error) => {
console.log("*****error adminInitiateAuth: ", error)
console.log(JSON.stringify(error))
//Some front logic here...
})
}}
...

To respond properly if there is an error, we use rejections.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject

The final part of the code In the API…

//pages/api/auth/[...nextauth].js
//Including the authentication provider...
....
CredentialsProvider({
name: 'Credentials',
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
password: { label: "Password", type: "password" }
},
async authorize(credentials, req) {
try {
console.debug("****createCredential: ", JSON.stringify(credentials))
var aws = require('aws-sdk');
aws.config.update({
region: 'us-east-1',
credentials: new aws.CognitoIdentityCredentials({
IdentityPoolId: '???'
})
});
var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
const UserPoolId = process.env.SOMEPOOLID
const userParams = {
"AuthParameters": {
"USERNAME": credentials.username,
"PASSWORD": credentials.password,
},
"AuthFlow": "ADMIN_NO_SRP_AUTH",
"ClientId": process.env.SOMECLIENTID,
UserPoolId
};
const errorInit = await cognitoidentityserviceprovider
.adminInitiateAuth(userParams).promise()
.then((data) => {
return null
})
.catch((error) => {
console.error("*****error createCredential adminInitiateAuth: ", error)
console.error(JSON.stringify(error))
return error
})
if (errorInit) {
console.error("*****errorInit: ", errorInit)
if (errorInit.code) {
return Promise.reject(new Error(
errorInit.code
))
}
return Promise.reject(new Error(
"Unknown Error"
))
}
...
//since we have a valid user... we use the cognitos user information for custom logic

After signing in successfully, we can transfer the info from the user to the session in the callbacks Next-Auth Callbacks ( https://next-auth.js.org/configuration/callbacks ):

async jwt({ token, user, account, profile, isNewUser }) {
if (user) {
token.enabled = user.Enabled
console.debug("IFFFFFFFFFFF***********", user)
const ua = user.UserAttributes
for (let i = 0; i < ua.length; i++) {
const att = ua[i];
token[att.Name] = att.Value
}
console.debug("Token after data transfer: ", token)
// some custom logic here
}
return token
}

Conclusion:

that worked for me