Auth.js v5 ja Next.js 16: täydellinen autentikointiopas App Routerille (2026)
Auth.js v5 (NextAuth) ja Next.js 16: täydellinen App Router -autentikointiopas. Asennus, OAuth-providerit, Credentials, proxy.ts-suojaus, roolipohjaiset oikeudet ja Edge-runtime-yhteensopivuus. Mukana toimivat koodiesimerkit Server Componenteille ja Server Actioneille.
Auth.js v5 (entinen NextAuth.js) on Next.js 16:n suositelluin tapa toteuttaa autentikointi App Routerissa, koska se tukee suoraan Server Componentteja, Server Actioneita ja uutta proxy.ts-tiedostoa (entinen middleware). Käytännössä asennat next-auth@beta-paketin, määrittelet providerit yhteen auth.ts-tiedostoon ja viet siitä neljä funktiota: auth, handlers, signIn ja signOut. Tässä oppaassa rakennetaan toimiva autentikointi alusta loppuun: OAuth (Google/GitHub), Credentials-tunnistautuminen, reittien suojaus, roolipohjaiset oikeudet ja Edge-runtime-yhteensopivuus.
Auth.js v5 (5.0.0-beta.29, toukokuu 2026) on yhteensopiva Next.js 16:n App Routerin ja React 19:n kanssa, ja korvaa getServerSession-kutsut yhdellä auth()-funktiolla.
Konfiguraatio jaetaan kahteen tiedostoon: kevyt auth.config.ts Edge-yhteensopivaan proxy.ts:ään ja täysi auth.ts Node-runtimea varten, koska adapterit (Prisma, Drizzle) eivät toimi Edgessä.
JWT-strategia on oletus ja toimii ilman tietokantaa; database-strategia vaatii adapterin, mutta antaa istuntojen mitätöinnin ja yhden sisäänkirjautumisen useilta laitteilta.
Server Actionit ovat oikea paikka signIn- ja signOut-kutsuille, koska ne suoritetaan palvelimella ja säilyttävät evästekontekstin oikein.
Reittien suojaus kannattaa toteuttaa kerroksittain: proxy.ts hoitaa karkean uudelleenohjauksen, ja Server Components / Route Handlers tekevät tarkemmat tarkistukset auth():lla.
Roolipohjainen pääsynvalvonta hoidetaan jwt- ja session-callbackeissa lisäämällä role-kenttä token-objektiin.
Mikä on Auth.js v5 ja miten se eroaa NextAuth v4:stä?
Auth.js v5 on NextAuth.js:n uusi sukupolvi, ja nimi vaihtui kuvastamaan sitä, että kirjasto tukee myös SvelteKitiä, SolidStartia ja Expressiä, ei pelkkää Next.js:ää. Next.js-pakettina nimi on edelleen next-auth, mutta versionumero alkaa viidestä. Itse pyöritin v4:ää tuotannossa kolme vuotta, ja v5 on selvästi parempi App Routerin kanssa. Migraatiossa on tosin muutama paikka jossa pages-router-tavat kolahtavat (tästä myöhemmin lisää).
Suurin yksittäinen muutos: kaikki istuntoa lukevat kutsut korvataan yhdellä auth()-funktiolla. Pages-routerissa käytettiin getServerSession(authOptions):ia, ja API-reiteissä getToken:ia. Nyt sama auth() toimii Server Componenteissa, Route Handlereissa, Server Actioneissa ja proxy.ts:ssä. Konfiguraatiokin siirtyi: vanha [...nextauth]/route.ts-tiedosto on edelleen olemassa, mutta sen sisältö on yksirivinen export { handlers as { GET, POST } } from "@/auth".
Toinen iso muutos on Edge-runtime-yhteensopivuus. v4 ei toiminut Edgessä jos adapter oli päällä, koska Prisma ja muut tietokanta-ajurit vaativat Node-ajoympäristön. v5 ratkaisee tämän jakamalla konfiguraation kahteen tiedostoon: kevyt Edge-versio menee proxy.ts:ään ja täysi versio Node-puolelle.
Asennus ja perusasetukset Next.js 16:een
Aloitetaan tyhjästä Next.js 16 -projektista. Asennus on suoraviivainen, mutta huomaa että v5 on edelleen beta-statusta. Komento next-auth@beta hakee uusimman 5.0.0-beta-version. Toukokuussa 2026 vakain versio on 5.0.0-beta.29.
pnpm add next-auth@beta
pnpm add @auth/core
# Vaihtoehtoinen adapter, vain jos käytät database-istuntoja
pnpm add @auth/prisma-adapter
Ympäristömuuttujat menevät .env.local-tiedostoon. AUTH_SECRET on pakollinen tuotannossa ja sitä käytetään JWT:n allekirjoitukseen. Generoi se komennolla openssl rand -base64 32 tai npx auth secret. Tuotannossa Vercelissä lisää sama arvo Environment Variables -välilehdellä.
Sitten yksi Route Handler joka delegoi handlers:ille. Polku on tärkeä: app/api/auth/[...nextauth]/route.ts.
// app/api/auth/[...nextauth]/route.ts
export { GET, POST } from "@/auth";
OAuth-providerit: Google ja GitHub
Auth.js v5 tukee yli 80 OAuth-provideria laatikosta valmiina. Konfiguraatio on yhden rivin importti, kunhan ympäristömuuttujien nimet noudattavat konventiota AUTH_<PROVIDER>_ID ja AUTH_<PROVIDER>_SECRET. Tällöin Auth.js löytää ne automaattisesti eikä konfiguraatiota tarvita.
Google-providerin prompt: "consent" ja access_type: "offline" ovat välttämättömiä, jos haluat refresh tokenin. Ilman näitä Google palauttaa refresh tokenin vain ensimmäisellä kirjautumisella, mikä on klassinen sudenkuoppa kehitysvaiheessa kun testaat kirjautumista useaan kertaan. Itse törmäsin tähän eräässä asiakasprojektissa, ja ratkaisuna piti käydä Googlen Account permissions -sivulla poistamassa appin pääsy, jotta refresh token tuli takaisin.
OAuth-callback-URL on aina https://<domain>/api/auth/callback/<provider>. Lisää Google Cloud Consolen OAuth-asetuksiin sekä paikallinen URL (http://localhost:3000/api/auth/callback/google) että tuotanto-URL. GitHubin OAuth Apps -asetuksissa Authorization callback URL on sama kaava.
Itse kirjautumislinkki Server Componentista näyttää tältä. Käytä Server Actionia, älä client-side signIn:iä, koska palvelin osaa asettaa evästeet oikein ilman flash-ehkä-kirjautunut-tilaa.
Jos haluat sähköposti/salasana-tunnistautumisen, käytä Credentials-provideria. Tämä on alue jossa pages-router-tavat kolahtavat eniten: v4:ssä authorize-funktio palautti null virheelle, v5:ssä on parempi heittää CredentialsSignin-virhe tai oma AuthError-aliluokka, jotta UI saa kunnon palautteen.
// auth.ts
import NextAuth, { CredentialsSignin } from "next-auth";
import Credentials from "next-auth/providers/credentials";
import bcrypt from "bcryptjs";
import { getUserByEmail } from "@/lib/users";
import { z } from "zod";
class InvalidLoginError extends CredentialsSignin {
code = "invalid_credentials";
}
const credentialsSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [
Credentials({
credentials: {
email: { label: "Sähköposti", type: "email" },
password: { label: "Salasana", type: "password" },
},
async authorize(credentials) {
const parsed = credentialsSchema.safeParse(credentials);
if (!parsed.success) throw new InvalidLoginError();
const user = await getUserByEmail(parsed.data.email);
if (!user?.passwordHash) throw new InvalidLoginError();
const valid = await bcrypt.compare(
parsed.data.password,
user.passwordHash
);
if (!valid) throw new InvalidLoginError();
return { id: user.id, email: user.email, name: user.name };
},
}),
],
session: { strategy: "jwt" },
});
Lomake itse on Server Action. signIn heittää NEXT_REDIRECT-virheen onnistuneen kirjautumisen jälkeen, joten ota se try/catch:ssa ja heitä uudelleen, muuten error boundary nappaa sen.
Next.js 16 nimesi middleware-tiedoston proxy.ts:ksi. Tämä on hyvä uutinen Auth.js:n kanssa. Jos haluat lukea aiheesta tarkemmin, tutustu artikkeliin Next.js Proxy: autentikointi, tietoturva ja reititys käytännössä. proxy.ts pyörii oletuksena Edge-runtimessa, joten et voi tuoda siellä Node-vain riippuvuuksia kuten bcryptjs, pg tai Prismaa.
Ratkaisu on jakaa Auth-konfiguraatio kahtia. Kevyt versio menee auth.config.ts:ään ja täysi versio auth.ts:ään.
authorized-callback on Auth.js v5:n tapa korvata vanha withAuth-HOC. Se ajetaan jokaisella pyynnöllä proxyssä ja palauttaa true, false tai NextResponse:n. Jos palautat false ja matcher osuu reittiin, Auth.js uudelleenohjaa pages.signIn-polkuun automaattisesti.
auth()-funktio Server Componenteissa
Server Componentissa kutsut auth():ia suoraan ilman propsia tai contextia. Se lukee evästeen, validoi JWT:n (tai hakee istunnon tietokannasta jos käytät database-strategiaa) ja palauttaa session-objektin tai null:n.
// app/dashboard/page.tsx
import { auth } from "@/auth";
import { redirect } from "next/navigation";
export default async function DashboardPage() {
const session = await auth();
if (!session?.user) redirect("/login");
return (
<div>
<h2>Tervetuloa, {session.user.name}</h2>
<p>Sähköposti: {session.user.email}</p>
</div>
);
}
Sama auth() toimii Route Handlereissa ja Server Actioneissa. Tämä on hyvä asia jos olet tottunut RSC- ja Server Action -suunnittelumalleihin. Autentikointitarkistus on yksi rivi, ei väliohjelma- tai Provider-rituaalia.
// app/api/posts/route.ts
import { auth } from "@/auth";
import { NextResponse } from "next/server";
export const GET = auth(async function GET(req) {
if (!req.auth) {
return NextResponse.json({ error: "Ei oikeuksia" }, { status: 401 });
}
// ... hae postaukset
return NextResponse.json({ user: req.auth.user });
});
Roolipohjaiset oikeudet ja callbackit
Roolit lisätään jwt- ja session-callbackeissa. JWT-strategialla rooli tallennetaan tokeniin ensimmäisellä kirjautumisella ja luetaan sitten joka pyynnössä ilman tietokantakutsua.
Jos haluat database-istunnot tai pysyvät käyttäjätiedot OAuth-providerilta, lisää adapter. Drizzle on omakohtaisesti nopein App Routerissa, ja käsittelen Drizzlen syvällisesti artikkelissa Next.js ja Drizzle ORM: käytännön opas. Tässä lyhyt Prisma-versio:
Tärkein gotcha: Credentials-provider ei tue database-istuntoja. Jos käytät sekä OAuth:ia että Credentials-provideria, pakota session.strategy arvoon "jwt". Voit silti tallentaa käyttäjät tietokantaan adapterilla, ja pelkkä istunto pysyy JWT:ssä.
Edge-runtime-yhteensopivuus
Edge-yhteensopivuus oli v4:n suurin kipupiste. v5 ratkaisee sen jakamalla konfiguraation: auth.config.ts ei saa importoida mitään Node-vain pakettia (ei adapteria, ei bcryptjs:ää, ei Prismaa). auth.ts sen sijaan saa, koska Route Handlerit ja Server Components pyörivät oletuksena Node-runtimessa.
Käytännössä matriisi on tämä:
Tiedosto
Runtime
Adapterit
Node-vain paketit
auth.config.ts
Edge + Node
EI
EI
auth.ts
Node
kyllä
kyllä
proxy.ts
Edge (oletus)
EI
EI
Server Components
Node
kyllä
kyllä
Route Handlers
Node (oletus)
kyllä
kyllä
Jos haluat ajaa koko sovelluksen Edge-runtimessa esim. paremman geografisen latenssin takia, sinun on käytettävä Edge-yhteensopivaa tietokanta-ajuria, kuten Drizzle + Neon serverless, Tursoa (libSQL) tai Vercel Postgresia. Prisma ei toimi Edgessä ilman Prisma Accelerate -palvelua.
Yleisiä virheitä ja korjauksia
"MissingSecret" tuotannossa: AUTH_SECRET puuttuu ympäristömuuttujista. Vercelissä lisää se Project Settings → Environment Variables, ja deploy uudelleen, sillä muuttujia ei lueta lennossa.
"UntrustedHost" Cloudflare/proxy-takana: Lisää trustHost: true NextAuth-konfiguraatioon. Tämä on tarpeen kun pyyntö menee kuormantasaajan kautta ja Host-header eroaa AUTH_URL:sta.
OAuth-kirjautuminen onnistuu, mutta käyttäjä on aina null: Yleisin syy on, että proxy.ts uudelleenohjaa /api/auth/callback/*-reitin /login:iin. Lisää matcher-konfiguraatioon api poikkeukseksi (kuten yllä). Tämän bugin parissa hutsasin itse pari tuntia ennen kuin tajusin matcherin ongelman.
"Server-only" -virhe selaimessa: Tuot auth.ts:ää Client Componenttiin. Käytä useSession-hookkia next-auth/react:sta Client-puolella, ja varmista että app/layout.tsx:ssä on SessionProvider.
Usein kysytyt kysymykset
Mitä eroa on NextAuth v4:llä ja Auth.js v5:llä?
Suurin ero on App Router -tuki ja Edge-yhteensopivuus. v5 korvaa getServerSession:in yhdellä auth()-funktiolla joka toimii Server Componenteissa, Server Actioneissa, Route Handlereissa ja proxyssä. Konfiguraatio jaetaan kahteen tiedostoon, jotta Node-vain adapterit eivät estä Edge-deploymenttia.
Voiko Auth.js v5:ttä käyttää Edge-runtimessa?
Kyllä, mutta vain Edge-yhteensopivilla provideilla ja ilman adapteria. Käytännössä proxy.ts tuo kevyen auth.config.ts:n ja Server Components -puoli käyttää täyttä auth.ts:ää. Credentials-provider Edgessä vaatii Edge-yhteensopivan salasanan hashauksen kuten @noble/hashes, koska bcryptjs ei toimi.
Pitääkö käyttää JWT- vai database-istuntoja?
JWT on oletus ja oikea valinta useimpiin sovelluksiin: ei tietokantakutsua jokaisella pyynnöllä, toimii Edgessä ja skaalautuu vaivatta. Database-istunnot kannattavat jos tarvitset välittömän mitätöinnin (pakko-uloskirjautumisen) tai aktiivisten istuntojen listauksen useilta laitteilta.
Miten suojaan Server Actionin Auth.js:llä?
Kutsu auth() Server Actionin sisällä ja tarkista session?.user sekä rooli ennen mutaation suorittamista. Älä luota proxyn matcheriin yksin, sillä proxy hoitaa karkean uudelleenohjauksen, mutta Server Action -kutsut menevät POST-pyyntöinä, ja hyökkääjä voi yrittää suoraa kutsua ilman selainnavigointia.
Miten lisään refresh tokenin Auth.js v5:een?
OAuth-providereilla aseta access_type: "offline" ja prompt: "consent" Googlella. Tallenna access_token, refresh_token ja expires_at JWT-tokeniin jwt-callbackissa. Kun token vanhenee, päivitä se kutsumalla providerin token endpointia ja palauta uusi token samasta callbackista.
Next.js 16.2 teki Turbopackista oletusbundlerin ja nopeutti buildit 2–5× sekä Fast Refreshin jopa 10×. Tämä käytännön opas näyttää, miten migroit webpack-konfiguraatiosi, otat tiedostojärjestelmävälimuistin käyttöön, ratkaiset yleisimmät yhteensopivuusongelmat ja optimoit CI-putken vuonna 2026.
Opettele Next.js App Routerin rinnakkaisreitit ja reitin sieppaus käytännön esimerkein. Rakenna URL-jaettavia modaaleja, itsenäisiä dashboard-paneeleja ja ehdollisia näkymiä.