Code Monkey home page Code Monkey logo

Comments (16)

PerrySetGo avatar PerrySetGo commented on September 27, 2024 7

This is an awesome conversation - if anyone in this thread would like to continue, we'd be stoked to have people's opinions on community.netlify.com - our brand new Community forum that is the perfect place for discussions such as these. You can create an account from scratch or use your Netlify to login via SSO. I'm closing this thread for now. See you in Community :)

from jamstack.org.

biilmann avatar biilmann commented on September 27, 2024 3

If it's your own API I would recommend making a public part of the API that can be consumed straight for the browser.

Alternatively you can use some kind of API gateway to sign those requests, we've made a tiny open-source one called gotiator here:

https://github.com/netlify/gotiator

But there are also far more advanced options that handles rate limiting, etc..

from jamstack.org.

biilmann avatar biilmann commented on September 27, 2024 2

In general you can never expose a secret in your front-end code base, so you'll have to take a different approach.

For an OAuth powered API, there's a few different options that can work. One option is to use the authentication flow called an "Implicit Grant" in the OAuth2 specification:

https://tools.ietf.org/html/rfc6749#section-4.2

If this flow is available with the OAuth API you're using, it just depends on exposing the Client ID, and then the redirect URI on file with the API for that client, needs to match the redirect URI in the OAuth request.

If that flow is not available you have two options. If the OAuth API is your own API and associated with your product, you can use the "Client Credentials Grant" flow where you simply ask the user for username/password and get back either an access token or a refresh token (that can be exchanged for a shorter lived access token).

