Social State

Some protocols (OAuth2, OpenID connect) supports the state parameter, a value the client can include in the request and that the server returns as a parameter unmodified in the response. This parameter should be used mainly to protect an application against CSRF attacks. But it can also be used to remember some state about the user.

To maintain the state in Silhouette, a state handler must be passed to every provider that supports state. This handler must be initialized with a list of state item handlers, whereby each is responsible for it's own use case represented by a state item. All state item handler implementations can be found in the state package.

Default state handler

Silhouette comes with a default implementation of the social state handler, called DefaultSocialStateHandler. This handler should be your preferred implementation, because it's well tested. But it's also possible to create your own implementation if the provided implementation doesn't fit your needs.

📘

Disable state validation

To disable state validation you must initialize the DefaultSocialStateHandler with an empty set. This is needed in some circumstances, where Silhouette doesn't start the authentication process.

List of state item handlers

We provide some built-in state item handlers. But as noted above, every customized state can be implemented to fit your use case.

CsrfState

The CSRF state should be used to protect your application against state based CSRF attacks. The state item handler sends a secure token along with the state to the provider and it also embeds the same token in a signed cookie. If the user comes back after authentication, we check if the token from state is the same as in the cookie. If it's not the same token then a possible CSRF attack was detected and the authentication process fails.

Storing the token in a signed cookie is one of the preferred methods from the OAuth2 RFC and it provides a stateless/scalable approach.

👍

Tip

Please take a look on the configuration settings, on how to configure the provider for this state.

UserState

The user state can be used to transport some custom state. This state item handler must not be added to the state handler, because it's added automatically if you use the new authenticate[S <: SocialStateItem, B](userState: S) method on the supported providers. The user state item can be of any type as long there is an implicit JSON format in scope. We provide a default item called UserStateItem which is based on a Map[String, String] to handle your user state.

authenticate(UserStateItem(Map("url" -> "https://silhouette.rocks"))).map {
  case Left(result) => 
    result
  case Right(StatefulAuthInfo(authInfo, userState)) =>
    ...
}
case class LoginUrl(url: String)
object LoginUrl {
  implicit val jsonFormat: Format[LoginUrl] = Json.format    
}

authenticate(LoginUrl("https://silhouette.rocks")).map {
  case Left(result) => 
    result
  case Right(StatefulAuthInfo(authInfo, userState)) =>
    ...
}

In both examples, the userState variable in our Right case, contains then the state passed to the authenticate method.