REST API: Providing redirect URIs to external services using client app domain - rest

Background
I have a RESTful API accessed through the domain http://restapi.com
I have a client app using http://restapi.com. The client app has the domain http://myapp.com
The way I have my HATEOAS setup is that the API presents URIs without a domain. So instead of http://restapi.com/some/resource, it contains links to resources like so /some/resource. Example API json resource below:
{"_links":{"self":{"href":"/some/resource"}}}
The benefit this has is that the API doesn't need to know about the client app, and the client app has to do very little to get the correct resource from the API and doesn't have to reformat all the URIs in the resource. For example, in the client app, the following URI would be used by the browser http://myapp.com/some/resource. When the app gets the request, it then needs to call the API to get the resource and simply swaps the domain i.e. http://restapi.com/some/resource.
This has been successful so for, and allows a lot of flexibility to have different clients use the API with the only knowledge required being the initial end point (domain) of the API. It also completely decouples the API from the client apps.
The problem I have run into is that I have started using some external services (specifically PayPal adaptive payments) where I need to provide a redirect URL for cancelled payments and successful payments. For example, the browser navigates to http://myapp.com/payment. The resource returned by http://restapi.com/payment presents a link to PayPal. Without going into too much detail, the API has to ask PayPal for a payment ID, which can then be used to create a link to a PayPal payment e.g. http://paypal.com?PayId-123456. Part of the creation process requires that URLs are provided to redirect on payment cancellation or success. Again, don't want to go into details, but when requesting a PayId from PayPal, the redirect URLs are sent as variables to PayPal, and I guess PayPal stores them against the specific PayId created.
The browser navigates to the link returned in the resource - http://paypal.com?PayId-12345. Payment is made and PayPal then uses the redirect URLs as needed to redirect back to my app e.g. on successful completion of payment, PayPal should redirect to http://myapp.com/paymentcomplete. Note: I realise that this is not a restfully named URI, but it simplifies building up the description of my problem
Problem
The problem I have may now be obvious. I need to redirect back to http://myapp.com/paymentcomplete, BUT its the API that provides the redirect URL to PayPal. It has no knowledge of the client application. Since PayPal is an external service, the full URL must be provided. The best the API can do is send http://restapi.com/paymentcomplete as the redirect URL, but if PayPal redirects to this, the resulting response will be a JSON string (the output format of my API) not the nicely formatted page of the client app.
My question is, what is a good way to correctly provide the redirect URL to PayPal?
One thought I had was to make the client application handle creating the PayPal PayId, but I don't like this option as I would like to keep the creation of the PayPal payment ID on the API side. It would also require every client app to provide its own implementation, something I also don't want.
The other option I though of was to ask the client to provide its domain in the request. Currently the request the client makes to get the resource with the link to PayPal is GET http://restapi.com/payment, but I could use POST http://restapi.com/payment with the client providing its domain as a param. The API can then use this to construct the correct redirect URL. I don't really like this idea either as its seems a bit hackish and also requires the app to know that is must fill in this field i.e. a human user wouldn't fill the domain input in.
Additional solutions, or thoughts greatly welcomed.

As you had already mentioned, PayPal is an external api that requires this additional parameter and you do not have control over it. Looks like the client is the only party that can provide the Redirect URI Information.
Couple of ideas come to mind.
The client could send the redirect uri to restapi via header and thus
keeping your rest urls intact. This is a grey area and not a violation of restful api
in my opinion. (Then again, its just my opinion).
The restapi could return the response with a placeholder for the
client to fill in before rendering. This way the API need not know
about the redirect uri and the responsibility is left to the client
which has this information.
It would be nicer if you could implement option 2 with executing couple of lines on Javascript code on the browser to fill-in the placeholder. Which is easy. Ultimately, only 2 end points of this transaction would be aware of the redirect uri - browser & paypal.
This alleviates most of your concerns. The job of handling PayPal id will continue to remain with your API.

