How to secure Web API with Auth0 without exposing ClientId & ClientSecret to client? - api

I am creating a new .Net Core Web API that is consumed by a new React client-side app. Both the client-side app and the Web API are on different hosts and protected by Auth0. I set up both the client-side app and the Web API in Auth0, and then I created a machine-to-machine app in Auth0 to be able to communicate with the Web API silently (without a user interface). The security flow works like this:
User tries to access client-side app.
User is re-directed to Auth0 to provide credentials.
Auth0 authenticates the credentials and returns user info (including user ID + access token) to client-side app.
Client-side app stores user info in local storage for future use until it expires.
Any calls to 3rd party APIs are routed through my own Web API, so 3rd party API keys are sitting in a safe place on the server, not on the client-side.
User accesses a page that requires a call to my Web API but we don't have an access token for my Web API yet.
Client-side app reads the ClientId & ClientSecret (hard-coded values) from .env file and makes a POST request to Auth0 to fetch an access token for my Web API (this is Auth0's recommended way of getting the access token for the Web API silently except they don't specify where the ClientId & ClientSecret would be stored).
Auth0 returns an access token for my Web API.
Client-side app stores the Web API access token in local storage for future use until it expires.
Client-side app invokes my Web API with newly acquired access token as the bearer token in the header.
Web API receives the access token, authenticates with Auth0 and fulfills the request.
All of the above is working for me but I am concerned about storing the Auth0 ClientSecret of my Web API in the client-side app. Although it is not visible on the screen or in a cookie anywhere, any capable user would be able to get at it by inspecting the network traffic.
Many people on the Internet seem to be fine with storing 3rd party API keys in .env files while others advise routing 3rd party API access through your own Web API ... and I am doing the latter. But I still need the Auth0 ClientSecret to get to my own Web API and I cannot figure out a better place way to get to it without storing them somewhere on the client-side.
One last-ditch solution I can think of is to not protect my Web API through Auth0 and instead every call from the client-side app to my Web API should include something unique (like the user ID from Auth0) that can be validated by the Web API. Thankfully, the user ID from Auth0 will be stored in our database when the user is set up initially, so this is actually possible.
Does Auth0 have any other way for me to get the Web API access token without providing the ClientSecret given that I already have the client-side app's access token? I am curious to know how others have secured both their client-side app and their Web API through Auth0.

You are correct, you should not include the client secret in your client-side app. Do not use a client credentials flow, instead use a auth code + PKCE or implicit flow.
With that being said, Auth0 should handle most of that if you are using a library or SDK.
You have two options for getting the token:
When requesting the initial access token and ID token add the Web API as an audience and request the related scopes.
Make a silent request using the checkSession function for Auth0.js or getTokenSilently for auth0-spa-js
Take a look at this:
https://auth0.com/docs/architecture-scenarios/spa-api/part-3

Related

When an Oauth provider is used to delegate authentication, then does the appserver return any token to the caller?

