Authenticating External System Connections to Web API with Azure AD - asp.net-web-api

I'm trying to figure out how to migrate a system that is currently using ACS to Azure AD. I've read the migration docs provided by Azure and have looked through the Azure AD docs and the sample code but I'm still a bit lost as to what the best approach for my situation would be.
I've got a web API that has about 100 separate external systems that connect to it on a regular basis. We add a new connections approximately once a week. These external systems are not users--these are applications that are integrated with my application via my web API.
Currently each external system has an ACS service identity / password which they use to obtain a token which we then use to authenticate. Obviously this system is going away as of November 7.
All of the Azure AD documentation I've read so far indicates that, when I migrate, I should set up each of my existing clients as an "application registration" in Azure AD. The upshot of this is that each client, instead of connecting to me using a username and password, will have to connect using an application ID (which is always a GUID), an encrypted password, and a "resource" which seems to be the same as an audience URL from what I can see. This in itself is cumbersome but not that bad.
Then, implementing the authorization piece in my web API is deceptively simple. It looks like, fundamentally, all I need to do is include the properly configured [Authorize] attribute in my ApiController. But the trick is in getting it to be properly configured.
From what I can see in all the examples out there, I need to hard-code the unique Audience URL for every single client that might possibly connect to my API into my startup code somewhere, and that really does not seem reasonable to me so I can only assume that I must be missing something. Do I really need to recompile my code and do a new deployment every time a new external system wants to connect to my API?
Can anyone out there provide a bit of guidance?
Thanks.

You have misunderstood how the audience URI works.
It is not your client's URI, it is your API's URI.
When the clients request a token using Client Credentials flow (client id + secret), they all must use your API's App ID URI as the resource.
That will then be the audience in the token.
Your API only needs to check the token contains its App ID URI as the audience.
Though I want to also mention that if you want to do this a step better, you should define at least one application permission in your API's manifest. You can check my article on adding permissions.
Then your API should also check that the access token contains something like:
"roles": [
"your-permission-value"
]
It makes the security a bit better since any client app with an id + secret can get an access token for any API in that Azure AD tenant.
But with application permissions, you can require that a permission must be explicitly assigned for a client to be able to call your API.
It would make the migration a tad more cumbersome of course, since you'd have to require this app permission + grant it to all of the clients.
All of that can be automated with PowerShell though.

Related

Best way to access Google APIs without user authorization from desktop application

I am trying to make a desktop application with Twitch API and Google API.
Since this application requires Twitch user permission, a user needs to authorize my application through twitch's OAuth and I think there's no way to omit this process.
Now, I want to add some functionalities from Goole APIs, for instance TTS.
My application will be installed and run on user's local machine,
it cannot store API key or credential information safely.
I think I have three options:
Add Google OAuth: This is most safe way, I think, but I don't think I can convince users to authorize another Google account even though they already authorized their Twitch account.
Make a kind of proxy server which verifies request for Google API using twitch authentication information and relays request to/response from Google API. This seems feasible but it requires additional payment to running server for sending data from Google API. I already have to pay for TTS service, another payment for proxy server which sends binary data frequently would be a financial burden for me.
Make a server to acquire API key for Google API. This also requires additional server, but it does not involve lots of traffic because application will access Google API directly once API key acquired. However, I concern that the API key may be easily stolen using monitoring tool such as wireshark.
Which method should I use here, and how can I improve it?
Or, is there better way for this case?

Distribution of application that relys on Google API InstalledAppFlow