For APIs that's not associated with your product, and that doesn't support the implicit grant flow, you should never ask for username password (it's an anti-pattern to ask users to give away their credentials for one service to another service), and in that case you'll need a some hosted endpoint where you can do the "Authorization Code Grant" which will give you back a "code" that you can pass to your hosted endpoint, that can in turn use your secret to exchange it for an access token or a refresh token without exposing that secret to the JS layer.

from jamstack.org.

tbrlpld avatar tbrlpld commented on September 27, 2024 1

@andrzejwp The technique in the linked article (sending request through a Cloudflare worker [or any other web function, i.e. AWS Lambda] and letting the function add the key to the request) may hide the API key, but now you have your functions URL in the front end / on the client. So all the points raised by @littlepea still seem to apply.

This does not protect the API from being abused by a malicious actor. They would just send requests through you function URL. I guess this could even make it worse actually, because now not only may your API account be locked for abuse (not complying to rate limits), but your function as well.

Maybe I am missing something, but that is how it seems to me.

from jamstack.org.

ivanoats avatar ivanoats commented on September 27, 2024

For example, Aerobatic can store your secrets in environment variables.
https://www.aerobatic.com/docs/cli/#env

And in case you think I am just tooting my own horn, here's how to do it on Netlify, too:
https://www.netlify.com/blog/2016/10/04/access-local-environment-variables-using-webpack/

And here's how to do it on TravisCI:
https://docs.travis-ci.com/user/environment-variables/

from jamstack.org.

littlepea avatar littlepea commented on September 27, 2024

@biilmann What if I don't need to authenticate the user, let's say I have public parts of the website (like showing blog posts) and private (like showing user orders). For the private ones I need a user to authenticate but for public ones, I should let the user's browser to use those without any actions from the user.
But because all endpoints are authorised by OAuth token I still need to get that token first from the authorization server in the background before I can start making API requests to those "public" endpoints... How can I do it without storing client ID and secret in the browser?

I understand that we can redirect the user in order to "log in" based on his action, but we shouldn't do any "empty redirects" just to "show a list of public blog posts in the home page"...

P.S. To be clear, I am talking about "the OAuth API is my own API and associated with my product", and I could implement the "Implicit Flow", I'm just not sure it's suitable for those "public endpoints" before user goes into any part of the website where he needs to explicitly "log in"...

from jamstack.org.

littlepea avatar littlepea commented on September 27, 2024

@biilmann So you mean that those endpoints will have no authorization except for "security by obscurity" like checking X-Requested-With header, HTTP referrer, rate limiting, etc...

In this case, how is this different from me creating an app/client with scope only for those public endpoints (like read-public), calling it something like website_name, storing client ID and secret on the front-end and following the normal OAuth flow? It's basically also "security by obscurity", bad actors can use it to access the public API endpoints, but any other way of protecting it can be easily bypassed too...

As far as rate limiting, it can be applied, either way, it's just a good practice.

So I still don't quite understand what difference does it make to store on not store the client secret on the front-end in terms of security?

P.S. Nice API gateway tool!

from jamstack.org.

biilmann avatar biilmann commented on September 27, 2024

No, I wouldn't argue for security by obscurity (ever), I just mean that if browsing the blog posts on the web site is available to the public, why not have the API endpoint be publicly available as well?

from jamstack.org.

littlepea avatar littlepea commented on September 27, 2024

@biilmann for a couple of reasons:

  1. It's still a little harder for "content stealers" to scrape the API, they have to at least figure out the whole OAuth flow (I'm in China and this "public content stealing" is a real concern, IP laws don't work really well here)
  2. It's easier to analyse the API traffic if all access is unified and I can see that my_web_app client has made those requests, I can also compare them with website page views and see if there's any mismatch in traffic (see point 1)

I understand that this makes the client secret not really a "secret", but I don't see what's especially less "secure" about it than any other solution (like "just make it public" or "proxy")...

from jamstack.org.

biilmann avatar biilmann commented on September 27, 2024

For the API traffic analysis you can just require a client_id in the requests. Adding a secret won't make that more secure if the secret is public anyway.

For preventing content stealers specifically there are solutions like: https://www.perimeterx.com/

from jamstack.org.

littlepea avatar littlepea commented on September 27, 2024

@biilmann Yes, I'm not saying that adding a secret would make it "more secure", I'm just saying that it wouldn't make it "less secure" so why people say it's such a "no-no"?

I would do it just to keep the way API handles requests more unified, everything is based on tokens, tokens are acquired via OAuth flow, all the analytics is based on clients, etc...

If I already have an API that handles everything based on OAuth grants why not just follow this way for all clients including SPAs, to make public endpoints ignore access tokens and require client id (which before was only needed by the authorization server) is an extra customization and extra work which doesn't really change anything... (same with setting up a proxy API gateway)

from jamstack.org.

littlepea avatar littlepea commented on September 27, 2024

@jhabdas This is very interesting as a "poor man's Vault" solution, but how can it be used in the JAMStack context and OAuth API flow?

Does it mean I save an encrypted secret with my front-end code and then send it to the authorization server to get an access token? How is this different from sending a non-encrypted secret in this context? At the end of the day, someone can grab the encrypted secret from the front end code and still use it to get a token from the authorization server...

from jamstack.org.

littlepea avatar littlepea commented on September 27, 2024

@jhabdas The way I see it the cryptex library is about securing server secrets, it could be used in a context of a SPA (for example to be able to store the client ID and secret together with a JAMStack app code), but I don't see what difference would it make one way or another for API security in this context

from jamstack.org.

sgb-io avatar sgb-io commented on September 27, 2024

Isn't the redirect OAuth flow a good solution to stay compliant with the JAMstack criteria?

For example, take Github. It requires the client ID and a redirection URI, but not the client secret. In the context of a SPA, you can put a link to it and provide the SPA url as the redirection URI. Following this, you have a code, which can in turn be exchanged for an access token.

At this stage the client secret is required, but this can be done with another backend (eg this is what Gatekeeper is used for), but this can be kept away from your SPA.

from jamstack.org.

andrzejwp avatar andrzejwp commented on September 27, 2024

Hey guys, I know the thread is closed, but since it gets a lot of visibility - I thought I'll post a link to a recent article that we posted on that subject. It applies to any JAMstack case, really.

How to secure your private API keys in JAMstack

from jamstack.org.

andrzejwp avatar andrzejwp commented on September 27, 2024

@tbrlpld consider a similar situation in a case when you have a backend running. It's still your responsibility to apply whatever limitations / security means you see fit for the particular situation. You can choose to apply your rate limitings, captchas and what-nots.

If you're deploying a static website - and for many this also means utilizing publicly available SaaS services and not wanting to write any server-side code - you might not have a place to put that kind of logic. A CF worker seems an option worth considering. The minimum it will give you is a place to "hide" your API credentials.

from jamstack.org.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.