In Oauth and Openidconnect, the appserver endpoint invocation starts the Oauth flow and the app server gets the token from the auth server and is able to pass the token to resource server to access resources (delegation) on behalf of the resource owner.
The token exchange happens between the app server and resource server, and the token never arrives at the end users browser.
I'm working on a web api (aka app server) that will be consumed by a mobile app. There is no other server involved. Presently the login endpoint returns a signed JWT token to the user if correct credentials are supplied (validate against the db). User places this token in the header of the subsequent request.
Assuming I don't want to have a user db and validate logins, and instead delegate the auth check to another service like azure b2c or firebase (that use the Oauth), then I assume the flow is like given below:
Api registered the firebase/azure b2c (let's call this the provier) clientid, secret.
User invokes login endpoint of my api
The api invokes the provider's Oauth flow.
User gets popup to authenticate with the provider.
Eventually the provider will send the token (containing the claim like username) to the api (aka app server)
Does the user get back any token? Otherwise, when the user makes subsequent endpoint calls, then how is the endpoint able to identify who is this user and whether he is already authenticated?
Although it is okay to send back the access token to the user , but from the security best practise 's point of view , it is better not to do it which I quote the reasons as follow from this:
Because of the issues outlined above, the best security recommendation
for an SPA is to avoid keeping tokens in the browser at all. This can
be achieved with the help of a lightweight back-end component, often
described as a Backend-For-Frontend.
The backend component can then be configured as a confidential OAuth
client and used to keep tokens away from the browser. It can either be
stateful and keep tokens in custom storage, or stateless and store the
tokens in encrypted HTTP-only, same-site cookies. Whichever variant is
chosen, the backend component creates a session for the SPA, using
HTTP-only, secure, same-site cookies, thus enabling a high level of
security. Such cookies cannot be read by scripts and are limited to
the domain of the SPA. When combined with strict Content Security
Policy headers, such architecture can provide a robust protection
against stealing tokens
Also from here ,they suggest for mobile app 's OAuth2 best practise , it should perform the OAuth flow inside a system browser component.

Authentication for hybrid flow for ASP.NET MVC client

I'm learning identityserver4 and can't understand some stuff.
Shortly: I want to authorize end-users with email and password on ASP.NET MVC client side (it will send user credentials to the token server to get tokens), and I don't want third-party clients to retrieve data from my API resources.
As I understood from the documentation:
implicit flow is used for SPA (js clients) and uses id_token to authorize users. I can store id_token in my browser.
client credentials flow is used for trusted apps (like ASP.NET MVC client) to authorize clients and uses access_code. I can store access_code inside my app.
So looks like I need a hybrid flow.
In the documentation I read that I need to use AddOpenIdConnect() method and
Technically the tokens are stored inside the properties section of the cookie.
So my questions:
If the id_token can be stored in the browser, why is it not safe to store the access_token there too ?
As the docs state, the tokens are stored inside the properties section of the cookie. It's confusing, because some guides says, that it's not safe to store access_token there. So where I should store access token in my ASP.NET MVC client?
Am I right, that AddOpenIdConnect() configures my ASP.NET MVC app to retrieve access_token automatically from the token server? And if yes - in which moment should I authorize users with email/password and how to combine all tokens inside one JWT on my ASP.NET MVC client's backend when I will send requests to api resources ?
Today you should not use the Implicit Flow and it has been deprecated as of Oauth 2.1. What you should use is the authorization code flow with PKCE. PKCE is a security enhancement for the authorization code flow.
So as of OAuth 2.1 you only have two main flows:
Authorization code flow, for a MVC client to login a user to the client
Client credentials flow, for API->API communication where no human is involved.
To answer your questions:
If the id_token can be stored in browser, why it's not safe to store access_token there too ?*
The ID-Token is only used to create the initial user session and after that you can throw it away. It also only have a short life time of 5 minutes by default in IdentityServer.
As the docs state, the tokens are stored inside the properties section of the cookie. It's confusing, because some guides says, that it's not safe to store access_token there. So where I should store access token in my ASP.NET MVC client?
The tokens can be stored in your session cookie in ASP.NET Core and that's secure. It's protected / encrypted using the Data Protection API. However, the cookies can grow in size quite a lot if you do that.
Am I right, that AddOpenIdConnect() configures my mvc app to retrieve access_token automatically from the token server? And if yes - In which moment I should authorize users with email/password and how to combine all tokens inside one JWT on my ASP.NET MVC client's backend when I will send requests to api resources?
AddOpenIdConnect only handles the initial login and retrieving the first ID and access token. It does not handle refreshing of the access token using refresh tokens. For that you can add the IdentityModel library.
Today when you use the auth code flow, you redirect the user to IdentityServer and you let the user login there instead of passing the username/pwd from you browser to identityserver.

OAuth 2 authentication for both iframe and api

I'm integrating several web sites/services into my application. I use iframes (or webview for Vue Electron) for UI integration and I also use API to implement cross-communication between those services.
At the moment I have to go through OAuth 2 authentication twice for each service: once as part of natural authentication in iframe and another when I ask the user to give me access to this service (for api reasons).
Is there any way to streamline this process?
The state of the art response would be to modify your application completely.
You should have 1 SPA application and not iframe
This application would authenticate to get OAuth2 token
This application would then call the backend (access multiple backend, or access on api management layer that call backends).
Thing is, with this you can have 2 strategies :
give all permission (scope) at 1st authentication
give the smalled scope possible at 1st authentication, then when needed "reauthenticate" (in fact validate new scope) to get new access token
When an API want to call another API, you have also 3 strategies:
you simply use the same client token the API receive to the service your API call (no human interaction needed)
your API generate a token from a service account (using ROPC authentication scheme) or via a client credential scheme (the access token will be valid but usually not be bind to a real user), (no human interaction needed). (the API will be the client of the 2nd API)
your identity provider have an endpoint to transform access token : Your API can give the client access token, and authorization server will transform this with the client_id of your API. You send this token to 2ndAPI ( token will show subject of your UI application, but client ID will be the 1st API clientId) (no human interaction needed)
Now if you use IFrame with multiple sub-application on the same domain (the domain need to be exactly the same!), it is possible to share the same access token for instance via local storage. (security is not top notch)
You will probably need to authenticate with a bigger scope list sometime but it is your only option. You will simulate a single page application, but issue is that you will have potentially different client_id depending first application you authenticate to.
Edit: Multiple authorization server
From your comment, you have multiple authorization server. One strategy could be to ask user to authenticate, your application can then get an access_token and a refresh_token.
Depending on your authorization server, refresh_token can be used a lot / on a long period of time, so that if you store it somewhere, the next time the user visit your application, your application can silently get an access_token from this refresh token. Your application have then access to remove api without newer interaction from your user.
Of course, this means you have to save this token the most safely you can.
By using OpenID Connect you could combine authentication and authorization in a one step and get both an id_token to logon your user to your app as well as an access_token to access APIs in a single authentication response.

REST API authentication for web app and mobile app

I'm having some trouble deciding how to implement authentication for a RESTful API that will be secure for consumption by both a web app and a mobile app.
Firstly, I thought to investigate HTTP Basic Authentication over HTTPS as an option. It would work well for a mobile app, where the username and password could be stored in the OS keychain securely and couldn't be intercepted in transit since the request would be over HTTPS. It's also elegant for the API since it'll be completely stateless. The problem with this is for the web app. There won't be access to such a keychain for storing the username and password, so I would need to use a cookie or localStorage, but then I'm storing the user's private details in a readily accessible place.
After more research, I found a lot of talk about HMAC authentication. The problem I see with this approach is there needs to be a shared secret that only the client and server knows. How can I get this per-user secret to a particular user in the web app, unless I have an api/login endpoint which takes username/password and gives the secret back to store in a cookie? to use in future requests. This is introducing state to the API however.
To throw another spanner into the works, I'd like to be able to restrict the API to certain applications (or, to be able to block certain apps from using the API). I can't see how this would be possible with the web app being completely public.
I don't really want to implement OAuth. It's probably overkill for my needs.
I feel as though I might not be understanding HMAC fully, so I'd welcome an explanation and how I could implement it securely with a web app and a mobile app.
Update
I ended up using HTTP Basic Auth, however instead of providing the actual username and password every request, an endpoint was implemented to exchange the username and password for an access key which is then provided for every authenticated request. Eliminates the problem of storing the username and password in the browser, but of course you could still fish out the token if you had access to the machine and use it. In hindsight, I would probably have looked at OAuth further, but it's pretty complicated for beginners.
You should use OAuth2. Here is how:
1) Mobile App
The mobile app store client credentials as you state yourself. It then uses "Resource Owner Password Credentials Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.3) to send those credentials. In turn it gets a (bearer) token it can use in the following requests.
2) Web site
The website uses "Authorization Code Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.1):
Website sees unauthorized request and redirects browser to HTML-enabled autorization endpoint in the REST api.
User authenticates with REST service
REST site redirects user back to website with access token in URL.
Website calls REST site and swaps access token to authorization token.
Here after the website uses the authorization token for accessing the REST service (on behalf of the end-user) - usually by including the token as a "bearer" token in the HTTP Authorization header.
It is not rocket science but it does take some time to understand completely.
3) Restricting API access for certain applications
In OAuth2 each client is issued a client ID and client secret (here "client" is your mobile app or website). The client must send these credentials when authorizing. Your REST service can use this to validate the calling client
I resolved this for my own API quite easily and securely without the need to expose any client credentials.
I also split the problem into 2 parts. API authentication - is this a valid request from a recognised entity (website or native app). API authorisation, is that entity allowed to use this particular endpoint and HTTP verb.
Authorisation is coded into the API using an access control list and user permissions and settings that are set up within the API code, configuration and database as required. A simple if statement in the API can test for authorisation and return the appropriate response (not authorised or the results of processing the API call).
Authentication is now just about checking to see if the call is genuine. To do this I issue self signed certificates to clients. A call to the API is made from their server whenever they want - typically when they generate their first page (or when they are performing their own app login checks). This call uses the certificates I have previously provided. If on my side I am happy the certificate is valid I can return a nonce and a time limited generated API key. This key is used in all subsequent calls to other API endpoints, in the bearer header for example, and it can be stored quite openly in an HTML form field or javascript variable or a variable within an app.
The nonce will prevent replay attacks and the API key can be stolen if someone wants - they will not be able to continue using after it expires or if the nonce changes before they make the next call.
Each API response will contain the next nonce of if the nonce doesn't match it will return an authentication error. In fact of the nonce doesn't match I kill the API key too. This will then force a genuine API user to reauthenticate using the certificates.
As long as the end user keeps those certificates safe and doesn't expose the method they use to make the initial authentication call (like making it an ajax request that can be replayed) then the API's are nice and secure.
One way of addressing the issue of user authentication to the API is by requesting an authentication token from the API when the user logs in. This token can then be used for subsequent requests. You've already touched on this approach - it's pretty sound.
With respect to restricting certain web apps. You'll want to have each web app identify itself with each request and have this authentication carried out inside your API implementation. Pretty straight forward.

