Do I need to save my Mapbox token in a environment variable? - mapbox-gl-js

I just switched from gmaps to Mapbox, and I want to keep my account and tokens safe.
I have already added a set of urls that are able to reach my mapbox service
I have the default scopes:
styles: tiles
styles:read
fonts:read
dataset:read
vision:read
In my app, I just show some markers on the screen and show a pop up on hover, so i think those scopes are fine.
The thing is my token is on the client, so it i visible to the public.
Is this correct? or do i have to send it from the backend or something? buteven in that case it would still show in the client, is this ok?

What you're doing is correct: exposing the public API token (pk.something) in the JavaScript front end. The risk it sounds like you're attempting to mitigate against is the risk of someone grabbing your token to make their own API calls. Setting URL restrictions (as you have done) and occasionally rotating the tokens is the correct way to do that.

Related

Next.js/Next-Auth/Apollo/GraphQL Setup

I'm looking for recommendations on how to approach a next.js front end that uses Apollo and GraphQL to access a PostgreSQL database. I figured it made sense to separate the front and back end, but I'm realizing there are tradeoffs. Next.js and NextAuth.js seem designed to work well when using the Next.js API functionality.
A few requirements:
Data needs to be restricted based on the user (public, internal, admin).
Using Google OAuth for signing in
With this in mind, NextAuth.js gets more complicated if you want the back end to be aware of the user's access rights.
However, if my apollo/graphql back end is independent there are definite benefits like:
I can swap out the front end if ever needed so there's some flexibility
Code and dependencies may be simpler than a combined front/back end
My current challenge is that I've got NextAuth.js working within the Next.js app, but I haven't figured out how to control data access. The best idea I've got so far is some sort of token management that mixes NextAuth.js and my back end. That doesn't seem to be the way NextAuth.js is designed though so I'm rethinking the whole architecture and looking for suggestions.
Thanks!
I found a very brief discussion of a similar question here, but I'd love to hear how others would approach this.
How to forward user sessions in Next.js + Graphql decoupled architecture?
I'm going to do my best to give a fairly generic answer, using a JWT for Authorization, but I'm going to have to make some assumptions since I'm not super familiar with Google OAuth & related Google system.
First, and most importantly, it's important to clarify the difference between Authentication, or "who you are" and Authorization, or "what you can do."
The best idea I've got so far is some sort of token management that mixes NextAuth.js and my back end. That doesn't seem to be the way NextAuth.js is designed though so I'm rethinking the whole architecture and looking for suggestions.
NextAuth is an Authentication library, and doesn't support external validation of the NextAuth-created JWTs, so you're right to not want to mix NextAuth with your backend. When someone logs in NextAuth creates a NextAuth-specific JWT (an ID Token) that will be passed between the Client and the Next Server. It tells you who the user is, and proves that they've logged in. Unless you're using database sessions, which I haven't used so can't speak to.
Extra work is required to implement Authorization so that you have a JWT that also describes what access rights the user has, that you can pass to your backend.
Ideally you will be able to leverage Google OAuth for this, and assuming that is the case, this is what I would do:
For the architecture
I'm not very familiar with GraphQL/Apollo, but separation there seems fine. Important to note, though, that not separating is also probably fine. Any approach will have tradeoffs, so you'll have to evaluate what works best for your situation.
Whenever you make a call to the backend, you pass your JWT with the call as an Authorization header, in the form of Bearer <token>.
On the backend, then, you validate the token with each incoming call, and allow the call to proceed (or not) as appropriate.
This is the relevant info I found in the Apollo docs.
For the token
In your NextAuth provider configuration, in the jwt callback you can add information to the NextAuth JWT.
Ideally, your Google OAuth also provides you a JWT (an Access Token). This should be something that should be relatively easy to validate on the backend, and it is what you'd want to use for Authorization.
You can store this Google OAuth JWT (access token) within the NextAuth JWT (id token) when the user first logs in, and then retrieve it on the Next.js server before you make your calls to the GraphQL backend. That would look something like this:
// [...nextauth].js
const options = {
// ... other configuration
callbacks: {
jwt: async (token, user, account, profile, isNewUser) => {
const isSignIn = !!user
if (isSignIn) {
token.b2c = {
accessToken: account.accessToken,
refreshToken: account.refreshToken,
iat: profile.iat,
exp: profile.exp,
}
}
return Promise.resolve(token)
}
}
}
This is a simplified example from the configuration I use. My config is for Azure AD B2C but it's the same general flow you're looking for. You can see my full config here which shows some additional code I use to handle refreshing the access token as needed.
If you don't have something usable from the Google OAuth flow, this gets more complicated and you'd have to build something custom.

