{"id":13801343,"url":"https://github.com/softwaremill/akka-http-session","last_synced_at":"2025-04-04T12:07:55.713Z","repository":{"id":34384665,"uuid":"38311352","full_name":"softwaremill/akka-http-session","owner":"softwaremill","description":"Web \u0026 mobile client-side akka-http sessions, with optional JWT support","archived":false,"fork":false,"pushed_at":"2023-08-29T17:18:02.000Z","size":809,"stargazers_count":440,"open_issues_count":11,"forks_count":58,"subscribers_count":47,"default_branch":"master","last_synced_at":"2025-03-28T11:07:54.915Z","etag":null,"topics":["akka","akka-http","csrf","java","scala","session","session-cookie","session-management"],"latest_commit_sha":null,"homepage":"https://softwaremill.com/open-source/","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/softwaremill.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"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}},"created_at":"2015-06-30T13:40:05.000Z","updated_at":"2025-03-09T17:55:01.000Z","dependencies_parsed_at":"2024-01-05T21:57:18.496Z","dependency_job_id":null,"html_url":"https://github.com/softwaremill/akka-http-session","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fakka-http-session","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fakka-http-session/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fakka-http-session/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softwaremill%2Fakka-http-session/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/softwaremill","download_url":"https://codeload.github.com/softwaremill/akka-http-session/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174418,"owners_count":20896078,"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":["akka","akka-http","csrf","java","scala","session","session-cookie","session-management"],"created_at":"2024-08-04T00:01:21.785Z","updated_at":"2025-04-04T12:07:55.697Z","avatar_url":"https://github.com/softwaremill.png","language":"Scala","readme":"![akka-http-session](https://github.com/softwaremill/akka-http-session/raw/master/banner.png)\n\n[![Build Status](https://travis-ci.org/softwaremill/akka-http-session.svg?branch=master)](https://travis-ci.org/softwaremill/akka-http-session)\n[![Join the chat at https://gitter.im/softwaremill/akka-http-session](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/softwaremill/akka-http-session?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.softwaremill.akka-http-session/core_2.12/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.softwaremill.akka-http-session/core_2.12)\n\n[`akka-http`](https://doc.akka.io/docs/akka-http/current/index.html) is an Akka \nmodule, originating from [spray.io](http://spray.io), for building *reactive* REST services with an elegant DSL. \n[`pekko-http`](https://pekko.apache.org/docs/pekko-http/current/) is an open-source fork of akka-http.\n\n`akka-http` is a great toolkit for building backends for single-page or mobile applications. In almost all apps there \nis a need to maintain user sessions, make sure session data is secure and cannot be tampered with.\n\n`akka-http-session` provides directives for client-side session management in web and mobile applications, using cookies\nor custom headers + local storage, with optional [Json Web Tokens](http://jwt.io/) format support. \n\nA [comprehensive FAQ](https://github.com/softwaremill/akka-http-session-faq) is available, along with code examples (in Java, but easy to translate to Scala) which answers many common questions on how sessions work, how to secure them and implement using akka-http.\n\nEach `akka-http-session` module for `akka-http` has a corresponding `pekko-http` module, with a different group id\n(see bottom of the readme).\n\n## What is a session?\n\nSession data typically contains at least the `id` or `username` of the logged in user. This id must be secured so that a \nsession cannot be \"stolen\" or forged easily.\n\nSessions can be stored on the server, either in-memory or in a database, with the session `id` sent to the client,\nor entirely on the client in a serialized format. The former approach requires sticky sessions or additional shared\nstorage, while using the latter (which is supported by this library) sessions can be easily deserialized on any server.\n  \nA session is a string token which is sent to the client and should be sent back to the server on every request.\n\nTo prevent forging, serialized session data is **signed** using a server secret. The signature is appended to the\nsession data that is sent to the client, and verified when the session token is received back.\n\n## `akka-http-session` features\n\n* type-safe client-side sessions\n* sessions can be encrypted\n* sessions contain an expiry date\n* cookie or custom header transport\n* support for [JWT](http://jwt.io/)\n* refresh token support (e.g. to implement \"remember me\")\n* CSRF tokens support\n* Java \u0026 Scala APIs\n\n## Example\n\nYou can try out a simple example by running [`com.softwaremill.example.ScalaExample`](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/ScalaExample.scala) or [`com.softwaremill.example.JavaExample`](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/JavaExample.java) and opening [http://localhost:8080](http://localhost:8080).\n\n## `SessionManager` \u0026 configuration\n\nAll directives require an (implicit for scala) instance of a `SessionManager[T]` (or `SessionManager\u003cT\u003e`), which can be created by providing a server \nsecret (via a `SessionConfig`). The secret should be a long, random string unique to each environment your app is\nrunning in. You can generate one with `SessionUtil.randomServerSecret()`. Note that when you change the secret, \nall sessions will become invalid.\n\nA `SessionConfig` instance can be created using [Typesafe config](https://github.com/typesafehub/config).\nThe only value that you need to provide is `akka.http.session.server-secret`,\npreferably via `application.conf` (then you can safely call `SessionConfig.fromConfig`) or by using \n`SessionConfig.default()`.\n\nYou can customize any of the [default config options](https://github.com/softwaremill/akka-http-session/blob/master/core/src/main/resources/reference.conf) \neither by modifying them through `application.conf` or by modifying the `SessionConfig` case class. If a value has\ntype `Option[]`, you can set it to `None` by using a `none` value in the config file (for both java and scala).\n\nWhen using cookies, by default the `secure` attribute of cookies is not set (for development), however it is \nrecommended that all sites use `https` and all cookies have this attribute set. \n\n## Client-side sessions\n\nAll session-related directives take at least two parameters:\n \n* session continuity: `oneOff` vs `refreshable`; specifies what should happen when the session expires. If `refreshable`\nand a refresh token is present, the session will be re-created. See below for details.\n* session transport: `usingCookies` vs `usingHeaders`\n\nTypically, you would create aliases for the session-related directives which use the right parameters basing on the\ncurrent request and logic specific to your application.\n\n### Cookies vs header\n\nSession data can be sent to the client using cookies or custom headers. The first approach is the simplest to use,\nas cookies are automatically sent to the server on each request. \n\nHowever, cookies have some security vulnerabilities, and are typically not used in mobile applications. For these\nscenarios, session data can be transported using custom headers (the names of the headers are configurable in \nthe config).\n\nWhen using headers, you need to store the session (and, if used, refresh-) tokens yourself. These tokens can be \nstored in-memory, or persistently e.g. using the browser's local storage.\n\nYou can dynamically decide which transport to use, basing e.g. on the user-agent or other request properties.\n\n### Basic usage\n\nSessions are typed. The `T` type parameter in `SessionManager[T]` (or `SessionManager\u003cT\u003e`) determines what data is stored in the session. \nBasic types like `String`, `Int`, `Long`, `Float`, `Double` and `Map[String, String]` (`Map\u003cString, String\u003e`) are supported out-of-the box. \nSupport for other types can be added by providing a (an implicit for scala) `SessionSerializer[T, String]` (`SessionSerializer\u003cT, String\u003e`). For case classes, it's most \nconvenient to use a `MultiValueSessionSerializer[T]` or (`MultiValueSessionSerializer\u003cT\u003e`) which should convert the instance into a `String -\u003e String` map \n(nested types are not supported on purpose, as session data should be small \u0026 simple). Examples of `SessionSerializer` and `MultiValueSessionSerializer` \nusage can be found [here](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/serializers) for scala and [here](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/serializers) for java. \n\nHere are code samples in [scala](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/session/manager/MyScalaSessionManager.scala) and [java](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/session/manager/MyJavaSessionManager.java) illustrating how to create a session manager where the session content will be a single `Long` number.\n\nThe basic directives enable you to set, read and invalidate the session. To create a new client-side session (create\nand set a new session cookie), you need to use the `setSession` directive. See how it's done in [java](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/session/SetSessionJava.java) and [scala](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/session/SetSessionScala.scala).\n\nNote that when using cookies, their size is limited to 4KB, so you shouldn't put too much data in there (the signature \ntakes about 50 characters). \n\nYou can require a session to be present, optionally require a session or get a full description of possible session decode outcomes. \nCheck [java](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/session/VariousSessionsJava.java) and [scala](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/session/VariousSessionsScala.scala) examples for details.\n\nIf a required session is not present, by default a `403` HTTP status code is returned. Finally, a session can be invalidated. See how it's done in examples for [java](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/session/SessionInvalidationJava.java) and [scala](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/session/SessionInvalidationScala.scala).\n\n### Encrypting the session\n\nIt is possible to encrypt the session data by modifying the `akka.http.session.encrypt-data` config option. When \nsessions are encrypted, it's not possible to read their content on the client side.\n\nThe key used for encrypting will be calculated basing on the server secret.\n\n### Session expiry/timeout\n\nBy default, sessions expire after a week. This can be disabled or changed with the `akka.http.session.max-age` config\noption.\n\nNote that when using cookies, even though the cookie sent will be a session cookie, it is possible that the client \nwill have the browser open for a very long time, [uses Chrome or FF](http://stackoverflow.com/questions/10617954/chrome-doesnt-delete-session-cookies), \nor if an attacker steals the cookie, it can be re-used. Hence having an expiry date for sessions is highly recommended.\n\n## JWT: encoding sessions\n\nBy default, sessions are encoded into a string using a custom format, where expiry/data/signature parts are separated using `-`, and data fields are separated using `=` and url-encoded.\n\nYou can also encode sessions in the [Json Web Tokens](http://jwt.io) format, by adding the additional `jwt` dependency, which makes use of [`json4s`](http://json4s.org).\n\nWhen using JWT, you need to provide a serializer which serializes session data to a `JValue` instead of a `String`. \nA number of serializers for the basic types are present in `JValueSessionSerializer`, as well as a generic serializer for case classes (used above).\n\nYou may also find it helpful to include the json4s-ext library which provides serializers for common Java types such as  `java.util.UUID`, `org.joda.time._` and Java enumerations.\n\nGrab some [java](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/java/com/softwaremill/example/jwt/JavaJwtExample.java) and [scala](https://github.com/softwaremill/akka-http-session/blob/master/example/src/main/scala/com/softwaremill/example/serializers/JWTSerializersScala.scala) examples.\n\nThere are many tools available to read JWT session data using various platforms, e.g. \n[for Angular](https://github.com/auth0/angular-jwt).\n\nIt is also possible to customize the session data content generated by overriding appropriate methods in \n`JwtSessionEncoder` (e.g. provide additional claims in the payload).\n\n## Registered JWT claims support\n\nThis library supports all registered claims mentioned in [RFC 7519, Section 4.1](https://tools.ietf.org/html/rfc7519#page-9).\n\nStatic claims such as `iss` (*Issuer*), `sub` (*Subject*) and `aud` (*Audience*) can be configured by setting `akka.http.session.jwt.iss`, `akka.http.session.jwt.sub` and `akka.http.session.jwt.aud` string properties, respectively.\n\nBecause claims such as `exp` (*Expiration Time*) and `nbf` (*Not Before*) depend on the time at which the JWT was issued, configuration expects durations instead of fixed timestamps.\nEffective claim values are then calculated by adding these offsets to the current timestamp (the JWT's issue time).\nThe offset values are configured via keys defined under `akka.http.session.jwt.exp-timeout` and `akka.http.session.jwt.nbf-offset`.\n\nIf `exp-timeout` is not defined, value of `akka.http.session.max-age` would be used instead.\n\n`iat` (*Issued At*) claim represents issue time and cannot be customized. Although you can decide to include this claim in your tokens or not by setting `akka.http.session.jwt.include-iat` to `true` or `false`. By default, this claim is not included.\n\n`jti` (*JWT ID*) claim is a case-sensitive string containing a unique identifier for the JWT. It must be unique per token and collisions must be prevented even among values produced by different issuers.\nAkka-http-session will compute and include `jti` claim if `akka.http.session.jwt.include-jti` is set to `true` (it's disabled by default).\nToken ids are generated using the below scheme:\n\n`\u003ciss claim value\u003e-\u003crandom UUID\u003e` or just `\u003crandom UUID\u003e`, depending on the `iss` claim presence.\n\nYou can find a sample claims configuration below:\n````hocon\nakka.http.session {\n  jwt {\n    iss = \"Issuer\"\n    sub = \"Subject\"\n    aud = \"Audience\"\n    exp-timeout = 7 days\n    nbf-offset = 5 minutes\n    include-iat = true\n    include-jti = true\n  }\n}\n\n````\n\n## Signing session using a configurable algorithm\n\nIn the case of JWT, it's possible to configure which JWS algorithm should be used. Currently, supported ones are:\n* `HS256` - HMAC using SHA-256 (used by default)\n* `RS256` - RSA (RSASSA-PKCS1-v1_5) using SHA-256\n\nAll non-JWT sessions use HMAC with SHA-256 and this cannot be configured.\n\n### Configuring JWS (for JSON Web Tokens only)\n\nIn order to start using RSA algorithm you have to configure `akka.http.session.jws.alg` and `akka.http.session.jws.rsa-private-key` properties:\n````hocon\nakka.http.session {\n  jws {\n    alg = \"RS256\"\n    rsa-private-key = \"\u003cyour private PKCS#8 key goes here\u003e\"\n  }\n}\n````\n\nBecause `HS256` is used by default you may skip the `jws` configuration and rely on a reference configuration delivered with the library. \nAlternatively, if you prefer to be more explicit, you might follow this configuration template:\n````hocon\nakka.http.session {\n  server-secret = \"\u003cat least 64-digits length secret goes here\u003e\"\n  jws {\n    alg = \"HS256\"\n  }\n}\n````\n\nYou might notice that even if you want to sign your sessions using RSA key and encryption is disabled, you still have to define the server-secret property.\n\nThat's because all non-JWT sessions still depend on HMAC with SHA256 algorithm which requires the server secret and the library cannot determine which session encoder(s) will be used (it's specified in the client's code).\n\n## CSRF protection (cookie transport only)\n\nCSRF is a kind of an attack where an attacker issues a `GET` or `POST` request on behalf of a user, if the user e.g.\nclicks on a specially constructed link. See the [OWASP page](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet)\nor the [Play! docs](https://www.playframework.com/documentation/2.2.x/JavaCsrf) for a thorough introduction.\n\nWeb apps which use cookies for session management should be protected against CSRF attacks. This implementation:\n\n* assumes that `GET` requests are non-mutating (have no side effects)\n* uses double-submit cookies to verify requests\n* requires the token to be set in a custom header or (optionally) in a form field\n* generates a new token on the first `GET` request that doesn't have the token cookie set\n\nNote that if the token is passed in a form field, the website isn't protected by HTTPS or you don't control all \nsubdomains, this scheme [can be broken](http://security.stackexchange.com/questions/59470/double-submit-cookies-vulnerabilities/61039#61039).\nCurrently, setting a custom header seems to be a secure solution, and is what a number of projects do (that's why, when\nusing custom headers to send session data, no additional protection is needed).\n\nIt is recommended to generate a new CSRF token after logging in, see [this SO question](http://security.stackexchange.com/questions/22903/why-refresh-csrf-token-per-form-request).\nA new token can be generated using the `setNewCsrfToken` directive.\n\nBy default the name of the CSRF cookie and the custom header matches what [AngularJS expects and sets](https://docs.angularjs.org/api/ng/service/$http).\nThese can be customized in the config.\n     \n## Refresh tokens (a.k.a \"remember me\")\n\nIf you'd like to implement persistent, \"remember-me\" sessions, you should use `refreshable` instead of `oneOff`\nsessions. This is especially useful in mobile applications, where you log in once, and the session is remembered for\na long time. Make sure to adjust the `akka.http.session.refresh-token.max-age` config option appropriately \n(defaults to 1 month)!\n\nYou can dynamically decide, basing on the request properties (e.g. a query parameter), if a session should be\nrefreshable or not. Just pass the right parameter to `setSession`.\n\nWhen using refreshable sessions, in addition to an (implicit) `SessionManager` instance, you need to provide an \nimplementation of the `RefreshTokenStorage` trait. This trait has methods to lookup, store and delete refresh tokens. \nTypically it would use some persistent storage.\n\nThe tokens are never stored directly, instead only token hashes are passed to the storage. That way even if the token\ndatabase is leaked, it won't be possible to forge sessions using the hashes. Moreover, in addition to the token hash,\na selector value is stored. That value is used to lookup stored hashes; tokens are compared using a special\nconstant-time comparison method, to prevent timing attacks.\n\nWhen a session expires or is not present, but the refresh token is (sent from the client using either a cookie,\nor a custom header), a new session will be created (using the `RefreshTokenLookupResult.createSession` function), \nand a new refresh token will be created.\n\nNote that you can differentiate between sessions created from refresh tokens and from regular authentication\nby storing appropriate information in the session data. That way, you can force the user to re-authenticate \nif the session was created by a refresh token before crucial operations.\n\nIt is of course possible to read `oneOff`-session using `requiredSession(refreshable, ...)`. If a session was created\nas `oneOff`, using `refreshable` has no additional effect.\n\n### Touching sessions\n\nThe semantics of `touch[Required|Optional]Session()` are a bit subtle. You can still use expiring client\nsessions when using refresh tokens. You will then have 2 stages of expiration: expiration of the client session\n(should be shorter), and expiry of the refresh token. That way you can have strongly-authenticated sessions\nwhich expire fast, and weaker-authenticated re-creatable sessions (as described in the paragraph above).\n\nWhen touching an existing session, the refresh token will not be re-generated and extended, only the session\ncookie.\n\n## Links\n\n* [Bootzooka](https://github.com/softwaremill/bootzooka), a web application template project using `akka-http` and `akka-http-session`\n* [Spray session](https://github.com/gnieh/spray-session), similar project for spray.io\n* [Spray SPA](https://github.com/enetsee/Spray-SPA), a single-page-application demo built using spray.io, also\ncontaining an implementation of client-side sessions\n* [Play framework](https://playframework.com), a full web framework, from which parts of the session encoding/decoding\ncode was taken\n* [Rails security guide](http://guides.rubyonrails.org/security.html#session-storage), a description of how sessions are\nstored in Rails\n* [Akka-Http issue 114](https://github.com/akka/akka-http/issues/114) for implementing similar functionality straight in Akka-Http\n* [Implementing remember me](https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence#title.2)\n* [The definitive guide to form-based website authorization](http://stackoverflow.com/questions/549/the-definitive-guide-to-form-based-website-authentication)\n* [The Anatomy of a JSON Web Token](https://scotch.io/tutorials/the-anatomy-of-a-json-web-token)\n* [Cookies vs tokens](https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/)\n\n## Using from SBT\n\nFor `akka-http` version `10+`:\n\n````scala\nlibraryDependencies += \"com.softwaremill.akka-http-session\" %% \"core\" % \"0.7.1\"\nlibraryDependencies += \"com.softwaremill.akka-http-session\" %% \"jwt\"  % \"0.7.1\" // optional\n````\n\nFor `pekko-http`:\n\n````scala\nlibraryDependencies += \"com.softwaremill.pekko-http-session\" %% \"core\" % \"0.7.1\"\nlibraryDependencies += \"com.softwaremill.pekko-http-session\" %% \"jwt\"  % \"0.7.1\" // optional\n````\n\n## Updating\n\nCertain releases changed the client token encoding/serialization. In those cases, it's important to enable the appropriate\ntoken migrations, otherwise existing client sessions will be invalid (and your users will be logged out).\n\nWhen updating from a version before 0.5.3, set `akka.http.session.token-migration.v0-5-3.enabled = true`.\n\nWhen updating from a version before 0.5.2, set `akka.http.session.token-migration.v0-5-2.enabled = true`.\n\nNote that when updating through multiple releases, be sure to enable all the appropriate migrations.\n\nFor versions prior to 0.5.0, no migration path is provided. However, you can implement your own encoders/serializers\nto support migrating from whatever version you are using.\n\nSince token changes may be security related, migrations should be enabled for the shortest period of time\nafter which the vast majority of client tokens have been migrated.\n\n## Commercial Support\n\nWe offer commercial support for akka-http-session and related technologies, as well as development services. [Contact us](https://softwaremill.com) to learn more about our offer!\n\n## Copyright\n\nCopyright (C) 2016-2023 SoftwareMill [https://softwaremill.com](https://softwaremill.com).\n","funding_links":[],"categories":["Table of Contents","Authentication"],"sub_categories":["Authentication"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftwaremill%2Fakka-http-session","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoftwaremill%2Fakka-http-session","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftwaremill%2Fakka-http-session/lists"}