Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
pilcrowonpaper committed Sep 22, 2024
0 parents commit 9b2e7de
Show file tree
Hide file tree
Showing 28 changed files with 2,157 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: pilcrowOnPaper
33 changes: 33 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: "Publish"
on:
push:
branches:
- main

env:
CLOUDFLARE_API_TOKEN: ${{secrets.CLOUDFLARE_PAGES_API_TOKEN}}

jobs:
publish:
name: Publish
runs-on: ubuntu-latest
steps:
- name: setup actions
uses: actions/checkout@v3
- name: setup node
uses: actions/setup-node@v3
with:
node-version: 20.5.1
registry-url: https://registry.npmjs.org
- name: install malta
working-directory: docs
run: |
curl -o malta.tgz -L https://github.com/pilcrowonpaper/malta/releases/latest/download/linux-amd64.tgz
tar -xvzf malta.tgz
- name: build
working-directory: docs
run: ./linux-amd64/malta build
- name: install wrangler
run: npm i -g wrangler
- name: deploy
run: wrangler pages deploy docs/dist --project-name lucia-next --branch main
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dist
pnpm-lock.yaml
node_modules
package-lock.json
.DS_Store
8 changes: 8 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
node_modules
/dist

pnpm-lock.yaml
package-lock.json
yarn.lock

5 changes: 5 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"useTabs": true,
"trailingComma": "none",
"printWidth": 120
}
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Lucia

Private link (requires auth): https://lucia-next.pages.dev

## Development

Install [Malta](https://malta.pilcrowonpaper.com) and start the dev server.

```
malta dev
```
42 changes: 42 additions & 0 deletions malta.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "Lucia",
"description": "ok",
"domain": "https://lucia-auth.com",
"twitter": "@lucia_auth",
"asset_hashing": true,
"sidebar": [
{
"title": "Sessions",
"pages": [
["Overview", "/sessions/overview"],
["Database", "/sessions/database"],
["Cookies", "/sessions/cookies"]
]
},
{
"title": "Tutorials",
"pages": [
["GitHub OAuth", "/tutorials/github-oauth"],
["Google OAuth", "/tutorials/google-oauth"]
]
},
{
"title": "Example projects",
"pages": [
["GitHub OAuth", "/examples/github-oauth"],
["Google OAuth", "/examples/google-oauth"],
["Email and password with 2FA", "/examples/email-password-2fa"],
["Email and password with 2FA and WebAuthn", "/examples/email-password-2fa-webauthn"]
]
},
{
"title": "Community",
"pages": [
["GitHub", "https://github.com/lucia-auth/lucia"],
["Discord", "https://discord.com/invite/PwrK3kpVR3"],
["Twitter", "https://x.com/lucia_auth"],
["Donate", "https://github.com/sponsors/pilcrowOnPaper"]
]
}
]
}
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "lucia-next",
"scripts": {
"format": "prettier -w ."
},
"repository": {
"type": "git",
"url": "https://github.com/lucia-auth/next"
},
"author": "pilcrowOnPaper",
"license": "MIT",
"devDependencies": {
"prettier": "^3.0.3"
}
}
5 changes: 5 additions & 0 deletions pages/examples/email-password-2fa-webauthn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Email and password with 2FA and WebAuthn"
---

# Email and password with 2FA and WebAuthn
5 changes: 5 additions & 0 deletions pages/examples/email-password-2fa.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Email and password with 2FA"
---

# Email and password with 2FA
14 changes: 14 additions & 0 deletions pages/examples/github-oauth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title: "GitHub OAuth"
---

# GitHub OAuth

## Repositories

