I'm developing an application in Next.js 14 for one project. You need to authenticate using the Phantom wallet for the Solana blockchain. On localhost:3000 everything works correctly and on preview deploy in vercel, everything works correctly, but on the main domain the following error occurs.
I thought use Moralis, but it have big bundle.
next auth
export const authOptions: AuthOptions = {
providers: [
CredentialsProvider({
name: 'web3',
credentials: {
signature: {
label: 'Signature',
type: 'text'
},
message: {
label: 'Message',
type: 'text'
}
},
async authorize(credentials, req) {
if (!credentials?.message) {
return null
}
const { publicKey, host } = JSON.parse(credentials?.message)
const nextAuthUrl = new URL(getURL())
if (host !== nextAuthUrl.host) {
return null
}
const crsf = await getCsrfToken({ req: { ...req, body: null } })
if (!crsf) {
return null
}
const nonceUnit8 = Signature.create(crsf)
const isValidate = await Signature.validate(
{
signature: credentials?.signature,
publicKey
},
nonceUnit8
).then((res) => res.valueOf)
if (!isValidate) {
throw new Error('Could not validate the signed message')
}
return { id: publicKey }
}
})
],
session: { strategy: 'jwt' },
debug: process.env.NEXT_PUBLIC_VERCEL_ENV === 'development',
callbacks: {
async session({ session, token }) {
if (session.user) {
session.user.name = token.sub
session.user.image = `https://ui-avatars.com/api/?name=${token.sub}`
}
return session
}
}
}
Fn for connect wallet
import base58 from 'bs58'
import { getCsrfToken, signIn } from 'next-auth/react'
import { getProvider } from '../hooks/getProvider'
import { Signature } from './Signature'
export const onConnect = async () => {
try {
const provider = getProvider()
if (!provider) {
window.open('https://phantom.app/', '_blank')
}
const resp = await provider.connect()
console.log('Connect', resp.publicKey.toString())
const csrf = await getCsrfToken()
if (resp && csrf) {
const noneUnit8 = Signature.create(csrf)
const { signature } = await provider.signMessage(noneUnit8)
const serializedSignature = base58.encode(signature)
const message = {
host: window.location.host,
publicKey: resp.publicKey.toString(),
nonce: csrf
}
const response = await signIn('credentials', {
message: JSON.stringify(message),
signature: serializedSignature,
redirect: false
})
console.log(response)
if (response?.error) {
console.log('Error occured:', response.error)
return
}
} else {
console.log('Could not connect to wallet')
}
} catch (error) {
console.error(error)
}
}
This getURL()
export const getURL = () => {
if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'development')
return 'http://localhost:3000'
else return `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
}