mirror of
https://github.com/michivonah/rss-reader.git
synced 2025-12-22 20:46:28 +01:00
add next auth & login with github
This commit is contained in:
parent
78afa6be22
commit
9a9110e58c
10 changed files with 226 additions and 22 deletions
117
package-lock.json
generated
117
package-lock.json
generated
|
|
@ -16,9 +16,11 @@
|
|||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.503.0",
|
||||
"next": "15.3.1",
|
||||
"next-auth": "^5.0.0-beta.27",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"simple-icons": "^14.12.3",
|
||||
"tailwind-merge": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -47,6 +49,35 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@auth/core": {
|
||||
"version": "0.39.0",
|
||||
"resolved": "https://registry.npmjs.org/@auth/core/-/core-0.39.0.tgz",
|
||||
"integrity": "sha512-jusviw/sUSfAh6S/wjY5tRmJOq0Itd3ImF+c/b4HB9DfmfChtcfVJTNJeqCeExeCG8oh4PBKRsMQJsn2W6NhFQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@panva/hkdf": "^1.2.1",
|
||||
"jose": "^6.0.6",
|
||||
"oauth4webapi": "^3.3.0",
|
||||
"preact": "10.24.3",
|
||||
"preact-render-to-string": "6.5.11"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@simplewebauthn/browser": "^9.0.1",
|
||||
"@simplewebauthn/server": "^9.0.2",
|
||||
"nodemailer": "^6.8.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@simplewebauthn/browser": {
|
||||
"optional": true
|
||||
},
|
||||
"@simplewebauthn/server": {
|
||||
"optional": true
|
||||
},
|
||||
"nodemailer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz",
|
||||
|
|
@ -904,6 +935,15 @@
|
|||
"node": ">=12.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@panva/hkdf": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
|
||||
"integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
|
||||
|
|
@ -4498,6 +4538,15 @@
|
|||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "6.0.10",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.0.10.tgz",
|
||||
"integrity": "sha512-skIAxZqcMkOrSwjJvplIPYrlXGpxTPnro2/QWTDCxAdWQrSTV5/KqspMWmi5WAx5+ULswASJiZ0a+1B/Lxt9cw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
|
@ -5055,6 +5104,33 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next-auth": {
|
||||
"version": "5.0.0-beta.27",
|
||||
"resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.27.tgz",
|
||||
"integrity": "sha512-/QtP9C0C99YpEuBEJqMaDXH3ISWMgObQalwVZEoC7sskaIPhv5fQl6fXS/rXJQKqLY6MNJ42rqjqmRdoXZH2EQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@auth/core": "0.39.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@simplewebauthn/browser": "^9.0.1",
|
||||
"@simplewebauthn/server": "^9.0.2",
|
||||
"next": "^14.0.0-0 || ^15.0.0-0",
|
||||
"nodemailer": "^6.6.5",
|
||||
"react": "^18.2.0 || ^19.0.0-0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@simplewebauthn/browser": {
|
||||
"optional": true
|
||||
},
|
||||
"@simplewebauthn/server": {
|
||||
"optional": true
|
||||
},
|
||||
"nodemailer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next-themes": {
|
||||
"version": "0.4.6",
|
||||
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
|
||||
|
|
@ -5093,6 +5169,15 @@
|
|||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/oauth4webapi": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.5.0.tgz",
|
||||
"integrity": "sha512-DF3mLWNuxPkxJkHmWxbSFz4aE5CjWOsm465VBfBdWzmzX4Mg3vF8icxK+iKqfdWrIumBJ2TaoNQWx+SQc2bsPQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/panva"
|
||||
}
|
||||
},
|
||||
"node_modules/object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
|
|
@ -5382,6 +5467,25 @@
|
|||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/preact": {
|
||||
"version": "10.24.3",
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
|
||||
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
}
|
||||
},
|
||||
"node_modules/preact-render-to-string": {
|
||||
"version": "6.5.11",
|
||||
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz",
|
||||
"integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"preact": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/prelude-ls": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||
|
|
@ -5915,6 +6019,19 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-icons": {
|
||||
"version": "14.12.3",
|
||||
"resolved": "https://registry.npmjs.org/simple-icons/-/simple-icons-14.12.3.tgz",
|
||||
"integrity": "sha512-P85Pqak4picfTzdujmGL7+pFfsd32K/tDjHPQ8vvJcr2Xk380A9kBVIW5QH86qWqa+YJgFa5huLcUuwmW+YBPQ==",
|
||||
"license": "CC0-1.0",
|
||||
"engines": {
|
||||
"node": ">=0.12.18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/simple-icons"
|
||||
}
|
||||
},
|
||||
"node_modules/simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
|
|
|
|||
|
|
@ -17,9 +17,11 @@
|
|||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.503.0",
|
||||
"next": "15.3.1",
|
||||
"next-auth": "^5.0.0-beta.27",
|
||||
"next-themes": "^0.4.6",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"simple-icons": "^14.12.3",
|
||||
"tailwind-merge": "^3.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
2
src/app/api/auth/callback/github/route.ts
Normal file
2
src/app/api/auth/callback/github/route.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import { handlers } from "@/auth" // Referring to the auth.ts we just created
|
||||
export const { GET, POST } = handlers
|
||||
12
src/app/login/page.tsx
Normal file
12
src/app/login/page.tsx
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import LoginForm from "@/components/login/login-form";
|
||||
import { Suspense } from "react";
|
||||
|
||||
export default function LoginPage(){
|
||||
return (
|
||||
<main className="h-screen flex justify-center items-center">
|
||||
<Suspense>
|
||||
<LoginForm />
|
||||
</Suspense>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { Button } from "@/components/ui/button";
|
||||
import { Rss } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
|
|
@ -12,7 +13,11 @@ export default function Page() {
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<Button>Log in</Button>
|
||||
<Link
|
||||
href="/login"
|
||||
key="Login">
|
||||
<Button>Log in</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
9
src/auth.ts
Normal file
9
src/auth.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import NextAuth from "next-auth";
|
||||
import GitHub from "next-auth/providers/github";
|
||||
|
||||
export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||
providers: [GitHub],
|
||||
pages: {
|
||||
signIn: "/login",
|
||||
}
|
||||
})
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { Home, Rss, LogOut } from "lucide-react";
|
||||
import { Home, Rss } from "lucide-react";
|
||||
import Link from 'next/link';
|
||||
import { SignOut } from "./login/signout-button";
|
||||
|
||||
import {
|
||||
Sidebar,
|
||||
|
|
@ -28,13 +29,6 @@ const items = {
|
|||
icon: Rss,
|
||||
},
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
title: "Log out",
|
||||
url: "#",
|
||||
icon: LogOut,
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
export function AppSidebar() {
|
||||
|
|
@ -74,19 +68,11 @@ export function AppSidebar() {
|
|||
|
||||
<SidebarFooter>
|
||||
<SidebarMenu>
|
||||
{items.footer.map((item) => (
|
||||
<SidebarMenuItem key={item.title}>
|
||||
<SidebarMenuButton asChild>
|
||||
<Link
|
||||
key={item.title}
|
||||
href={item.url}
|
||||
>
|
||||
<item.icon />
|
||||
<span>{item.title}</span>
|
||||
</Link>
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
))}
|
||||
<SidebarMenuItem>
|
||||
<SidebarMenuButton asChild>
|
||||
<SignOut />
|
||||
</SidebarMenuButton>
|
||||
</SidebarMenuItem>
|
||||
</SidebarMenu>
|
||||
</SidebarFooter>
|
||||
</Sidebar>
|
||||
|
|
|
|||
41
src/components/login/login-form.tsx
Normal file
41
src/components/login/login-form.tsx
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { signIn } from "@/auth";
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
CardFooter
|
||||
} from '@/components/ui/card';
|
||||
|
||||
export default function LoginForm(){
|
||||
return (
|
||||
<div>
|
||||
<Card>
|
||||
<CardHeader className="text-center">
|
||||
<CardTitle>Nice to meet you!</CardTitle>
|
||||
<CardDescription>Sign in below with your GitHub account.</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<form action={async () => {
|
||||
"use server";
|
||||
await signIn("github", { redirectTo: "/home" });
|
||||
}}>
|
||||
<Button type="submit" variant="outline" className="w-full">
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<title>GitHub</title>
|
||||
<path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
|
||||
</svg>
|
||||
Login with GitHub
|
||||
</Button>
|
||||
</form>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<p className="my-4 text-center text-sm text-muted-foreground">
|
||||
By clicking continue, you agree to our Terms of Service and Privacy Policy.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
18
src/components/login/signout-button.tsx
Normal file
18
src/components/login/signout-button.tsx
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { signOut } from "@/auth";
|
||||
import { LogOut } from "lucide-react";
|
||||
|
||||
export function SignOut() {
|
||||
return (
|
||||
<form
|
||||
action={async () => {
|
||||
"use server";
|
||||
await signOut();
|
||||
}}
|
||||
>
|
||||
<button className="flex flex-row items-center gap-2 cursor-pointer w-full" type="submit">
|
||||
<LogOut size={16} />
|
||||
<span>Log out</span>
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
12
src/middleware.ts
Normal file
12
src/middleware.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { auth } from "@/auth"
|
||||
|
||||
export default auth((req) => {
|
||||
if (!req.auth && req.nextUrl.pathname !== "/login") {
|
||||
const newUrl = new URL("/login", req.nextUrl.origin)
|
||||
return Response.redirect(newUrl)
|
||||
}
|
||||
})
|
||||
|
||||
export const config = {
|
||||
matcher: ["/((?!api|_next/static|_next/image|favicon.ico|$).*)"],
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue