loading...

How do you protect your backend API in your microservice if you use a Single Page Application on the frontend?

djviolin profile image István Lantos ・2 min read

I currently working on a pet project where I intend to learn a "simple" microservice architecture, meaning no universal rendering (or I thought it would be simple).

I have a backend REST API written in Go, which is proxying a third-party API. Later on it will be replaced with a Postgres database. Right now serving content under 127.0.0.1:8080/api/v1.

I have a static fileserver written in Go for SPA, which is serving a Single Page Application written in Vue.js, generated by vue-cli. This fileserver serving content under 127.0.0.1:8081. This vue app querying data from the API server with axios, fecthing AJAX requests.

This is where I hit the first problem: if I not whitelisting the address of the static fileserver on the API server, so the server doesn't have any CORS header presented, like:

Access-Control-Allow-Origin: http://127.0.0.1:8081
# or
Access-Control-Allow-Origin: *

The request got ignored by the browser.


Another problem (well, not really a problem) that I had to drop the relative urls in axios (because they are not on the same server anymore), meaning replacing:

return this.$http.get(`/api/v1/${this.id}/`, {

with:

return this.$http.get(`//127.0.0.1:8080/api/v1/${this.id}/`, {

in the vue app.

Am I doing something wrong here? How should I make request to the API server from the SPA from another server?


How can I protect my backend API from people to using it without restrictions?

I guess I have to implement a rate limiter for sure. I plan to use HAProxy for load balancing and probably this is the point where it should limit the requests from users who wants to execute DDOS attacks or use the database as a free fountain for their sites.

But there are no other way of limiting the API accessing it from the browser bar, if they type in the address of the API server? What about GraphQL? Same situation?


This site will not feature any authentication, user management, or restricted access at the start. But if I try to implement such feature in the future, how can I implement user authentication safely, not shooting myself in the leg? What are the best practices to do this, if I completely want to ditch server-side or universal rendering?

I want to have an SPA and an API server which will be a good start for web and mobile apps, too.

Discussion

pic
Editor guide
Collapse
usamaashraf profile image
Usama Ashraf

I could be on the wrong track here, but employing a microservices-based architecture without a proper API gateway is considered a bad practice. The idea is similar to a reverse proxy of course (Nginx, HAProxy etc): a single interface (facade) sitting in front of all the individual services that makes life easier for clients since then they would just have to talk to one server.
Clients should not have to talk to the microservices directly, for a number of reasons:

  • The client has to make several separate requests.
  • Makes it extremely difficult to refactor the microservices e.g. merging or splitting existing services.
  • Imagine your services being relocated, IPs changing, ports changing, that the clients will have to adjust to e.g. by updating the allowed origins.

It is absolutely crucial that your clients and the microservices remain independently deployable, maintainable, scalable etc.

Of course, for different kinds of clients you could have different gateways like, famously, Netflix does.

The API gateway itself can and should handle limited business logic like combining responses from multiple services and returning them to the user or even authorization.

This might be a good place to start.

Collapse
rhymes profile image
rhymes

Very interesting!

Although I didn't classify what @djviolin wrote as a microservice but I might be wrong :-) I don't know if now "API server" as become a synonym for microservice.

Thanks for the link, I'll check it out!

Gateway wise I always wanted to check out Kong but I still haven't found a project to use it for.

Collapse
djviolin profile image
István Lantos Author

In the last few days I checked some API gateways and dumped it down to these solutions:

getkong.org
tyk.io
krakend.io
traefik.io

Traefik seems a nice little project, but doesn't feature any authorization service and the biggest minus is cannot be extended with plugins (to have some kind of auth), but there is a PR request regarding this, based on Go's newest Plugin library: github.com/containous/traefik/issu...

Kong, Tyk, and KrakenD seems nice projects, they are also extensible with plugins.

Looks like these projects also managing load balancing and rate limiting, so using HAProxy is obsolute?

Collapse
usamaashraf profile image
Usama Ashraf

Largely subjective. You might even try developing your own gateway, nothing wrong with that.

I'd prefer using load-balancing, rate-limiting features if they ship with the gateway. Though consider caching as well.
Else, an Nginx/HAProxy instance could be placed in front of multiple instances of the gateway. Best of luck!

Collapse
rhymes profile image
rhymes

I'll try to answer with what I know:

CORS

Yeah, you definitely need CORS while you're developing a SPA with a different server.

It also enables other clients to consume your API.

Proxying requests

The proxying issue hit me as well, I didn't actually solve it because it was configured in the webpack vue template. If you are using it the solution is here: github.com/vuejs-templates/webpack... - If you are not refer to webpack's own documentation: webpack.js.org/configuration/dev-s...

Authentication

I still have to implement it in my own SPA, because it's not exposed to the web and I'm waiting for some business requirements on how to best do it so I don't have an answer for you. In the meantime I can refer you to some articles (I haven't read everything yet :D):

Collapse
djviolin profile image
István Lantos Author

Thank You!

Yeah, I know about the proxy in vue-cli, but the problem I don't want to use this Node.js server in production, so I build the vue project and Go will be the static fileserver. For development, the webpack based proxy server in vue-cli is fine though.

I can implement a proxy in Go which is exposing the api server within the static server (under a route like /api/v1, this way I can use relative urls in axios), but my problem with this approach is that the static server is not only serving the static files in this case, it's doing a little bit of backend work also. Which I try to ignore, because what if the static files hosted on AWS?

Collapse
rhymes profile image
rhymes

Why don't you just deploy the build of the SPA to the go server so it can serve it?

I'm not using Node as a server, just for development. I have a post build command that builds the static files so that the Python server can send them to the client.