Provide a more secure authentication option than API keys
I'm building a prototype app with Cognitive services called from a web browser (this is the most appropriate option for my use case for speech-to-text with continuous recognition), but I won't be able to use this solution in production because anyone can steal our API key. The API key can then be used by anyone to call the services for free (and have it paid by us, potentially generating millions of dollars of billing if done with a malicious intent).
This is not acceptable and there should be a more secure authentication option. For example, something similar to SAS tokens for Azure Blob Storage could be used:
- My web server generates a SAS token from a secret key it knows and that is known to Cognitive services too.
The SAS token has a limited scope: services and features it is allowed to use, how many calls it is allowed to do in total, and expiration datetime.
- After exceeding the allowed number of calls or after the timeout, the web browser must call my authentication service to retrieve a new SAS token
- When calling Cognitive services, the web browser provides the SAS token instead of the API key
Christos Karras commented
After more digging in the samples, I found something similar to what I suggested is already available, for some services only, and with some flaws:
https://dev.cognitive.microsoft.com/docs/services/57346a70b4769d2694911369/operations/57346edcb5816c23e4bf7421. It returns a JWT token that is valid for 10 minutes, and that can be provided instead of the API key.
There are still some problems though:
- Not all Cognitive Services appear to support this option. For example, for text analytics sentiment analysis, I could not find a way to specify a JWT token. This option should be supported for all cognitive services.
- For speech to text, if a malicious user calls SpeechSDK.TranslationRecognizer.startContinuousRecognitionAsync and never stops it, the connection is allowed to continue far longer after the token has expired. The server should automatically close the socket at the token's expiration time, unless a new token was provided through the websocket (new methods in the SDK would probably be needed for this)