Yes, what Mark said.
Your meaning is coming through clearly enough. I imagine you are thinking, you want the upload to happen between the client and the storage service, and before the storage service allows the upload, you want the storage service to call Apigee to ask Apigee to validate the uploader’s token. I have some views on that.
You asked if it is possible to make the “token validation endpoint” callable only from a specific set of callers - the storage service in your case. One way to make a proxy endpoint callable from only a specific client, is to use transport-layer security (TLS) with mutual authentication. In that case the Apigee endpoint can authenticate the caller, and only a caller with the right certificate will be able to call the Apigee endpoint.
The interaction sequence I suppose would be something like this:
- uploader client sends a request-for-token to Apigee, presenting some sort of credentials (maybe client id and secret)
- Apigee evaluates that request and if valid, generates a token and sends it to the uploader client as response.
- uploader client then sends the received token, along with its to-be-uploaded file, to the storage service
- storage service calls Apigee to ask Apigee to validate the uploader’s token.
- Apigee allows the inbound call only if the TLS certificate presented by the storage service is trusted. (Transport layer authentication of client)
- Apigee evaluates the token and response “200 OK” or “403 unauthorized” depending on token validity
- Storage service makes the allow/deny decision based on that response.
As an alternative to the transport layer (TLS) trust, you could rely on something at the message/application layer. The storage service would send its own special credential (API Key or token) to Apigee, at the time it requests token validation. In this model, the storage service would call Apigee with 2 pieces of data - its own token, and the token provided to it, by the uploader client . You would need to configure Apigee to validate both tokens. First the token from the caller (“is this caller allowed to ask me to validate a token?”) , and then the relayed token from the uploader. Only if both tokens are valid, would Apigee respond “200 OK” to the storage service, and then the storage service would know it should accept the upload.
The reason the storage service needs to contact Apigee is only Apigee knows the status of the token. Only Apigee can determine if the token is expired, valid, good for this particular file, and so on.
But you could use a different interaction pattern if you rely on public/private cryptography. If the storage service could validate the token on its own, then you could avoid the step in which the storage service explicitly asks Apigee to validate a token. This is possible if the token is a “federated token”, like a signed JWT. In that case the storage service could validate the token all by itself, without asking Apigee. To validate the JWT, the storage service needs only the public key of Apigee. The interaction sequence would be: uploader client contacts Apigee, presents credentials, and requests a JWT that would grant it “upload rights” for a specific payload. Apigee sends the generated JWT to the uploader in response. The uploader then sends its file along with the JWT to the storage service. The storage service can validate the JWT, inspect the claims, and then make an authorization decision (allow or deny the upload?) based on those claims.
The “Signed URL” model that Mark mentioned, which I described in detail elsewhere, is basically the same idea, except that:
- cloud storage systems like Azure, AWS S3, GCP Storage , already support signed URL access to their storage endpoints. You don’t need to “build” a storage service yourself; the existing cloud service already does this.
- the signature in these cases are not wrapped up in a JWT, but a different signature format, which is “proprietary” and specific to each storage service.
You can still use Apigee to generate the Signed URL. The interaction sequence is similar to what I described above for a JWT:
- uploader client contacts Apigee, presents credentials, and requests a signed URL that would grant it “upload rights” for a specific payload.
- Then the uploader receives the signed URL,
- uploader client invokes that signed URL, passing its file as payload to the storage service.
- The storage service validates the signature in the query param, and then makes an authorization decision (allow or deny?) based on that signature.
If you already have a storage service, or if you don’t want to depend directly on one of the big cloud provider’s storage services, then you could use the JWT model. If you don’t wish to write a storage service, then you could use signedURL and one of the pre-built services.