How to secure REST API PUT/POST calls being called manually through postman

Actually I have an API called update user data, it is called when the user moves from one page to another page. If the user copy the API from console and post in postman, user should not able to update the user data. How to provide security or implement feature to not to update data through post man.
You really can't.
You can slightly make it harder using some CSRF protection, but that's just it - it will only make it a bit harder, but not stop anyone determined.
If your API is public, you should be ready for your users to have custom client apps.
I am a bit confused by your question. Because PostMan or other applications like Fiddler are created to make the job easier for developers during development. anyhow if you are concern about who makes call to your webpage, you can make your API private and just give access to the user that have the right credentials. You can also read about CSRF or XSS.

Understanding CORS and Same origin policy

Lets say I own a site www.a.com which shows some information to the user after logging him in. Here is the flow (assume everything is over https even if not explicitly mentioned) -
User loads https://www.a.com/ which also sends down the login page.
User types login+passwd and the JS calls www.a.com/login and gets an auth token (T) back.
JS then calls www.a.com/getdata (and T is sent as well). The server responds with the data for the appropriate user.
Just looking at the code anyone can know that the two APIs the JS uses are www.a.com/login and www.a.com/getdata
Now here are the scenarios I get confused over -
IF a rogue entity (or someone like mint) creates a site (www.r.com) that asks for the user password and posts it to the APIs can my server know it?
Here the JS is not from a.com but completely re-written by r.com. Do the CORS rules or same origin policy apply here?
Another scenario, IF www.r.com embedded a frame on its page that is loading www.a.com and asking for user name and passwd there, that means its actually loading the a.com JS. In this case, can JS from r.com access the data sent down to the frame loading a.com?
Do the CORS rules or same origin policy apply here?
Yes. Per the Same Origin Policy the script on r.com will not be able to read the results of any request it makes to a.com. Therefore it will not be able to read the login token. If you add CORS support then you can opt-in to allowing r.com access, in which case it will be able to interact freely with your site.
Note that if r.com is a malicious site and is able to get the user to enter their password, the browser's Same Origin Policy won't actually protect the user. The malicious page can just send the information to their own server where arbitrary requests can be sent to your site with the user's credentials.
Can JS from r.com access the data sent down to the frame loading a.com?
The Same Origin Policy applies to iframes as well, so the r.com script will not be able to access the data sent to the a.com iframe.

How to pass Facebook Id from client to server securely