You should be able to use the Referer header to determine the client's full URI. It might be populated automatically for you. If not, you can add it yourself. The URI class has methods to pull out the client's host for you. When the API builds the PayPal URI to return to the client, it can include the client's host.
Note that referer is not always included and sometimes gets stripped by intermediaries, as detailed on the wiki page. Since you control both the client and the server in this case, you should be able to tell everybody to play nicely.

I would keep the GET http://restapi.com/payment and pass in a query param with the client domain
GET http://restapi.com/payment?domain=http://myapp.com (of course, the "http://myapp.com" needs to be encoded)

Related

RESTful API: how to distinguish users requests from front-end requests?

So, I have a RESTful API (built with Hapi.js) that has endpoints consumed by users and my front-end app (built with Next.js). GET api/candies is one of them, I'll take it as an example.
The front-end asks the list of candies stored in my DB and displays them on a page anyone can access (it has to be this way). The front-end doesn't provide an API token since people could read/use it. But, users who want to get this list of candies (to build whatever they want with it) must provide a valid API token (which they get by creating an account on my front-end app).
How could my API tell if a request for api/candies is from a user or from my front-end app, so it can verify (or not) the validity of their token?
I'm wondering if my problem isn't also about web scraping.
Can anyone help me please? :D
I thought about the same problem a while ago. If your frontend has a client side REST client (JS+XHR/fetch), then I don't think it is possible to do this reliably, because no matter how you identify your frontend REST client, your users will be able to copy it just by checking the HTTP requests in browser via CTRL+SHIFT+I. There are even automation tools, which use the browser e.g. Selenium. If you have a server side REST client (e.g. PHP+CURL), then just create a consumer id for the frontend and use a token. Even in this case I can easily write a few lines of code that uses the frontend for the same request. So if you want to sell the same service for money that you provide for free on your frontend, then you are out of luck here. This does not mean that there won't be consumers who are willing to pay for it.
I think your problem is bad business model.
Your requirement can be addressed by inspecting different headers sent by different user agents. You can also add custom headers from your front-end and validate the same on the backend.

How to call Salesforce REST API from external web forms

