---
title: "Secure Lapis APIs with API Key Authentication"
description: "Secure your Lapis API using a shared secret."
canonicalUrl: "https://zuplo.com/use-cases/api-key-auth/lua/lapis/secure-header"
framework: "Lapis"
language: "Lua"
authStrategy: "shared secret header"
pageType: use-case
---

# Secure Lapis APIs with API Key Authentication

Secure your Lapis API using a shared secret.

## How Zuplo Handles It

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

## Lapis Backend Code

```lua
local lapis = require("lapis")
local app = lapis.Application()

-- Environment variable to be used for shared secret
local expected_secret = os.getenv("SHARED_SECRET")

-- Middleware to validate shared secret header
local function validate_shared_secret(req, res)
  local secret = req.headers["x-shared-secret"]

  if not expected_secret then
    return res:write({ status = 500, json = { error = "Server configuration error" } })
  end

  if not secret then
    return res:write({ status = 401, json = { error = "No secret provided" } })
  end

  if #secret ~= #expected_secret or not lapis.util.constant_time_compare(secret, expected_secret) then
    return res:write({ status = 401, json = { error = "Invalid secret" } })
  end
end

-- Example route protected by shared secret validation
app:match("/protected", {
  before = validate_shared_secret,
  on_success = function(self)
    return { json = { message = "Access granted" } }
  end
})

return app
```

## 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)