I have a Facebook canvas app. I am using the JS SDK to authenticate the user on the browser-side and request various information via FB.api (e.g. name, friends, etc.).
I also want to persist some additional user information (not held on Facebook) to the database on my server by making an ajax call:
{ userFavouriteColour: "Red" }
To save this on the server and associate with the correct user, I need to know the Facebook uid and this presents a problem. How do I pass the uid from the client to the server.
Option 1: Add uid to the ajax request:
{ uid: "1234567890",
userFavouriteColour: "Red" }
This is obviously no good. It would be trivial for anyone to make an ajax request to my web service using someone else's Facebook Id and change their favourite colour.
Option 2: On the server, extract the uid from a cookie:
Is this even possible? I have read that Facebook sets a cookie containing the uid and access token but do I have access to this cookie on my domain? More importantly, can I securely extract the uid form the cookie or is this open to spoofing just like option 1.
Option 3: User server-side authentication on the server:
I could use the server-side authentication to validate the user identity on my server. But will this work if I am already using client-side authentication on the browser? Will I end up with two different access tokens? I would like to make FB.api requests from the browser so I need the access token on the client (not just on the server).
This must be a very common scenario so I think I'm missing something fundamental. I have read a lot of the Facebook documentation (various authentication flows, access tokens, signed_request, etc.) and many posts on SO, but I still don't understand how client-side authentication and server-side authentication play nicely together.
In short, I want to know the user's identity on the server but still make requests to the Facebook api from the client browser?
(I am using ASP.NET and the Facebook C# SDK on the server)
EDIT: Added bounty. I was hoping to get a more deifnitive, official recommendation on how to handle this situation, or even an example. As said, I have already read a lot of the official FB docs on authentication flows but I still can't find anything definitive on how client-side and server-side authentication work together.
Option 1:
The easiest way I can think of is to include the accessToken in JS and pass it with the ajax call.
Option 2:
Using the same as option 1, but instead of sending just the accessToken, send the signedRequest.
On the server side you can decode it using (TryParseSignedRequest method) which will give you the UserID :-)
Note: signedRequest is encrypted with the application Secret. you are the only one who should know it, so you are safe on that end.
Disclaimer:
I have no coding experience in C#, but a little search in google gave me this:
Facebook C# SDK for ASP.NET
Making AJAX Requests with the Facebook C# SDK
It's very simple actually.
When the user loads you app use the server side authentication, get the access token and load the user data by issuing an api request from the server.
On the server side you'll have everything you need and it's sandboxed.
When the page renders for the user, using the js sdk get the user authentication data, you should be able to use FB.getLoginStatus since the user already went through the server side authentication.
Now on the client side you also have an access token which you can use to get the user data from the graph api.
The two tokens will be different, and will also have different expiration, but that should not be a problem, both token should work properly as you'd expect them to.
Since both sides have their own token and a way to make requests to the api, there's no need to send any fb data between them.
So the 3rd option you mentioned, to me, sounds the best, and it's really simple to implement that too.
Edit
All facebook SDKs are just wrappers for http request since the entire fb api is made on http requests.
The SDKs just give you easy and shorter access to the data with out the need to build the url yourself (with all the different possible parameters), make the request and parse the response.
To be completely honest, I think that stop providing a way for the C# SDK to support server side authentication is a very bad decision.
What's the point in providing a SDK which does not implement the entire api?
The best answer to your question, from my experience, is to use both server and client side authentication, and since the C# SDK does not support it, my advice to you is to create your own SDK.
It's not complicated at all, I already implemented it for python and java (twice), and since you'll be developing it for your own needs it can be tailored for your exact needs, unlike a public SDK which should support all possible options.
2nd Edit
There's no need to create a completely new SDK, you can just "extend" the ones you're using and add the missing parts that you need, like sever side authentication support.
I don't know if it's language specific but using both server-side and client-side authentication does no harm.
You can work on option 2 but yes, that will be also vulnerable to spoofing.
Doing option 3, you will be having a single access token for that user session, so that would be the best choice according to me since you always have chance of spoofing when passing user information from client side.
I had exactly the same question recently. It's option 2. Check this post from the Facebook blog.
To be honest I am not enough of a hacker to know if you could spoof the UID in the cookie, but this seems to be the 'official' way to do it.
EDIT: to the other question under option 2, yes, I believe you have to access this cookie on your domain.

How to use the same facebook application for different websites