Using Google's OpenID Connect as part of a SSO

I'm developing a common auth service for several different web services. The general idea is that a user goes to one of these web services and clicks on a login button and gets redirected to my auth service. Once authenticated, the auth service redirects the user back to the original web service.
To begin with, the auth service will use Google's OpenID Connect service. One idea I had was that when a user was authenticated using Google I could pass around the resulting JWT to other services to use as an auth token. Google mentions this idea in their documentation (https://developers.google.com/accounts/docs/OAuth2Login#validatinganidtoken):
One thing that makes ID tokens useful is that fact that you can pass them around different components of your app. This can be helpful because different components of your application may pass the ID token between them and use it as a lightweight authentication mechanism authenticating the app and the user.
Can anyone help me with the actual details on how this should work e.g. How do I handle log outs both on Google and from the auth service? There appeared to be some documentation on this in older OpenID Connect Session documents (-03) but it appears to have been removed.
You should not pass the ID Token that you receive to Google back to the app to use as an auth token. The ID Token will have an audience specific to your app, not the ultimate client.
If you just passed this back to clientA, then you would open it up to auth attacks where clientB could obtain an Google ID Token via your auth service and then use that token to gain access to user data in clientA.
A much better approach would be to mint your own ID Token and provide an audience designation for each app that uses your service.
Monitoring session state is not as straightforward. The easiest thing to do is for your service to wrap G+ sign-in libraries and interface with the session state api's.
https://developers.google.com/+/web/signin/session-state