- [Astro](https://github.com/lucia-auth/github-oauth-astro)
- [Next.js](https://github.com/lucia-auth/github-oauth-nextjs)
- [Nuxt](https://github.com/lucia-auth/github-oauth-nuxt)
- [SvelteKit](https://github.com/lucia-auth/github-oauth-sveltekit)

## Important points
5 changes: 5 additions & 0 deletions pages/examples/google-oauth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: "Google OAuth"
---

# Google OAuth
21 changes: 21 additions & 0 deletions pages/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: "Lucia"
---

# Lucia

Lucia is an open source resource on implementing authentication with JavaScript and TypeScript.

The main section is on implementing sessions with your database, library, and framework of choice. Using the API you just defined, you can continue learning by going through the tutorials or by referencing the many fully-fledged examples.

We also recommend checking out [the Copenhagen Book](https://thecopenhagenbook.com). This is a free, online resource covering the various auth concepts in web applications.

## Why not a library?

We've found it extremely hard to develop a library that:

1. Supports the many database libraries, ORMs, frameworks, runtimes, and deployment options available in the ecosystem.
2. Provides enough flexibility for the majority of use cases.
3. Does not add significant complexity to projects.

We came to the conclusion that at least for the core of auth - sessions - it's better to teach the code and concepts rather than to try cramming it into a library. The code is very straightforward and shouldn't take more than 10 minutes to write it once you understand it. As an added bonus, it's fully customizable.
161 changes: 161 additions & 0 deletions pages/sessions/cookies/astro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
title: "Session cookies in Astro"
---

# Session cookies in Astro

_This page builds upon the API defined in the [Database](/sessions/database) page._

## CSRF protection

CSRF protection is a must when using cookies. From Astro v5.0, basic CSRF protection using the `Origin` header is enabled by default. If you're using Astro v4, you must manually enable it by updating the config file.

```ts
// astro.config.mjs
export default defineConfig({
output: "server",
security: {
checkOrigin: false
}
});
```

## Cookies

Session cookies should have the following attributes:

- `HttpOnly`: Cookies are only accessible server-side
- `SameSite=Lax`: Use `Strict` for critical websites
- `Secure`: Cookies can only be sent over HTTPS (Should be omitted when testing on localhost)
- `Max-Age` or `Expires`: Must be defined to persist cookies
- `Path=/`: Cookies can be accessed from all routes

```ts
import type { APIContext } from "astro";

// ...

export async function createSession(userId: number): Promise<Session> {
// ...
}

export async function validateSession(sessionId: string): Promise<SessionValidationResult> {
// ...
}

export async function invalidateSession(sessionId: string): Promise<void> {
// ...
}

export function setSessionCookie(context: APIContext, session: Session): void {
context.cookies.set("session", session.id, {
httpOnly: true,
sameSite: "lax",
secure: import.meta.env.PROD,
expires: session.expiresAt,
path: "/"
});
}

export function deleteSessionCookie(context: APIContext): void {
context.cookies.set("session", "", {
httpOnly: true,
sameSite: "lax",
secure: import.meta.env.PROD,
maxAge: 0,
path: "/"
});
}
```

## Session validation

Sessions can be validated by getting the cookie and using the `validateSession()` function we created. If the session is invalid, delete the session cookie. Importantly, we recommend setting a new session cookie after validation to persist the cookie for an extended time.

```ts
import { validateSession, deleteSessionCookie, setSessionCookie } from "$lib/server/auth";

import type { APIContext } from "astro";

export async function GET(context: APIContext): Promise<Response> {
const sessionId = context.cookies.get("session")?.value ?? null;
if (sessionId === null) {
return new Response(null, {
status: 401
});
}

const { session, user } = await validateSession(sessionId);
if (session === null) {
deleteSessionCookie(context);
return new Response(null, {
status: 401
});
}
setSessionCookie(context, session);

// ...
}
```

We recommend handling session validation in middleware and passing the current auth context to each route.

```ts
// src/env.d.ts

/// <reference types="astro/client" />
declare namespace App {
// Note: 'import {} from ""' syntax does not work in .d.ts files.
interface Locals {
session: import("./lib/server/auth").Session | null;
user: import("./lib/server/auth").User | null;
}
}
```

```ts
// src/middleware.ts
import { validateSession, setSessionCookie, deleteSessionCookie } from "./lib/server/auth";
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async (context, next) => {
const sessionId = context.cookies.get("session")?.value ?? null;
if (sessionId === null) {
context.locals.user = null;
context.locals.session = null;
return next();
}

const { session, user } = await validateSession(sessionId);
if (session !== null) {
setSessionCookie(context, session);
} else {
deleteSessionCookie(context);
}

context.locals.session = session;
context.locals.user = user;
return next();
});
```

Both the current user and session will be available in Astro files and API endpoints.

```ts
---
if (Astro.locals.user === null) {
return Astro.redirect("/login")
}
---
```

```ts
export function GET(context: APIContext): Promise<Response> {
if (context.locals.user === null) {
return new Response(null, {
status: 401
});
}
// ...
}
```
Loading

0 comments on commit 9b2e7de

Please sign in to comment.