I'm developing a small CMS in PHP and we're putting on social integration.
The content is changed by a single administrator who as right for publishing news, events and so on...
I'd to add this feature, when the admin publishes something it's already posted on facebook wall. I'm not very familiar with facebook php SDK, and i'm a little bit confused about it.
If (make it an example) 10 different sites are using my CMS, do I have to create 10 different facebook application? (let's assume the 10 websites are all in different domains and servers)
2nd, is there a way for authenticating with just PHP (something like sending username&password directly) so that the user does not need to be logged on facebook?
thanks
You might want to break up your question in to smaller understandable units. Its very difficult to understand what you are driving at.
My understanding of your problem could be minimal, but here goes...
1_ No you do not create 10 different facebook application. Create a single facebook application and make it a service entry point. So that all your cms sites could talk to this one site to interact with facebook. ( A REST service layer).
2_ Facebook api does not support username and password authentication. They only support oauth2.0. Although Oauth is not trivial, but since they have provided library for that, implementing authentication is pretty trivial.
Please read up on http://developers.facebook.com/docs/.
Its really easy and straight forward and well explained.
Your question is so vague and extensive that it cannot be answered well here.
If you experience any specific implementation problems, this is the right place.
However to answer atleast a part of your question:
The most powerful tool when working with facebook applications is the Graph API.
Its principle is very simple. You can do almonst any action on behalf of any user or application. You have to generate a token first that identifies the user and the proper permissions. Those tokens can be made "permanent" so you can do background tasks. Usually they are only active a very short time so you can perform actions while interacting with the user. The process of generating tokens involves the user so that he/she has to confirm the privileges you are asking for.
For websites that publish something automatically you would probably generate a permanent token one time that is active as long as you remove the app in your privacy settings.
Basically yuo can work with any application on any website. There is no limitation. However there are two ways of generating tokens. One involves on an additional request and one is done client side, which is bound to one domain oyu specifiedin your apps settings.
Addendum:
#ArtoAle
you are right about every app beeing assighend to exactly one domain. however once you obtained a valid token it doesnt matter from where or who you use it within the graph api.
let me expalin this a little bit:
it would make no sense since it is you doing the request. there is no such thing as "where the request is coming from". of course there is the "referer" header information, but it can be freely specified and is not used in any context of this.
the domain you enter in your apps settings only restricts where facebook redirects the user to.
why?
this ensures that some bad guy cannot set up a website on any domain and let the user authorize an app and get an access token with YOUR application.
so this setting ensures that the user and the access token are redirected back to YOUR site and not to another bad site.
but there is an alternative. if you use the control flow for desktop applications you don't get an access token right after the user has been redirected back. you get a temporary SESSION-TOKEN that you can EXCCHANGE for an access token. this exchange is done server side over the REST api and requires your application secret. So at this point it is ensured that it is YOU who gets the token.
This method can be done on any domain or in case of desktop applications on no domain at all.
This is a quote from the faceboo docs:
To convert sessions, send a POST
request to
https://graph.facebook.com/oauth/exchange_sessions
with a comma-separated list of
sessions you want to convert:
curl client_id=your_app_id \
-F client_secret=your_app_secret \
-F sessions=2.DbavCpzL6Yc_XGEI0Ip9GA__.3600.1271649600-12345,2.aBdC...
\
https://graph.facebook.com/oauth/exchange_sessions
The response from the request is a
JSON array of OAuth access tokens in
the same order as the sessions given:
[ {
"access_token": "...",
"expires": 1271649600, }, ... ]
However you don't need this method as its a bit more complex. For your use case i would suggest using a central point of authorization.
So you would specify your ONE domain as a redirect url. This domain is than SHARED between your websites. there you can obtain the fully valid access token and seamlessly redirect the user back to your specific project website and pass along the access token.
This way you can use the traditional easy authentication flow that is probably also more future proof.
The fact remains. Once the access token is generated you can perform any action from any domain, there is no difference as ther is literally no "domain" where the request is coming from (see above).
apart from that, if you want some nice javascript features to work - like the comments box or like button, you need to setup up open graph tags correctly.
if you have some implementation problems or as you said "domain errors" please describe them more clearly, include the steps you made and if possible an error message.