Question
If InstalledAppFlow requires client secret json file to perform oauth2 authorization, how actual real-life applications using Google API are distributed?
Is client secret json file should be considered as part of application and included as constant?
Context
Currently I am learning how to use oauth2 to authorize google APIs access with python module google_auth_oauthlib.
And I found that Oauth2 authorization process itself require client secret files for InstalledAppFlow authorization method, but I never seen an application that asks for authorization asking for client secret.
After countless searches all I could find about it was this, from google identity docs.
The process results in a client ID and, in some cases, a client secret, which you embed in the source code of your application. (In this context, the client secret is obviously not treated as a secret.)
And from google cloud docs
Save the credentials file to client_secrets.json. This file must be distributed with your app.
Is this explaining that I should embed(include) client secret as constant in the code itself?
The issue with the client id and client secrete is that they need to be kept secure. Googles TOS requires that developers keep their client id and secrete secure
Asking developers to make reasonable efforts to keep their private keys private and not embed them in open source projects.
This can cause issues with for example open source applications. Can I really not ship open source with Client ID?
I have had a few conversations with the Oauth2 team at google over the years. Installed applications those that are compiled anyway can compile the client id and client secrete internally however that would not stop anyone from decompiling the application and retrieving the client id and client secret.
I was told that they are aware of that issue and that there is really no way around it.
I have seen other option where the client id and client secret would be sored on the server and then the installed application would request them from a web api. This is another option but you are sending them across HTTPS it should be considered secure even if you double encrypt them.
The fact of the matter is there really is no way around it. The main thing is that you should not release an application with for example a settings file where the client id and client secrete appear in clear text that would IMO be to great a risk you would need to compile it into your application or at the very least encrypt it some how.
You wont stop someone who really wants to get it from getting it but you will stop most people.
Why installed apps are the issue.
There are serval types of applications. Mobile, web, installed.
With mobile and web there are ways of configuring the client so that you can ensure that they only work form your server. With Web you have a redirect uri, with mobile there is the actual mobile api id.
With installed applications this is not possible because they mostly run on localhost. There is no way for you to know where the app is running so they are left open. So if anyone got ahold of your client id and client secret then they could use it for their app. Users would have no way of knowing it wasn't your official app and neither would google.
As you have a python script why not consider instructing your users in creating their own client id and client secret then they will be independent.

How to authenticate a web API which runs every hour from a scheduled console application?

I have a requirement where I have to schedule a console application, which fetches certain records from database and calls an ASP.NET web API. Could someone help me with how to restrict the web API to not get called from anywhere else?
Please help me with any useful links, tips, or steps to follow.
There are a few ways you can lock down access to your application for an rpc call.
You can restrict access via IP with IP filtering.
If you're using windows authentication, you can grant permission to specific AD User or Groups in your web config file.
If you're using forms authentication and basically just need to make an RPC call, you can create an endpoint for your console app which accepts a username/password parameter (using https, of course).
If your setup is more advanced, you can use tokens and ASPNET Identity to limit access.
These are just a few ideas. Basically just google ASPNET security and you'll get a ton of ideas.

Restricting Google API Server to server service account key to be used with specific domains

Google API Server To Server service account key is a simple json or p12 file which can be compromised in some scenarios. Is there a way to limit its use to specific IPs or domains from Google Developer Console? The support topics there are not helpful at all.
No service accounts cant be restricted to IPs or Domains. Currently if you have the correct credentials then you can use them.
This is why you need to keep them safe. However that being said i think its a good idea. I am going to see if i can find someplace to add it as a feature request.
Note for openid signin
Signin returns an id token this id token can be verified verify the hd claim matches your domain name. Again this only works if you are authenticating with the openid scope.
Response from Google
I contacted one of the developers on Google identity this was his response.
IP restrictions had some value many years ago. Now, most of the apps are hosted in the cloud and traffic can move around the world thus making the IP restriction not very useful. If service account credentials are compromised, it is time to get a new credential or they were used in an incorrect way.

Only allow access to my REST APIs from my own application?

We have a Windows app hosting a WebBrowser control that hits our REST APIs. We like to restrict access to the APIs to be only coming from withing the Windows app itself (for example, the APIs cannot be accessed in a browser, etc).
How can we accomplish that? what is the most secure way without having to expose any kind of credential (for example, if we use HTTP Basic auth, the username and password can be seen by reverse engineering the app itself)?
Thanks a bunch!
EDIT: We plan to distribute the application freely so we have no control over where the connection will be made from.
Restrict the REST interface to only accept connections from 127.0.0.1 (home) and then connect from your rest-consuming application only with http://localhost or http://127.0.0.1 in the URLs (if you use the external IP or DNS name of your machine it'll be treated as a remote connection and denied access).
You can do this with web server settings, or within the code of your REST APIs
I had a similar situation during a project where we distributed an iPhone app that also connected to a REST api that my team developed.
For security we used somewhat of a three-legged scenario. The app was required to authenticate using the user's credentials against a standalone service responsible only for authenticating and generating access tokens. Once the app received a valid access token, subsequent requests to the api required sending this token in the Authorization header.
You could do something similar. If you come up with a credential scheme to authenticate your app as valid API consumers you could use basic auth over HTTPS to obtain tokens, and then only by using those tokens could a consumer gain access to the rest of the API.

Resources