{"id":15523612,"url":"https://github.com/maxcountryman/tower-sessions","last_synced_at":"2025-04-13T09:00:12.522Z","repository":{"id":196121846,"uuid":"694304277","full_name":"maxcountryman/tower-sessions","owner":"maxcountryman","description":"🥠 Sessions as a `tower` and `axum` middleware.","archived":false,"fork":false,"pushed_at":"2024-09-03T16:55:11.000Z","size":357,"stargazers_count":248,"open_issues_count":2,"forks_count":42,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-30T03:42:49.112Z","etag":null,"topics":["axum","axum-middleware","cookies","sessions","tower"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxcountryman.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["maxcountryman"]}},"created_at":"2023-09-20T18:19:15.000Z","updated_at":"2024-10-26T18:14:42.000Z","dependencies_parsed_at":"2023-09-25T22:47:28.539Z","dependency_job_id":"6cc46771-6216-4666-af8c-175f687955bb","html_url":"https://github.com/maxcountryman/tower-sessions","commit_stats":{"total_commits":252,"total_committers":25,"mean_commits":10.08,"dds":"0.15476190476190477","last_synced_commit":"d5592f1de4ae98db9eb1490e931a924462bbe464"},"previous_names":["maxcountryman/tower-sessions"],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxcountryman%2Ftower-sessions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxcountryman%2Ftower-sessions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxcountryman%2Ftower-sessions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxcountryman%2Ftower-sessions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxcountryman","download_url":"https://codeload.github.com/maxcountryman/tower-sessions/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248688561,"owners_count":21145765,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["axum","axum-middleware","cookies","sessions","tower"],"created_at":"2024-10-02T10:46:10.878Z","updated_at":"2025-04-13T09:00:12.440Z","avatar_url":"https://github.com/maxcountryman.png","language":"Rust","funding_links":["https://github.com/sponsors/maxcountryman"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n    tower-sessions\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    🥠 Sessions as a `tower` and `axum` middleware.\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://crates.io/crates/tower-sessions\"\u003e\n        \u003cimg src=\"https://img.shields.io/crates/v/tower-sessions.svg\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://docs.rs/tower-sessions\"\u003e\n        \u003cimg src=\"https://docs.rs/tower-sessions/badge.svg\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/maxcountryman/tower-sessions/actions/workflows/rust.yml\"\u003e\n        \u003cimg src=\"https://github.com/maxcountryman/tower-sessions/actions/workflows/rust.yml/badge.svg\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://codecov.io/gh/maxcountryman/tower-sessions\" \u003e \n        \u003cimg src=\"https://codecov.io/gh/maxcountryman/tower-sessions/graph/badge.svg?token=74POF0TJDN\"/\u003e \n    \u003c/a\u003e\n\u003c/div\u003e\n\n## 🎨 Overview\n\nThis crate provides sessions, key-value pairs associated with a site\nvisitor, as a `tower` middleware.\n\nIt offers:\n\n- **Pluggable Storage Backends:** Bring your own backend simply by\n  implementing the `SessionStore` trait, fully decoupling sessions from their\n  storage.\n- **Minimal Overhead**: Sessions are only loaded from their backing stores\n  when they're actually used and only in e.g. the handler they're used in.\n  That means this middleware can be installed anywhere in your route\n  graph with minimal overhead.\n- **An `axum` Extractor for `Session`:** Applications built with `axum`\n  can use `Session` as an extractor directly in their handlers. This makes\n  using sessions as easy as including `Session` in your handler.\n- **Simple Key-Value Interface:** Sessions offer a key-value interface that\n  supports native Rust types. So long as these types are `Serialize` and can\n  be converted to JSON, it's straightforward to insert, get, and remove any\n  value.\n- **Strongly-Typed Sessions:** Strong typing guarantees are easy to layer on\n  top of this foundational key-value interface.\n\nThis crate's session implementation is inspired by the [Django sessions middleware](https://docs.djangoproject.com/en/4.2/topics/http/sessions) and it provides a transliteration of those semantics.\n\n### Session stores\n\nSession data persistence is managed by user-provided types that implement\n`SessionStore`. What this means is that applications can and should\nimplement session stores to fit their specific needs.\n\nThat said, a number of session store implementations already exist and may be\nuseful starting points.\n\n| Crate                                                                                                            | Persistent | Description                                                 |\n| ---------------------------------------------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------- |\n| [`tower-sessions-dynamodb-store`](https://github.com/necrobious/tower-sessions-dynamodb-store)                   | Yes        | DynamoDB session store                                      |\n| [`tower-sessions-file-store`](https://github.com/mousetail/tower-sessions-file-store)                            | Yes        | Local filesystem store                     |\n| [`tower-sessions-firestore-store`](https://github.com/AtTheTavern/tower-sessions-firestore-store)                | Yes        | Firestore session store                                     |\n| [`tower-sessions-libsql-store`](https://github.com/daybowbow-dev/tower-sessions-libsql-store)                    | Yes        | libSQL session store                                        |\n| [`tower-sessions-mongodb-store`](https://github.com/maxcountryman/tower-sessions-stores/tree/main/mongodb-store) | Yes        | MongoDB session store                                       |\n| [`tower-sessions-moka-store`](https://github.com/maxcountryman/tower-sessions-stores/tree/main/moka-store)       | No         | Moka session store                                          |\n| [`tower-sessions-redis-store`](https://github.com/maxcountryman/tower-sessions-stores/tree/main/redis-store)     | Yes        | Redis via `fred` session store                              |\n| [`tower-sessions-rorm-store`](https://github.com/rorm-orm/tower-sessions-rorm-store)                             | Yes        | SQLite, Postgres and Mysql session store provided by `rorm` |\n| [`tower-sessions-rusqlite-store`](https://github.com/patte/tower-sessions-rusqlite-store)                        | Yes        | Rusqlite session store                                      |\n| [`tower-sessions-sled-store`](https://github.com/Zatzou/tower-sessions-sled-store)                               | Yes        | Sled session store                                          |\n| [`tower-sessions-sqlx-store`](https://github.com/maxcountryman/tower-sessions-stores/tree/main/sqlx-store)       | Yes        | SQLite, Postgres, and MySQL session stores                  |\n| [`tower-sessions-surrealdb-store`](https://github.com/rynoV/tower-sessions-surrealdb-store)                      | Yes        | SurrealDB session store                                     |\n\nHave a store to add? Please open a PR adding it.\n\n### User session management\n\nTo facilitate authentication and authorization, we've built [`axum-login`](https://github.com/maxcountryman/axum-login) on top of this crate. Please check it out if you're looking for a generalized auth solution.\n\n## 📦 Install\n\nTo use the crate in your project, add the following to your `Cargo.toml` file:\n\n```toml\n[dependencies]\ntower-sessions = \"0.14.0\"\n```\n\n## 🤸 Usage\n\n### `axum` Example\n\n```rust\nuse std::net::SocketAddr;\n\nuse axum::{response::IntoResponse, routing::get, Router};\nuse serde::{Deserialize, Serialize};\nuse time::Duration;\nuse tower_sessions::{Expiry, MemoryStore, Session, SessionManagerLayer};\n\nconst COUNTER_KEY: \u0026str = \"counter\";\n\n#[derive(Default, Deserialize, Serialize)]\nstruct Counter(usize);\n\nasync fn handler(session: Session) -\u003e impl IntoResponse {\n    let counter: Counter = session.get(COUNTER_KEY).await.unwrap().unwrap_or_default();\n    session.insert(COUNTER_KEY, counter.0 + 1).await.unwrap();\n    format!(\"Current count: {}\", counter.0)\n}\n\n#[tokio::main]\nasync fn main() {\n    let session_store = MemoryStore::default();\n    let session_layer = SessionManagerLayer::new(session_store)\n        .with_secure(false)\n        .with_expiry(Expiry::OnInactivity(Duration::seconds(10)));\n\n    let app = Router::new().route(\"/\", get(handler)).layer(session_layer);\n\n    let addr = SocketAddr::from(([127, 0, 0, 1], 3000));\n    let listener = tokio::net::TcpListener::bind(\u0026addr).await.unwrap();\n    axum::serve(listener, app.into_make_service())\n        .await\n        .unwrap();\n}\n```\n\nYou can find this [example][counter-example] as well as other example projects in the [example directory][examples].\n\n\u003e [!NOTE]\n\u003e See the [crate documentation][docs] for more usage information.\n\n## 🦺 Safety\n\nThis crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in 100% safe Rust.\n\n## 🛟 Getting Help\n\nWe've put together a number of [examples][examples] to help get you started. You're also welcome to [open a discussion](https://github.com/maxcountryman/tower-sessions/discussions/new?category=q-a) and ask additional questions you might have.\n\n## 👯 Contributing\n\nWe appreciate all kinds of contributions, thank you!\n\n[counter-example]: https://github.com/maxcountryman/tower-sessions/tree/main/examples/counter.rs\n[examples]: https://github.com/maxcountryman/tower-sessions/tree/main/examples\n[docs]: https://docs.rs/tower-sessions\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxcountryman%2Ftower-sessions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxcountryman%2Ftower-sessions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxcountryman%2Ftower-sessions/lists"}