My team and I are implementing a centralized API authentication system so that one set of API credentials can be shared among several different API-publishing services. These are all Rails apps.
Long explanation
For any given API transaction, there will typically be 3 apps involved:
- End-user-facing app that consumes API X. Has API credentials stored (not provided by end user).
- API X service provider app that app #1 connects to.
- API authentication system that app #2 connects to to verify the API credentials sent by app #1.
So for authentication, app #2 is just a forwarder. App #1 sends some credentials, and app #3 is capable of verifying that they are valid or not. Typically app #1 will just have these credentials stored securely, rather than asking the end user for them. Think API key rather than username and password.
We would like app #2 to not be involved in authentication at all. It should delegate all of that to app #3. And obviously we don't want to send the API in clear text over insecure networks, so something like HMAC request signing should be used unless the connection is SSL encrypted.
However, signing a request with HMAC requires that the authentication server can see enough of the original request to construct its own signature and compare that to the one supplied by the client. Only app #2 will have access to the request that is signed, but it does not have access to the API credentials in order to re-construct the signed "canonical string" for comparison with the supplied credentials.
So one implementation option is to forward the original request in some form to app #3 along with the HMAC signature that app #2 received from app #1. App #3 then re-constructs the signature using its credential store and the forwarded request data, and responds with "authenticated" or "access denied." This seems a bit hacky, though.
I then thought this was a problem that OAuth 2.0 could solve, since it involves forwarding responsibility for authentication to another service. However, OAuth's flows all assume you're dealing with user credentials at some point in the flow. Here we have API credentials that are stored in app #1. So this seems like it actually isn't a very good fit.
So my question is (finally!), is there a well-known pattern here that I'm just missing? I feel like this can't be that novel of an authentication system, and there's probably already a pattern for how to do this right, if not a protocol and libraries to implement that protocol.
A very high-level description of how you would tackle this problem would be sufficient as an answer. Thanks!
TL;DR
I'm giving out API keys that third-party applications will store and use to access several API-publishing services. I want to centralize authentication of these keys in one app that all the API-publishers use for authentication. But HMAC requires that the API publisher have both the credential store and the original request data to re-construct its own signature and compare that to the client-supplied one. I want to keep the credential store in the centralized authentication service, but it also can't see the signed request to API publisher. How would you implement such a beast?