I am a bit confused. The requirement is that we need to create a REST API in Salesforce(Apex class) that has one POST method. Right now, I have been testing it with POSTMAN tool in 2 steps:
Making a POST request first with username, password, client_id, client_secret(that are coming from connected app in Salesforce), grant_type to receive access token.
Then I make another POST request in POSTMAN to create a lead in Salesforce, using the access token I received before and the body.
However, the REST API that I have in Salesforce would be called from various different web forms. So once someone fills out the webform, on the backend it would call this REST API in Salesforce and submits lead request.
I am wondering how would that happen since we can't use POSTMAN for that.
Thanks
These "various different web forms" would have to send requests to Salesforce just like Postman does. You'd need two POST calls (one for login, one to call the service you've created). It'll be bit out of your control, you provided the SF code and proven it works, now it's for these website developers to pick it up.
What's exactly your question? There are tons of libraries to connect to SF from Java, Python, .NET, PHP... Or they could hand-craft these HTTP messages, just Google for "PHP HTTP POST" or something...
https://developer.salesforce.com/index.php?title=Getting_Started_with_the_Force.com_Toolkit_for_PHP&oldid=51397
https://github.com/developerforce/Force.com-Toolkit-for-NET
https://pypi.org/project/simple-salesforce/ / https://pypi.org/project/salesforce-python/
Depending how much time they'll have they can:
cache the session id (so they don't call login every time), try to reuse it, call login again only if session id is blank / got "session expired or invalid" error back
try to batch it somehow (do they need to save these Leads to SF asap or in say hourly intervals is OK? How did YOU write the service, accepts 1 lead or list of records?
be smart about storing the credentials to SF (some secure way, not hardcoded). Ideally in a way that it's easy to use the integration against sandbox or production changing just 1 config file or environment variables or something like that

What's the REST way to verify an email?

When a user register to my web application I send an email to verify his inbox.
In the email there are a link to a resource like this:
GET /verify/{token}
Since the resource is being updated behind the scenes, doesn't it break the RESTful approach?
How can I do it in a RESTful manner?
What you are talking about is not REST. REST is for machine to machine communication and not for human to machine communication. You can develop a 1st party REST client, which sends the activation to the REST service.
You can use your verification URI in the browser to access the REST client:
# user follows a hyperlink in the browser manually
GET example.com/client/v1/verify/{token}
# asking the client to verify the token
and after that the REST client will get the hyperlink for verification from the REST service and send the POST to the service in the background.
# the REST client follows the hyperlinks given by the service automatically
# the REST client can run either on the HTTP client or server side
GET example.com/api/v1
# getting the starting page of the REST service
# getting the hyperlink for verification
POST example.com/api/v1/verification {token}
# following the verification hyperlink
If you have a server side 1st party REST client, then the HTTP requests to the REST service will run completely on the server and you won't see anything about it in the browser. If you have a client side REST client, then you can send the POST in the browser with AJAX CORS or you can try to POST directly with a HTML form (not recommended). Anyways the activation should be a POST or a PUT.
It depends on what are you trying to do.
Does it fire an email after validating the user for example? If so, it is not an idempotent method and you should use POST.
Example:
POST /users/{id}/verify/{token}
If the method doesn't have any consequence besides the update, I think you should use PUT.
Aren't you overthinking REST? With e-mail verification you want the user to be able to simply click the link from whatever mail user agent he is using, so you'll end up with a simple GET on the server (presented as a hyperlink to the user) with the token either in the path or as part of the query string:
GET http://example.com/verify-email/TOKEN
GET http://example.com/verify-email?token=TOKEN
Either is fine for this use case. It is not really a resource you are getting or creating; just a trigger for some process on the backend.
Why do you think this would run afoul of good design?

Client Facing REST API Authentication

I have seen many different posts regarding different solutions for authenticating a RESTful API and I have some questions, given this current scenario.
I've built a REST API that will allow clients of my software service (we are a B2B company) to access resources programmatically. Now that I've got the API working properly, I'd like to secure it in the most standardized way possible. I need to allow access to certain resources based on the caller of the API. That is to say, not all users of the API can access all resources.
I have URLS available in the following formats:
https://mydomain/api/students
https://mydomain/api/students/s123
https://mydomain/api/students/s123/classes
https://mydomain/api/students/s123/classes/c456
So far I've come up with these possible solutions:
Provide a unique key to each client that they can use to ultimately generate an encrypted token that will be passed as a GET parameter at the end of each REST call to (re)-authenticate every single request. Is this approach too expensive
https://mydomain.com/api/students/s123?token=abc123
Provide a value in the HTTP Authorization Header as seen here. Is this almost the same as #1? (Except I can't paste a URL into the browser) Do people use these headers anymore?
Use OAuth 2 (which I'm still a bit unclear on). Does OAuth 2 actually authenticate the client as a logged in user? And doesn't that go against the spirit of a REST API being stateless? I was hoping OAuth was the proper solution for me (since it's a public standard), but after reading up on it a little bit, I'm not so sure. Is it overkill and/or improper for REST API calls?
My goal is to provide an API that will not have to be changed for each client that wants to consume the API, but rather that I can provide a standard documentation made available to all of our clients.
I'll be happy to post additional details if I've been unclear.
There are 2 type of clients you probably want to prepare your API:
trusted clients - Which are written by you. They can have the username and password of the actual user, and they can send that data to your server with every request, possibly in a HTTP auth header. All you need is an encrypted connection by them.
3rd party clients - Which are written by some random developer. You can register them in your service and add a unique API key to each of them. After that if an user wants to use their services, you have to show her a prompt in which she can allow access to the 3rd party client. After that the 3rd party client will be assigned to the user's account with the given permissions and it will get an user specific access token. So when the client sends its API key and the user specific token along with the request, then it sends the requests in the name of the user.
OAuth can help you to control the second situation.
Your URLs do not have a meaning to the clients. By REST you have to decouple the clients from the URL structure by sending links annotated with semantics (e.g. link relations). So your documentation does not have to contain anything about the URL structure (maybe it can be useful for server side debug, but nothing more). You have to talk about different types of links. By generating these links on server side, you can check the permissions of the actual user (or 3rd party client) and skip the links which she does not have permission to follow.

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.