Right now my website has an API which is secured using signed key authentication (accessed using a PHP client). Now, I want to introduce the use of a JavaScript client for use with certain endpoints.
What I've done is require the client to authenticate through the PHP client and receive an access token and a refresh token. Then it is able to pass that token to the javascript client and can access endpoints from there.
Now, what I've having a problem with is refreshing the access token when it expires. Is there a way I can accomplish this without requiring the client to use the PHP client again?
The reason I don't want to use the PHP client is because the app using the api is written entirely in javascript, so using the php client would require the page to be redirected, losing the app's state.
I don't want to use OAuth because I don't want the user to have to grant access to the client. I own both the client and api and there will never be any 3rd party clients created.
Related
Requirments
I have created a Web API that requires access token from Microsoft Active Directory Application and then uses the access token in a subsequent request to Web API. I am consuming these Web APIs in my PowerApp components. However, I am unable to get the access token internally from Javascript without redirecting the user to the login page. As per my requirements, I have to get the access token and then access my Web APIs, without redirecting the user to login.
Implementation
I am making a POST call to "https://login.microsoftonline.com/{tanent_id}/oauth2/token" from JS and trying to get the access token by using client secret.
Issue
I am getting the CORS issue whenever trying to reach the login API. I can get the access token from Postman and Internet Explorer but not to the rest of the browsers (i.e. Chrome, Firefox, Edge).
Can someone suggest me the way to prevent the CORS issue and proceed with my Web APIs calls with the access token. I have already learned the Implicit approach and it did not work since we need to redirect to URL in this approach too.
Since Implicit Grant Flow is not your option, and you do need an app-only token, I am afraid you must do the request from a back-end application. Then you can get the access token from the back-end application.
I'm using an external service called auth0 in order to get an access token and let my users use my api. Auth0 is using Oauth2 protocol.
In short The user adds a username and a password, I'm doing a call to auth0 by using a client_id (apps have an id) and client_secret and I get an jwt access token in return. Then from there I carry this access token to have access to my own api since I can check its validity.
I have been looking around about how secure it is to store client_id and client_secret on the client side (e.g. web (javascript)/mobile (native or hybrid with ionic)) and everybody was saying that it's not secure since everybody can reverse engineer the code and get the client_id and client_secret. Ok...I can take it...what Can I do with them if I don't have credentials in order to get the access token?
Given that I don't want to store the client_id and the client_secret, one solutions I have thought is to make a direct call to my api (Java) with the credentials and then my api make a call to auth0 and return the corresponding access token. In this way the client_id and client_secret is stored in the backend and somebody cannot get them easily. Is that safe?
However I have some endpoints, e.g. creating use account, sending sms for phone validation etc, that cannot have credentials. How do I protect the api in such case? If I can't store my own access token on the client side how could I get an access token and access my own api without credentials?
Thanks
One possible solution that OAuth spec suggests is that you could have three different servers for your application.
client-side
backend server and an additional authentication server.
The preferred way of doing this would be that the client would send the user credentials to the authentication server. The authentication server would be a back-end server which contains the client secret
The authentication server will authenticate the credentials and return back the token.
The client will then use the token obtained from the authentication server to access the resource API server.
If you wanna know more check out this video
https://www.youtube.com/watch?v=rCkDE2me_qk
In my opinion you are almost certainly using the wrong OAuth flow. I use Auth0 with Ionic as both a web app and a native Cordova app. I don't have the client secret in my client code at all.
If you follow the Auth0 quickstarts (https://auth0.com/docs/quickstarts), you should be choosing (Native/Mobile App) if you are deploying to app stores, and (Single-Page App) if you are deploying the web version of Ionic. From there you can pick Cordova (for native) or Angular (for SPA). These should give you instructions that implement OAuth flows which DO NOT require your client secret. My guess would be you are referencing a "Regular Web App" quickstart, which runs server-side and CAN safely hold the client secret. That's not the world you're coding in if you are using Ionic Hybrid/Native.
I would consider wrapping the call to Auth0 into your own server side implementation as safe. Your API takes user credentials and then calls Auth0 and this way your client_id/secret are secure on your server and the client can be reverse-engineered all the way without compromising your security.
Regarding the other APIs which cannot have credentials you are pretty much out of luck. Their very use case is to be used by an unauthenticated third party, so at least the account creation API cannot really be protected. However you can still use some nicely designed constraints to limit the attack surface. E.g. you can require an email address/phone number to register and you will not allow the same address/phone number twice. If you set up your process that you first need to confirm your email address before you can validate your phone number this will make the life of an attacker a lot harder. He would need a real working email address, and some automation to receive your confirmation mails before he could get to call your SMS service. You could also rate-limit the service per IP-address so an attacker cannot cause your SMS cost to skyrocket by issuing a lot of calls for SMS validation in a short period of time.
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.
The model for our product is like this:
Api backend (headless)
I already have oauth set up and ready to use with a resource owner credentials grant. Anyone who wants to use our api can do so using either an API key or their username/password. Of course they also need their client ID and secret.
SPA frontend that accesses the Api
I have built an SPA that will uses the api to provide a portal GUI for our clients. Given that this client-side app is owned and administrated by us (so it's a trusted app) how can I safely authenticate users using only username/password with oauth?
Originally it was using a JWT auth system that only required username/pass but now that we've implemented oauth I'd like to consolidate. It's unreasonable to make every user need to also have their client id and secret on hand to login, but I want users to have full access to the api from the GUI.
I've looking at using CSRF tokens but how would that work with my app when nothing is generated server-side?
I'm not sure how to proceed.
EDIT: very similar to the problem here.
I have decided to use the solution described here.
And here is a snippet of my implementation
The TL;DR version is
Create a proxy between the app and the api
Store the client ID and secret in the proxy
App logs in using password grant type -- proxy intercepts login request and inserts client id and secret
On login response proxy returns access token as an encrypted cookie
Client stores cookie and sends with api requests (to proxy)
Proxy decrypts cookie and inserts access token into Authorization header before forwarding to api endpoint
For me this has several advantages over implementing something custom on the api itself:
No need for custom grant on oauth server
ID/secret is hidden from app securely and can still use password grant
oauth server can identify client (no need for separate client ids for each user)
You should not use the resource owner credential grant from a JavaScript application. The fact that you own and administer the application does not make it a trusted application.
A trusted client is an application that can keep a secret. SPAs or any JavaScript app cannot keep a secret.
You should use the implicit grant for non-trusted clients.
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.