Building a Next.js API endpoint to issue upload tokens with Imgwire
Signed uploads let a browser or mobile app upload with a publishable Client Key while your backend decides who is allowed to upload.
This tutorial builds a Next.js App Router endpoint that creates Imgwire upload tokens with @imgwire/node.
How the flow works
- The frontend asks your app for an upload token.
- Your Next.js route checks the current user or request context.
- The route uses a Server API Key to call Imgwire.
- The frontend sends the returned token with its Imgwire upload request.
Do not create upload tokens from client-side code. The endpoint in this tutorial must run on the server because it uses your Imgwire Server API Key.
Install the SDK
yarn add @imgwire/node
Create a Server API Key from the Imgwire dashboard and store it in .env.local:
IMGWIRE_API_KEY=sk_...
If your frontend also uploads directly with an Imgwire Client Key, keep that key in a public environment variable such as NEXT_PUBLIC_IMGWIRE_CLIENT_KEY.
Create a shared Imgwire client
Create src/lib/imgwire.ts:
import { ImgwireClient } from '@imgwire/node';
export const imgwire = new ImgwireClient({
apiKey: process.env.IMGWIRE_API_KEY!,
});
Keeping the client in one module makes it easier to reuse in API routes, server actions, and background jobs.
Add the upload token route
Create src/app/api/imgwire/upload-token/route.ts:
import { NextRequest } from 'next/server';
import { imgwire } from '@/lib/imgwire';
export async function POST(request: NextRequest) {
const user = await getCurrentUser(request);
if (!user) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
const uploadToken = await imgwire.images.createUploadToken();
return Response.json({
uploadToken: uploadToken.token,
});
}
async function getCurrentUser(_request: NextRequest) {
// Replace this with your auth provider or session lookup.
return { id: 'user_123' };
}
The response shape matches the frontend SDK examples:
{
"uploadToken": "..."
}
Add request validation
The route should only issue tokens for users and workflows your app allows. The exact checks depend on your auth system, but a production route usually validates:
- The user is signed in.
- The user is allowed to upload to the current workspace, team, or project.
- The UI flow is allowed to upload images at this point.
- Any app-level upload count, file type, or moderation requirement has been checked before issuing the token.
Imgwire Client Key settings still define upload limits and supported MIME types. Your endpoint is where you add app-specific permission checks.
Connect the frontend SDK
Configure @imgwire/js with getUploadToken:
import { ImgwireClient } from '@imgwire/js';
export const imgwireBrowser = new ImgwireClient({
apiKey: process.env.NEXT_PUBLIC_IMGWIRE_CLIENT_KEY!,
getUploadToken: async () => {
const response = await fetch('/api/imgwire/upload-token', {
method: 'POST',
});
if (!response.ok) {
throw new Error('Unable to create Imgwire upload token');
}
const { uploadToken } = await response.json();
return uploadToken;
},
});
Now client.images.upload(file) can request a token automatically when the Client Key requires signed uploads.
Handle errors clearly
Return normal HTTP status codes from your endpoint:
| Status | When to use it |
|---|---|
401 | The user is not signed in |
403 | The user is signed in but cannot upload |
429 | Your app-level upload limit has been hit |
500 | Imgwire token creation or server code fails |
Keep detailed server errors out of the client response, but log enough context on the server to debug failed uploads.
Best practices
- Store only Server API Keys in server-only environment variables.
- Do not cache upload tokens in shared caches unless your app has a deliberate token reuse policy.
- Keep the token route small and focused on authorization plus token creation.
- Pair signed uploads with Client Key upload limits for size and MIME type control.
- Use CORS Origins in Imgwire for browser-origin restrictions when applicable.
Related pages
- Building a Secure Upload Form in Next.js with Imgwire
- Frontend Quickstart
- Backend Quickstart
- CORS Origins
Last updated at: May 8, 2026