§Header Filters
In Lagom you may add HeaderFilters to your service descriptor. In a HeaderFilter you will usually handle protocol negotiation or authentication. 
A single HeaderFilter implementation may transform a request leaving a client or entering a server and a response leaving a server and entering a client. Here’s an example that uses the User-Agent header to read the service name:
object UserAgentHeaderFilter extends HeaderFilter {
  override def transformClientRequest(request: RequestHeader): RequestHeader = {
    request.principal match {
      case Some(principal: ServicePrincipal) =>
        request.withHeader(HeaderNames.USER_AGENT, principal.serviceName)
      case _ => request
    }
  }
  override def transformServerRequest(request: RequestHeader): RequestHeader = {
    request.getHeader(HeaderNames.USER_AGENT) match {
      case Some(userAgent) =>
        request.withPrincipal(ServicePrincipal.forServiceNamed(userAgent))
      case _ =>
        request
    }
  }
  override def transformServerResponse(
      response: ResponseHeader,
      request: RequestHeader
  ): ResponseHeader = response
  override def transformClientResponse(
      response: ResponseHeader,
      request: RequestHeader
  ): ResponseHeader = response
}This UserAgentHeaderFilter is the default HeaderFilter any Lagom service will use if none is specified. It uses a ServicePrincipal which identifies the client with the service name.
In UserAgentHeaderFilter the code at transformClientRequest will be invoked when preparing a client invocation to add a User-Agent header if a ServicePrincipal was specified on the request. Note that by default, Lagom will automatically pass the current services name as the ServicePrincipal when it makes a request. On the server end transformServerRequest will be used to read the User-Agent header and set that value as the request’s Principal.
Keep in mind that a header filter should only be used to deal with cross cutting protocol concerns, and nothing more. For example, you may have a header filter that describes how the current authenticated user is communicated over the HTTP protocol (by adding a user header, for example). Cross cutting domain concerns, such as authentication and validation, should not be handled in a header filter, rather they should be handled using service call composition.
§Header Filter Composition
Each service Descriptor can only have one HeaderFilter. In order to use several filters at once you may compose them using HeaderFilter.composite which will return a HeaderFilter that chains all the HeaderFilters you composed. When composing, the order is important so when sending message headers the filters of the composite are used in the order they were provided, and when receiving message headers the filters will be used in reverse order. So if we had the following filter:
class VerboseFilter(name: String) extends HeaderFilter {
  private val log = LoggerFactory.getLogger(getClass)
  def transformClientRequest(request: RequestHeader) = {
    log.debug(name + " - transforming Client Request")
    request
  }
  def transformServerRequest(request: RequestHeader) = {
    log.debug(name + " - transforming Server Request")
    request
  }
  def transformServerResponse(response: ResponseHeader, request: RequestHeader) = {
    log.debug(name + " - transforming Server Response")
    response
  }
  def transformClientResponse(response: ResponseHeader, request: RequestHeader) = {
    log.debug(name + " - transforming Client Response")
    response
  }
}And we registered two of them with the names Foo and Bar:
def descriptor = {
  import Service._
  named("hello")
    .withCalls(
      call(sayHello)
    )
    .withHeaderFilter(
      HeaderFilter.composite(
        new VerboseFilter("Foo"),
        new VerboseFilter("Bar")
      )
    )
}and then called the service, then we would get the following on the server output logs:
[debug] Bar - transforming Server Request
[debug] Foo - transforming Server Request
[debug] Foo - transforming Server Response
[debug] Bar - transforming Server Response