Skip to content

Commit

Permalink
refine readme
Browse files Browse the repository at this point in the history
  • Loading branch information
jcs224 committed Sep 16, 2023
1 parent c9caf8c commit b892a5e
Showing 1 changed file with 61 additions and 92 deletions.
153 changes: 61 additions & 92 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,137 +7,98 @@ Use cookie-based sessions with the [Hono](https://hono.dev/) framework. Currentl
- Built-in Memory and Cookie storage drivers (more coming soon)
- Encrypted cookies thanks to [iron-webcrypto](https://github.com/brc-dd/iron-webcrypto)
- Session expiration after inactivity
- Session key rotation, for mitigating session fixation attacks
- Session key rotation*

## Usage
> *CookieStore is not able to rotate session keys by nature of how a pure cookie session works (no server-side state).
### Cloudflare Workers
## Installation and Usage

Install from NPM
```
npm install hono-sessions
```
### Deno

Here is a full-fledged example that shows what a login form might look like:
Simply include the package from `deno.land/x`

```ts
import { Hono } from 'hono'
import { sessionMiddleware, CookieStore, Session } from 'hono-sessions'
import { sessionMiddleware } from 'https://deno.land/x/hono_sessions/mod.ts'
```

const store = new CookieStore()
### Bun, Cloudflare Workers

Install the NPM package
```
npm install hono-sessions
```

const app = new Hono()
## Examples

const sessionRoutes = new Hono<{
### Deno
```ts
import { Hono } from 'https://deno.land/x/[email protected]/mod.ts'
import {
Session,
sessionMiddleware,
CookieStore
} from 'https://deno.land/x/hono_sessions/mod.ts'

const app = new Hono<{
Variables: {
session: Session,
session_key_rotation: boolean
}
}>()

sessionRoutes.use('*', sessionMiddleware({
const store = new CookieStore()

app.use('*', sessionMiddleware({
store,
expireAfterSeconds: 900, // delete session after 15 minutes of inactivity
encryptionKey: 'password_that_is_at_least_32_characters_long' // Required while using CookieStore. Please use a secure, un-guessable password!
encryptionKey: 'password_at_least_32_characters_long', // Required for CookieStore, recommended for others
expireAfterSeconds: 900, // Expire session after 15 minutes
cookieOptions: {
sameSite: 'Lax',
},
}))

sessionRoutes.post('/login', async (c) => {
app.get('/', async (c, next) => {
const session = c.get('session')

const { email, password } = await c.req.parseBody()

if (password === 'correct') {
c.set('session_key_rotation', true)
session.set('email', email)
session.set('failed-login-attempts', null)
session.flash('message', 'Login Successful')
if (session.get('counter')) {
session.set('counter', session.get('counter') as number + 1)
} else {
const failedLoginAttempts = (session.get('failed-login-attempts') || 0) as number
session.set('failed-login-attempts', failedLoginAttempts + 1)
session.flash('error', 'Incorrect username or password')
session.set('counter', 1)
}

return c.redirect('/')
})

sessionRoutes.post('/logout', (c) => {
c.get('session').deleteSession()
return c.redirect('/')
})

sessionRoutes.get('/', (c) => {
const session = c.get('session')

const message = session.get('message') || ''
const error = session.get('error') || ''
const failedLoginAttempts = session.get('failed-login-attempts')
const email = session.get('email')

return c.html(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hono Sessions</title>
</head>
<body>
<p>${message}</p>
<p>${error}</p>
<p>${failedLoginAttempts ? `Failed login attempts: ${failedLoginAttempts}` : ''}</p>
${email ?
`<form id="logout" action="/logout" method="post">
<button name="logout" type="submit">Log out ${email}</button>
</form>`
:
`<form id="login" action="/login" method="post">
<p>
<input id="email" name="email" type="text" placeholder="[email protected]">
</p>
<p>
<input id="password" name="password" type="password" placeholder="password">
</p>
<button name="login" type="submit">Log in</button>
</form>`
}
</body>
</html>`)
return c.html(`<h1>You have visited this page ${ session.get('counter') } times</h1>`)
})

app.route('/', sessionRoutes)

export default app
Deno.serve(app.fetch)
```

### Deno

There is a Deno package available on `deno.land/x`.
### Bun

```ts
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { sessionMiddleware, CookieStore, Session } from 'https://deno.land/x/hono_sessions/mod.ts'
import { Hono } from 'hono'
import { sessionMiddleware, CookieStore, Session } from 'hono-sessions'

// Same as CF Workers, however instead of:
// export default app
// Same as Deno, however instead of:
// Deno.serve(app.fetch)
// use:

Deno.serve(app.fetch)
export default {
port: 3000,
fetch: app.fetch
}
```

### Bun
### Cloudflare Workers

```ts
import { Hono } from 'hono'
import { sessionMiddleware, CookieStore, Session } from 'hono-sessions'

// Same as CF Workers, however instead of:
// export default app
// Same as Deno, however instead of:
// Deno.serve(app.fetch)
// use:

export default {
port: 3000,
fetch: app.fetch
}
export default app
```

## Contributing
Expand All @@ -147,5 +108,13 @@ This package is built Deno-first, so you'll need to have Deno installed in your
Once Deno is installed, there is a test server you can run a basic web server to check your changes:

```
deno run --allow-net --watch test/server_deno.ts
deno run --allow-net --watch test/deno/server_deno.ts
```

There's also a [Playwright](https://playwright.dev/) test suite. By default, it is set up to run a Deno server with the MemoryStore driver. In Github actions, it runs through a series of runtimes and storage drivers when a pull request is made.

```
cd playwright
npm install
npx playwright test
```

0 comments on commit b892a5e

Please sign in to comment.