howdy_authentication_cookies
Cookie authentication library for the Howdy Web Server, using ETS as session storage.
Quick start
import gleam/erlang
import gleam/result
import gleam/string
import howdy/server
import howdy/context.{Context}
import howdy/context/user
import howdy/router.{Get, Post, RouterMap, RouterMapWithFilters}
import howdy/response
import howdy/filter
import howdy/authentication/cookie
pub fn main() {
let routes =
RouterMap(
"/",
routes: [
Get("/", fn(_) { response.of_string("hello from root") }),
Post("/signin", do_sign_in),
Post(
"/signout",
fn(context) {
cookie.sign_out(context, response.of_string("signed out"))
},
),
RouterMapWithFilters(
"/secret",
filters: [filter.authenticate(_, cookie.authenticate_with_cookie)],
routes: [Get("/", get_secret_page)],
),
],
)
cookie.new()
assert Ok(_) = server.start(routes)
erlang.sleep_forever()
}
fn get_secret_page(context: Context(a)) {
let email =
context.user
|> user.get_claim("email")
|> result.unwrap("No Email")
response.of_string(string.concat(["Email: ", email]))
}
fn do_sign_in(_context: Context(a)) {
case cookie.sign_in(
"username",
"password",
True,
response.of_string("signed in!"),
validate_user,
) {
Ok(resp) -> resp
Error(_) -> response.of_internal_error("failed to sign you in!")
}
}
fn validate_user(
_username: String,
_password: String,
) -> Result(List(#(String, String)), Nil) {
// TODO: Get the claims from somewhere, database maybe?
Ok([#("email", "test@email.com")])
}
Installation
If available on Hex this package can be added to your Gleam project:
gleam add howdy_authentication_cookies
and its documentation can be found at https://hexdocs.pm/howdy_authentication_cookies.
Configuration
There are several configuration options that allows you to control the cookie authentication procesess better. The default configuration is great for getting started, but is not advised for production, and you should set stronger cookie attributes to prevent unauthorized access to you cookies.
Calling cookie.new()
sets the authentication library to its defaults.
Setting Cookie Attributes
You can modify the attributes of the cookies with the following:
cookie.new_with_config(
CookieConfig(
Some(Attributes(
max_age: None,
domain: None,
path: None,
secure: False,
http_only: False,
same_site: None,
)),
None,
None))
Setting a custom storage method:
In order to change the default session storage of ETS, you can override 3 functions. This would allow you to use a database, reddis or a shared implitmention that multiple servers can use.
You will need to create 3 functions with the following signitures:
// Insert (unique_key, username, timeout_in_seconds, claims)
fn(String, String, Int, List(#(String, String))) -> Bool,
// Lookup input of (unique_key) returns a result of #(unique_key, username, timeout_in_seconds, claims)
fn(String) -> Result(#(String, String, Int, List(#(String, String))), Nil),
// Delete (unique_key)
fn(String) -> Bool,
Example:
fn insert(key, user, timeout, claims) {
False
}
fn lookup(key) {
Error(Nil)
}
fn delete(key) {
False
}
cookie.new_with_config(
CookieConfig(
None,
Some(
DataStorage(
insert,
lookup,
delete
)
),
None))
Config session timeout
By default, if remember me
is set to False
, the session will last 4 hours, if it is set to True
it will last for 30 days. You can change these defaults with the the foolowing:
cookie.new_with_config(
CookieConfig(
None,
None,
Some(
Timeouts(
long: 126144000, // 4 years
short: 10 // 10 seconds
)
)
)
)