---
title: "Secure Lagom APIs with API Key Authentication"
description: "Secure your Lagom API using a shared secret."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/javascala/lagom/secure-header"
framework: "Lagom"
language: "Java/Scala"
authStrategy: "shared secret header"
pageType: use-case
---

# Secure Lagom APIs with API Key Authentication

Secure your Lagom API using a shared secret.

## How Zuplo Handles It

Put Zuplo in front of your Lagom backend to authenticate API keys and forward a shared secret header so your origin only accepts traffic from Zuplo.

## Lagom Backend Code

```scala
import akka.NotUsed
import com.lightbend.lagom.scaladsl.api.ServiceCall
import com.lightbend.lagom.scaladsl.server.{LagomApplication, LagomApplicationContext, LagomServer}
import com.lightbend.lagom.scaladsl.api.transport.{ExceptionMessage, MessageProtocol, NotAuthorized, RequestHeader, ResponseHeader, TransportErrorCode}

import scala.concurrent.{ExecutionContext, Future}
import java.util.concurrent.CompletionStage

trait ProtectedService {
  def protectedEndpoint(): ServiceCall[NotUsed, String]
}

abstract class ProtectedServiceImpl(implicit ec: ExecutionContext)
  extends ProtectedService {

  private val expectedSecret: Option[String] = sys.env.get("SHARED_SECRET")

  private def validateSharedSecret(requestHeader: RequestHeader): Future[Unit] = {
    val secret = requestHeader.getHeader("X-Shared-Secret")
    (secret, expectedSecret) match {
      case (_, None) =>
        Future.failed(
          new NotAuthorized(
            new ExceptionMessage("Server configuration error", "No secret configured")
          )
        )
      case (None, Some(_)) =>
        Future.failed(
          new NotAuthorized(
            new ExceptionMessage("Authorization failed", "No secret provided")
          )
        )
      case (Some(actualSecret), Some(expected)) =>
        if (actualSecret == expected)
          Future.successful(())
        else
          Future.failed(
            new NotAuthorized(
              new ExceptionMessage("Authorization failed", "Invalid secret")
            )
          )
    }
  }

  override def protectedEndpoint() = ServiceCall { request =>
    requestHeader =>
      validateSharedSecret(requestHeader).map { _ =>
        (ResponseHeader.OK, "Access granted")
      }
  }
}

abstract class ProtectedApplication(context: LagomApplicationContext)
  extends LagomApplication(context) with ProtectedService {

  override def lagomServer: LagomServer = serverFor[ProtectedService](this)
}
```

## Example Request

```bash
curl -X GET \
  'https://your-api.zuplo.dev/your-route' \
  -H 'Authorization: Bearer YOUR_API_KEY'
```

## Learn More

- [API Key Authentication on Zuplo](https://zuplo.com/docs/policies/api-key-auth-inbound)
- [JWT Authentication on Zuplo](https://zuplo.com/docs/policies/open-id-jwt-auth-inbound)
- [All use cases](https://zuplo.com/use-cases)
