I need to design an API with reasonably secure* authentication that can be used from either an application server or a web client (e.g., AJAX running in an application loaded from an application server).

{ * - "Reasonably secure" means "Secure enough to protect the API from a competent hacker who isn't interested enough to invest a lot of effort in cracking it." The API won't handle financial transactions or military secrets. It just needs to protect commercial information of moderate value. }

The access requirements are: only applications running on authorized servers can access the API at all. Some API operations are accessible to any such application; others are accessible only to users who are identifiable, that is, who have registered on the application server and are logged in.

I've found a good approach to authenticating the application server. The API server and the application server share a secret (a private key). When the application server makes an API request, it signs the request with a hash code computed from the unsigned request and the secret. The API server recomputes the hash code and honors the request if it gets the same result.

If I simply extend this design to a web client, though, it collapses. The client must have access to the secret... and then it's no longer secret.

I've thought of ways around this problem, but they add complexity and latency, and/or leave holes in the authentication procedure.

Is there a way of dealing with this problem that's reasonably simple, practical, and secure?