tawny

Repo License

A proxy for proxying last.fm API calls because the last.fm API isn’t very great.

The project is an API proxy developed in Go, based on the Gin web framework, which transforms the outdated structure of the last.fm API into a modern, clearly defined REST architecture. Instead of directly addressing the sometimes inconsistent and historically grown endpoints of last.fm, the proxy takes over communication and provides a consolidated, versioned, and easily consumable API layer.

HMAC

Another key component is the integrated HMAC signature system. Clients can sign their requests locally before sending them to the proxy. The server then validates these signatures using a shared secret key. This means that the public last.fm API key is never exposed in the client, and unauthorized or manipulated requests can be effectively intercepted. This is particularly relevant for browser and mobile clients, where API keys would otherwise inevitably be exposed.

Sadly the implementation and calling HMAC signed methods are a bit messy.

How does signing work?

In the /hmac/sign endpoint, the payload with the schema, like the following, gets signed with the PSK provided with the header.

Example:

{
  "method": "GET",
  "api_identifier": "/user/",
  "api_parameters": {
    "username": "alice"
  }
}

This will then generate the following if selected the signing for base64:

{
  "signature": "1e336e066c239565d936245578ac77bf6494d2feae15e60211c3a1a7607d1f08",
  "request": "ewogICJtZXRob2QiOiAiR0VUIiwKICAiYXBpX2lkZW50aWZpZXIiOiAiL3VzZXIvIiwKICAiYXBpX3BhcmFtZXRlcnMiOiB7CiAgICAidXNlcm5hbWUiOiAiYWxpY2UiCiAgfQp9"
}

otherwise something like this:

{
  "signature": "1e336e066c239565d936245578ac77bf6494d2feae15e60211c3a1a7607d1f08",
  "request": {
    "method": "GET",
    "api_identifier": "/user/",
    "api_parameters": {
      "username": "alice"
    }
  }
}

It is higly recommended that you use base64, as it is more stable and the json version tends to be malfunctioning often.

This signed request can then be safely sent to /hmac/execute for server-side execution, without exposing the API key or sensitive logic in the client.

How does executing work?

In the /hmac/execute endpoint, the Base64-encoded request payload is decoded and parsed into a JSON structure. This JSON object defines the HTTP method, the target last.fm API identifier, and any parameters required for the proxied call.

A decoded request looks like this:

{
  "method": "GET",
  "api_identifier": "/user/",
  "api_parameters": {
    "username": "alice"
  }
}

The proxy uses this structure to reconstruct the appropriate last.fm API call internally—while still validating the HMAC signature before any request is executed. This design keeps the client implementation minimal and ensures that no sensitive keys or routing logic need to be embedded in public-facing applications.

Image Generation for now listening

One of the initial goals of the project was to generate “now listening” images without revealing the API key. Using the HMAC execution endpoint, the proxy can safely produce dynamically generated images—such as a currently-playing card—while keeping authentication entirely server-side.

Example Output:

currently listening to on lastfm

And for that we only need the base64 encoded request and the signature.

API Documentation

Many know that using the official last.fm API can be frustrating not the least because the documentation is really bad.

Thats why this project’s API is documented using openapi Specification:

Source-Code and Licensing

This Project is licensed under the Apache 2.0 License and the source code can be found in the GitHub Repository dozro/tawny