When the user is logged in, the code works correctly, the user authorizes the app and redirects me correctly to –> api/x/callback, the problem is when I have a user who is not logged in to X, when I access –> api/auth/x/callback, it redirects me to X’s login, I log in correctly, but it does not redirect me correctly to the (Authorize App) page, but instead it redirects me to X’s profile, does anyone know a solution to this problem, I would greatly appreciate your help
this is –> api/auth/x/callback
import { NextResponse } from 'next/server'
import crypto from 'crypto'
const X_CLIENT_ID = process.env.X_CLIENT_ID as string
const REDIRECT_URI = `${process.env.NEXT_PUBLIC_URL}${process.env.NEXT_PUBLIC_X_REDIRECT_URI}`
export async function GET() {
if (!X_CLIENT_ID) {
return NextResponse.json(
{ error: 'X_CLIENT_ID is not defined' },
{ status: 500 }
)
}
const codeVerifier = crypto.randomBytes(32).toString('hex')
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url')
const response = NextResponse.redirect(
`https://twitter.com/i/oauth2/authorize?${new URLSearchParams({
response_type: 'code',
client_id: X_CLIENT_ID,
redirect_uri: REDIRECT_URI,
scope: 'tweet.read tweet.write users.read offline.access',
state: crypto.randomBytes(16).toString('hex'),
code_challenge: codeChallenge,
code_challenge_method: 'S256'
})}`
)
response.cookies.set('code_twitter_verifier', codeVerifier, {
httpOnly: true,
secure: true,
sameSite: 'lax',
path: '/'
})
return response
}
this is –> api/x/callback
import { NextResponse } from 'next/server'
import { cookies } from 'next/headers'
const X_CLIENT_ID = process.env.X_CLIENT_ID as string
const X_CLIENT_SECRET = process.env.X_CLIENT_SECRET as string
const REDIRECT_URI = `${process.env.NEXT_PUBLIC_URL}${process.env.NEXT_PUBLIC_X_REDIRECT_URI}`
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const code = searchParams.get('code')
if (!code) {
const redirectUrl = new URL(
'/admin/organizations',
request.url
)
return NextResponse.redirect(redirectUrl)
}
const codeVerifier = cookies().get('code_twitter_verifier')?.value
if (!codeVerifier) {
return NextResponse.json(
{ error: 'code_verifier not found' },
{ status: 400 }
)
}
const credentials = Buffer.from(`${X_CLIENT_ID}:${X_CLIENT_SECRET}`).toString(
'base64'
)
const tokenResponse = await fetch('https://api.twitter.com/2/oauth2/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${credentials}`
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
code_verifier: codeVerifier
}).toString()
})
const tokenData = await tokenResponse.json()
if (!tokenResponse.ok) {
return NextResponse.json(
{ error: 'No se pudo obtener el token' },
{ status: 401 }
)
}
const { access_token, refresh_token, expires_in } = tokenData
const userResponse = await fetch('https://api.twitter.com/2/users/me', {
headers: {
Authorization: `Bearer ${access_token}`
}
})
const userData = await userResponse.json()
const { id, username } = userData.data
if (!userResponse.ok) {
return NextResponse.json({ error: 'User not found' }, { status: 401 })
}
const redirectUrl = new URL(
'/admin/organizations/channels/twitter',
request.url
)
redirectUrl.searchParams.append('accessToken', access_token)
redirectUrl.searchParams.append('refreshToken', refresh_token)
redirectUrl.searchParams.append('userId', id)
redirectUrl.searchParams.append('screenName', username)
redirectUrl.searchParams.append('expiresIn', expires_in)
return NextResponse.redirect(redirectUrl)
}