diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index 714e996..1786e82 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -1,4 +1,4 @@
-import { auth } from '@/auth';
+import { auth, providerMap } from '@/auth';
import SSOLogin from '@/components/user/sso-login-button';
import LoginForm from '@/components/user/login-form';
import { redirect } from 'next/navigation';
@@ -35,11 +35,15 @@ export default async function LoginPage() {
-
+ {providerMap.length > 0 &&
}
- {process.env.AUTH_AUTHENTIK_ISSUER && (
-
- )}
+ {providerMap.map((provider) => (
+
+ ))}
diff --git a/src/auth.ts b/src/auth.ts
index b3ed869..09a5065 100644
--- a/src/auth.ts
+++ b/src/auth.ts
@@ -1,16 +1,49 @@
import NextAuth from 'next-auth';
+
+import type { Provider } from 'next-auth/providers';
+import Credentials from 'next-auth/providers/credentials';
+
import Authentik from 'next-auth/providers/authentik';
+const providers: Provider[] = [
+ !process.env.DISABLE_PASSWORD_LOGIN &&
+ Credentials({
+ credentials: { password: { label: 'Password', type: 'password' } },
+ authorize(c) {
+ if (c.password !== 'password') return null;
+ return {
+ id: 'test',
+ name: 'Test User',
+ email: 'test@example.com',
+ };
+ },
+ }),
+ process.env.AUTH_AUTHENTIK_ID && Authentik,
+].filter(Boolean) as Provider[];
+
+export const providerMap = providers
+ .map((provider) => {
+ if (typeof provider === 'function') {
+ const providerData = provider();
+ return { id: providerData.id, name: providerData.name };
+ } else {
+ return { id: provider.id, name: provider.name };
+ }
+ })
+ .filter((provider) => provider.id !== 'credentials');
+
export const { handlers, signIn, signOut, auth } = NextAuth({
- providers: [process.env.AUTH_AUTHENTIK_ISSUER ? Authentik : null].filter(
- (x) => x !== null,
- ),
- callbacks: {
- authorized: async ({ auth }) => {
- return !!auth?.user;
- },
+ providers,
+ session: {
+ strategy: 'jwt',
},
pages: {
signIn: '/login',
+ signOut: '/logout',
+ },
+ callbacks: {
+ authorized({ auth }) {
+ return !!auth?.user;
+ },
},
});
diff --git a/src/components/labeled-input.tsx b/src/components/labeled-input.tsx
index 7b4768a..7a416d4 100644
--- a/src/components/labeled-input.tsx
+++ b/src/components/labeled-input.tsx
@@ -6,23 +6,24 @@ export default function LabeledInput({
label,
placeholder,
value,
+ name,
}: {
type: 'text' | 'email' | 'password';
label: string;
placeholder?: string;
value?: string;
+ name?: string;
}) {
- const elementId = Math.random().toString(36).substring(2, 15);
-
return (
-
+
);
diff --git a/src/components/user/login-form.tsx b/src/components/user/login-form.tsx
index 20438e8..2869930 100644
--- a/src/components/user/login-form.tsx
+++ b/src/components/user/login-form.tsx
@@ -1,18 +1,38 @@
+import { signIn } from '@/auth';
import LabeledInput from '@/components/labeled-input';
import { Button } from '@/components/ui/button';
+import { AuthError } from 'next-auth';
+import { redirect } from 'next/navigation';
+
+const SIGNIN_ERROR_URL = '/error';
export default function LoginForm() {
return (
-