A minimal Next.js app that implements the X API OAuth 2.0
Authorization Code flow with PKCE ("Login with X") and then displays the
signed-in user's account info by calling
GET /2/users/me.
The OAuth authorize step uses the twitter.com host; the token exchange and
API calls use api.twitter.com.
| Route | Purpose |
|---|---|
GET /api/auth/login |
Generates a PKCE verifier/challenge + state, sets them in httpOnly cookies, and redirects to https://twitter.com/i/oauth2/authorize. |
GET /api/auth/callback |
Validates state, exchanges the code for an access token at https://api.twitter.com/2/oauth2/token, and stores the token in an httpOnly cookie. |
POST /api/auth/logout |
Clears the access-token cookie. |
/ (home) |
If a token cookie exists, calls GET /2/users/me and renders the profile; otherwise shows the "Sign in with X" button. |
PKCE logic lives in lib/oauth.ts.
- Go to the X Developer Portal → your Project → app settings → User authentication settings.
- Enable OAuth 2.0.
- Type of App:
- Web App = confidential client → you get a Client ID and Client Secret.
- Native App / SPA = public client → Client ID only (no secret).
- Callback URI / Redirect URL — add both:
http://127.0.0.1:3000/api/auth/callback(local dev)https://<your-app>.vercel.app/api/auth/callback(production)
- Copy the Client ID (and Client Secret if you have one).
The callback URL must match exactly what the app sends. This sample derives it from the request origin, or you can pin it with
X_REDIRECT_URI.
npm install
cp .env.example .env.local # then fill in X_CLIENT_ID (and X_CLIENT_SECRET)
npm run devUse
127.0.0.1(notlocalhost) so it matches the registered callback URL.
- Commit and push to GitHub:
git add . git commit -m "Login with X OAuth 2.0 sample" git push
- In Vercel, Import the GitHub repo. Next.js is auto-detected — no build config needed.
- Add Environment Variables in the Vercel project settings:
X_CLIENT_ID— requiredX_CLIENT_SECRET— only for confidential (Web App) clientsX_REDIRECT_URI— optional; set tohttps://<your-app>.vercel.app/api/auth/callbackto pin it
- Deploy. Then make sure your production callback URL is registered in the X developer portal (step 1.4).
| Variable | Required | Notes |
|---|---|---|
X_CLIENT_ID |
Yes | OAuth 2.0 Client ID |
X_CLIENT_SECRET |
No | Only for confidential "Web App" clients |
X_REDIRECT_URI |
No | Pins the callback URL; otherwise derived from the request origin |
tweet.read, users.read, offline.access — the minimum needed to log in and
read the authenticated user's profile.