I have a client side React application and a Rails API from which the React app is fetching data.
As you would expect I only want my React application to be able to fetch data from the API and the rest of the world shouldn't be able to receive data from it.
Despite much searching I am yet to find the best way to secure the communication between the two applications.
I have read about JWT tokens and cookie based session authentication but the majority of articles seem to be focused on authentication of users (ie sign in/sign out) rather than communication between just the two applications.
The two apps will share the same domain so is it enough to rely on Cross Origin to secure communication?
Any advice really would be much appreciated.
If I got your question right you want your client(React App) to be the only client who can access your server.
As a solution to that you will have to have a combination of CORS and a JWT authorization, Thus I would suggest having a strict CORS to enable only your react app's domain to make a call to the server. To achieve this, I generally use a CORS npm module and configure the origin on my server or you can do it yourself as well.
var express = require('express')
var cors = require('cors')
var app = express()
var corsOptions = {
origin: 'http://example.com',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
The above code allows only requests from example.com to be accepted by the server or have a look at this code for more dynamic whitelist & blacklist approach.
Now coming back to JWT, It is just a json encryption and decryption token which can share across API request to Authenticate as well as authorize the user.
For instance, you can store information like email, role, and nickname of the user in JWT and sent this encrypted JWT in each API request, the server authorizes this request and if true forwards to the requested API. This process of authorization and forwarding is generally implemented using an 'Interceptor' pattern wherein a middleware(Passport oAuth) does the check and auth before each API call.
Doing the above 2 things will ensure that only a client which has valid JWT token and domain address which you allowed to talk with the server. And this client will be your react app, as it is the only one with proper JWT and origin address.
So now your react app should just make sure that appropriate JWT token is passed in the API calls (post/get/put), most probably in the header of the API request, you can have an API helper service which does this for you and import that in component where-ever you make an API call. And your node server will implement the passport middleware pattern to authorize this JWT and filter non-authorized requests.
If you react app doesn't have a login, The JWT can be a client ID as well which recognizes your client as being legit. And just like user login, you can have you react app make a call to the server with data like a secret client id. This will return a JWT token. OR you can pre-generate a JWT token and you react app store it when it loads the first time, and by setting TTL and another config you can check if the Client which is making a call to your server is Old or New or some other fake client.
HTH
The case of cross origin domains is when you might need to implement CORS and a security like a blacklist. JWT is a little different, as you say authenticating users who need access to your api.
I believe as long as you don't enable CORS on your server, you'll be fine.
Note that this will not stop people from doing things like:
https://example.com/api/blah to access a part of your api if it is public. This is essentially the same as your front end doing the same because the client is served to the user, and the user then has full control over the client. They could change all instances of api calls in your app to a different endpoint and you couldn't stop them, just as they could just type it in the url bar. Any public endpoints on your api have to not share sensitive info.
Related
I've got an OAuth2-driven authorization system for the applications in my ecosystem using the Auth Code flow. At the moment, it is working extremely well following what I feel are best practices. My current flow can be summed up as this:
User clicks a Login button in application frontend.
Backend for application redirects user to Auth Server login page with redirect URI, client ID, etc, in params.
User logs in, Auth Server redirects to Backend /authcode endpoint with Authorization Code.
Backend authenticates with Authorization Code, receives Access (JWT) & Refresh tokens. It stores Refresh token in its own database, and returns Access token as an HTTP-Only cookie.
When Access token expires, Backend sends Refresh token to Auth Server to refresh.
The problem with this approach is it is heavily dependent on a single-backend/monolith/etc architecture. When the access token expires, the backend app in question needs to be able to get the refresh token and then do the refresh against the Auth Server.
My goals for the future state of this architecture are driven by two main concerns:
Allowing backends to be split into multiple micro-services that are all capable of authenticating the same JWT.
Supporting SSO. Currently, even though all users are managed through the same Auth Server and use the same credentials, they need to enter those credentials separately for each app they log into.
My initial thought was to move the refresh handling to the client-side part of the architecture. Since all the apps are owned by me, I could setup a new flow where a user would login directly with the Auth Server, and then the Access (JWT) and Refresh tokens are set as HTTP Only cookies. This is further supported by the fact that all of my apps are hosted via a single domain name (with different root URI paths for different apps). The new token structure would determine which apps a given user has access to.
My concern there is how to secure the Refresh Token client-side. Most likely I would need to use the Path attribute and depend on the fact that all my apps are on the same hostname, which as I said they are and that will not be changing.
I guess the point of this post is I'm looking for guidance on best practices for handling this kind of scenario.
A few thoughts based on design patterns we recommend at Curity:
BACKENDS AND JWTs
Related APIs should be able to forward JWT access tokens to each other, as detailed in the scopes article. Validating the JWT in each API results in a recommended zero trust setup.
BACK END FOR FRONT END
We recommend a particular way of doing this, focused on separation of web and API concerns - see this code example on the token handler pattern.
Token refresh is handled via HTTP Only cookies and client side retries. This provides a stateless solution that is easy to manage, and where the web back end is static content only, eg a content delivery network. It requires a couple utility API components to be deployed though.
An alternative option, as you say, is to write code within your back end to store tokens, so that cookies only contain a Session ID.
COOKIES AND MULTIPLE WEB APPS
In our resources we use reverse proxies / API gateways as the entry point to APIs, rather than a web back end. Common plumbing such as translating cookies to tokens can then be managed via gateway plugins - as covered in this tutorial.
However, when you have multiple web apps you need to keep cookies isolated during API requests. Each app therefore needs its own API routes. This is awkward but is a consequence of needing to use secure cookies for best browser security. It is best managed in the gateway, and separate domains or subdomains is usually cleanest:
https://api.brand1.com
https://api.brand2.com
Each web team is then responsible for their own API routes and the cookie / CORS / CSRF stuff, rather than the API developers.
SSO
This should be determined solely by the Identity Provider session cookie, which will remain valid as you navigate across apps. If you are presenting a login button when the app does not have a secure cookie yet, then it will not feel like SSO though. One technique for making SSO look seamless is for each app to automatically redirect when it does not have application cookies yet, rather than presenting a login button.
SUMMARY
A long answer, but the best solutions require separation of concerns that is not always obvious. Done well, the end result should be simple code in apps, correct security and an architecture that can be scaled.
I understand the Oauth code flow which involves the mobile app, app server, auth server, resource server. The app server is registered with auth server using the clientidand secret. The idea being that mobile app calls an endpoint of the app server which triggers the code flow eventually resulting in callback from the auth server to the app server with the auth code. The app server presents the secret and code to auth server to get the access token.
The other legacy option where there is no clientid and secret is the implicit flow wherein the mobile app receives the redirect url with the auth code (assuming redirect url destination is a SPA) which will invoke auth server endpoint to get the access token.
This is insecure because anyone can steal the access code from the url.
The solution to this for clients like mobile app is to use pkce. A random number hash is sent in the initial request which is verified later on when the auth code is passed to retrieve the access token.
This prevents the compromise of the access code from the url if an attacker is snooping because without initial hash the auth code is useless.
However how can the situation where the mobile phone is hacked and the secret and auth code is recorded by an attacker be handled to prevent misuse?
However how can the situation where the mobile phone is hacked and the
secret and auth code is recorded by an attacker be handled to prevent
misuse?
This is out of scope for OAuth 2.0 & related specifications. This issue is similar to storing encryption details in a server, but still, the server can be attacked by gaining physical access. It's a different attack vector altogether. It is user's duty to make sure their devices are safe from other vulnerabilities.
However, PKCE provides an extra security layer for public clients' usage of OAuth flow. It prevents attacks based on redirect (authorization code stealing), by establishing secondary validation at the authorization server.
In general, read through OAuth 2.0 Threat Model and Security Considerations & OAuth 2.0 for Native Apps for best practice suggestions.
These are the standard options:
PKCE uses a different code_verifier and code_challenge for every login attempt. If an authorization code is somehow captured from the system browser by an attacker it cannot be exhanged for tokens. No client secret is used, since a mobile app is a public client.
Use HTTPS redirect URIs (based on mobile deep links) so that if an attacker steals your client_id and redirect_uri they cannot receive the response containing the authorization code and will not be able to get tokens.
See this previous answer of mine for some further details, though claimed HTTPS schemes are tricky to implement.
Of course if an attacker has full control over a device, including authentication factors such as autofilled passwords, there may still be attack vectors
I have a web app that exposes an api using devise_token_auth. I build multiple mobile apps that talk to different facets of this web app over https. They use devise_token_auth to get an access token, and then the access token is used in future requests.
I want to avoid the case where others create their own mobile apps that talk to my web backend.
When a call is made from the mobile client, it uses a user and password who has already signed up on my server to get an access token. How do I preclude others from creating their own mobile clients?
Option 1: I could create a secret api token, and use it on the client and server, where mobile client passes in the api token and the server only accepts the requests containing the api token.
Problem with option 1: anyone who sees the request on the wire can now create a similar request with the api token, and use the api token to make the same call.
Option 2: I make my web server an oauth server, where my app uses oauth to authorize client requests only for my own api user, and rejects other requests.
Problem with option 2: I don't know enough about oauth to know if it works this way, and how to implement this in addition to devise_token_auth - this effectively means two credentials are checked on the server - the oauth verification of the api user, and the devise_token_auth verification of the actual user.
I did look at this and this related questions, but they are not exactly my scenario. The recommendation in those threads seems to be a) that https + basic auth is enough and oauth is unnecessary, and b) blocking ip addresses that are unauthorized (Problem: I don't know how to detect which ip address is my mobile app users' and which is someone else's). c) Another insight from those threads is that if I stored some private secret key in my mobile apps to use to identify the app, they are likely going to be exposed since mobile apps (at least on android) are fully reverse-engineerable.
Any suggestions on how best to design/implement this? Is just https + basic auth sufficient?
I would be happy to share any code (since SO usually expects code in the question) - but honestly don't know what code to share here.
I'm currently developing my own service with its own app. The service has a backend JSON API that the app uses to communicate.
Now, since an iOS app does not have sessions or cookies, I was wondering how I would go about creating a user authentication/login for my app. Should I simply locally encrypt the password/username and then, for every action (such as posting a new entry), send the user/password with the request (which seems unsafe), use a token-based system (app receives a token from the service when authenticating, saves it locally - encrypted - and then sends it with the request), or something else? Should I try to implement OAuth for my service?
I'm using the CodeIgniter Rest API for the backend.
Thanks!
My preference includes both. I normally use oauth2 with a bearer token setup (if I remember correctly). I ask for a username/email + password, encrypt the password client-side and send it to the server via Basic Auth in return for an access token which I can send on all consecutive calls. That way I can always revoke access to the backend by invalidating the access token. Oauth2 is much easier to implement than Oauth 1.0a and by following the specification, it is easy to open up your api for 3rd party apps later.
The Oauth2 access token can be send as a GET parameter, but lately I start to think sending it as a header might be preferable, to distinguish better the meta parameters like an access token and data parameters like it's or a model's actual data.
I am writing some code to get Twitter and Instagram feed. Before I can write any code, I keep wanting to get a good understanding of oAuth because I have this nagging feeling that it is not all that secure and that most times, for instance when accessing public tweets, it is an unnecessary hassel. I started reading the oAuth 2 specification to get a better understanding, I am still in the middle of it. And I have a host of questions.
Let's use Twitter as an example.
A user accesses your site. You redirect them to Twitter for authentication and to obtain the authorization_grant code.
I understand this part is secure because the user authentication and the redirect to your website will happen over ssl. Is it enough for Twitter to support SSL or does your site also have to support SSL for the redirect to be secure? You wouldn't want the authorization code to be transferred insecurely, right?
Now that you have your authorization_grant code, your site will send a request to Twitter to obtain an access token. When making this request your site will send the authorization_grant code, your client id and client secret. Again I guess the communication is secure because this will happen over ssl. But what if the site has included the client id and secret somewhere in its HTML or Javascript, especially if it is a static site with no server side code?
Should the redirect url always be handled by server side code and the server side code should make the request for access token without ever going through HTML or Javascript?
Once you have the access token, you will include it in your request to obtain the user's tweets, to post tweets on their behalf etc. Again if the site in question were to include the access token inside its HTML or JavaScript along with the client id and secret, that would be pretty insecure, right?
It seems all the security of oAuth stems from ssl and the client's ability to keep their client secret secret. Am I right in this conclusion?
Another thing - in the first step of the process, when the client redirects the user to Twitter to authenticate and obtain the authorization_grant code, they could send in their client id and secret and get the access token directly instead of making a second request for it. I think this is what they mean by the implicit method in the specification.
So, why was this extra step of sending a second request to obtain access token added in the specification? Does it increase security?
I am not sure about twitter API, I am talking with respect to stackexchange API
https://api.stackexchange.com/docs/authentication
Again I guess the communication is secure because this will happen
over ssl. But what if the site has included the client id and secret
somewhere in its HTML or Javascript, especially if it is a static site
with no server side code?
client_secret is send only in the case of explicit flow. Explicit flow should be used by server side application and care should be taken to keep the client_secret safe.
So, why was this extra step of sending a second request to obtain
access token added in the specification?
Well, Implicit flow is less secure than explicit flow since access toke is send to the user agent. But there is an attribute expire in the case of implicit flow which will get expired unless you have specified scope as no_expiry. Also server side flow can be used only by the apps that are registerd
It seems all the security of oAuth stems from ssl and the client's
ability to keep their client secret secret. Am I right in this
conclusion?
Again client_secret will be available in server side flow. But yes, client should take care that access_token is not given out
Check out this link. It gives an example of possible vulnerability in ouath.