envelopmenuskypeburger-menulink-externalfacebooktwitterlinkedin2crossgithub-minilinkedin-minitwitter-miniarrow_rightarrow_leftphonegithubphone-receiverstack-overflow

Client-side sessions for akka-http

akka-http is an experimental Akka module, originating from spray.io, for building reactive REST services with an elegant DSL. It has almost all of the required functionalities to serve as a backend for a web (single-page-)application, with one exception: session handling. The akka-http-session project aims to fill that gap (star if you like the code / find it interesting!).

akka-http-session provides three main features:

  • client-side sessions, using session cookies, with signed content, optionally encrypted and expiring after the given period
  • CSRF protection using double-submit cookies
  • remember me support using persistent cookies and a server-side token store

The sessions are typed, which means that you can easily store simple case classes in the client-side session in addition to values of basic types.

Let's take a look at some code! Here we have login, logout and get-data endpoints using client-side sessions where all non-GET requests are protected against CSRF:

case class ExampleSession(username: String)

val sessionConfig = SessionConfig.default("server_secret_please_change_me")
implicit val sessionManager = new SessionManager[ExampleSession](sessionConfig)

randomTokenCsrfProtection() {
  pathPrefix("api") {
    path("do_login") {
      post {
        entity(as[String]) { body =>
          logger.info(s"Logging in $body")
          setSession(ExampleSession(body)) {
            setNewCsrfToken() { ctx => ctx.complete("ok") }
          }
        }
      }
    } ~
    path("do_logout") {
      post {
        requiredSession() { session => // session: ExampleSession
          invalidateSession() { ctx =>
            logger.info(s"Logging out $session")
            ctx.complete("ok")
          }
        }
      }
    } ~
    path("current_login") {
      get {
        requiredSession() { session => ctx =>
          logger.info("Current session: " + session)
          ctx.complete(session.username)
        }
      }
    }
  } ~
  pathPrefix("site") {
    getFromResourceDirectory("") // serve the .html and .js files
  }
}

You can try this out locally by running the example; the code in the repo also contains a simple HTML page to test logging in & out, plus fetching the login-protected data.

When dealing with sessions and cookies, security is one of the main concerns. That's why the project aims to follow the current best practices, for example:

  • sign the session content using a long, environment-specific secret key
  • use headers as the preferred method for submitting the CSRF token (Angular-compatible)
  • store remember-me token hashes, not the tokens directly
  • store remember-me token selectors and token hashes separately, to prevent timing attacks

Take a look at the readme, it contains a much more comprehensive documentation on the available directives, plus a number of links explaining the possible session/cookie-handling designs and their strenghts/weaknesses.

If you like the project - star it! Also any feedback in the form of issues / PRs is always welcome!

scala times
Interested in Scala news?

Subscribe to Scala Times Newspaper delivered weekly by SoftwareMill straight to your inbox.