What is the right way to implement authentication between a WordPress plugin and a Laravel API? - wordpress

I'm so confused about how to get authentication between an external, consumer website and a Laravel API right. What I'd like is to have a web app for which users are able to present information from the app to other people, using an external website that consumes the app's API. Here's an example of the basic setup in a bit more detail:
A Laravel 5.3 app that has a protected API endpoint api/status. Only authenticated users should be able to hit api/status, and the status returned is a particular status for the authenticated user.
An external website that consumes the Laravel API on behalf of a user, let's call her Alice. The necessary information is stored in the backend of Alice's website so that it can authenticate with the API on behalf of Alice. (The actual implementation I'm working on will be a WordPress site, and the API consumption will be done by a WordPress plugin that I am implementing; so any info stored will likely be stored in the WordPress database.)
The website has a /status page that displays Alice's status to anyone who browses to the page. (Ie, when the /status page is browsed to, an API call to the app is made on behalf of Alice. The returned status is specific to Alice, and is displayed to the person browsing the page.) People browsing to /status on Alice's website do NOT need to do any sort of authenticating to view the status on the page.
That is very simplified compared to my actual goal, but I hope it serves to keep the extraneous details to a minimum so we can focus on my actual question, which is what method of authentication should I use to achieve this?
One thing I DON'T want:
The person browsing Alice's website should NOT be able to use their browser's inspector to watch the API call and from that create further API calls on Alice's behalf on their own.
I have Passport installed on my Laravel App, but if I'm understanding things correctly I don't want to use the basic Access Token issuing workflow, as that would require the people browsing to Alice's website to authenticate using the Alices's credentials. For the same reason, I don't think I want an Implicit Grant Token.
Using a Password Grant Token would require storing Alice's password for the Laravel app on her website. Is it ok to store passwords like this in a WordPress database? It makes me nervous...
The other option available through Passport is to have Alice create a Personal Access Token and store that in her website backend as the token to use to authenticate. But the Laravel documentation seems to imply that Personal Access Tokens are meant for testing and development purposes, which makes me wary of going this route for a production plugin. Plus, doesn't using a PAT make it possible to do the thing I DON'T want above, since the PAT is simply passed in the request header? Or is that problem mitigated by the fact that the API interaction would be done over SSL?
Do I even need to go through Passport to achieve what I want here? Is there a better way?
I've been reading myself in circles trying to understand what the best practice for this kind of setup is. I'm sorry if this question isn't focused enough, but if anyone has any good advice, or can clarify things for me I would much appreciate it!

Related

Next.js restrict the api to my next.js application and my mobile app

Let me clarify my use case:
I have a next.js application which is a plattform for listing real estate objects. I have several api routes which im using inside my next.js app. for example:
/api/createpost ->
Takes informations from my form on my next.js app and creates a database entry to perform a new post
/api/getposts ->
fetching all the real estate posts from my database and displays it
/api/login ->
logs in a user by checking the credentials in the database and sends a jwt
/api/register ->
registers a user by taking the credentials from a form from my next.js app, registering a user and creating an entry in my database
Now in order to secure my apis I want to make sure to check if there is a valid user session if anybody is calling one of the apis (except the register/login api) to get the expected result. Im doing this by calling the /api/login route and getting a valid user session. Until here everything just works fine. Apis like the /api/createpost can only be called if we have a valid user session.
Now I want to create a mobile app and I want to use my api routes from above to provide full functionality in my mobile app too. It should work the same, if i want to call the /api/createpost on my mobileapp for example, i need a valid user session.
But I want to restrict my api by asking for a key in my database which is pointing to my app and saying okay if you call the /api/createpost api, first of all i need to verify that its the mobile app asking. The mobile app will provide the key in the request then.
I didnt try this yet, but it should work i think. Now the big mess: If we call the /api/createpost and the api wants a valid token to check in the database, which will work for the mobile app, because we are giving it a valid token to check in the database, how can we provide a token if we are calling the api from inside our next.js application? Since I have to do the api call clientside, there is no way for me to provide a secret key or something to validate that the call is coming from my next.js application.
If your application is private
(to be used only by you or a few select people)
You can send a private API key over SSL with each request from your application to the server and verify it. Or you can limit your API to only accept requests from certain IPs.
If your application is public
Unfortunately there's no way to determine where the request is coming from, since anything your app can send, an attacker can send it manually.
Think about it, if your app is trying to make a request to your API, any user can intercept this request before its sent out of his/her machine, and send the exact same request from a different app on the same machine.
You might say, well I can encrypt the requests and responses so that they are of no use to the attacker. But such an encryption will require either a key that's already agreed upon, or some way to provide a new key at the beginning of each session.
If the key is already agreed upon, the app must contain it, as you've already guessed in the question, the attacker can retrieve this key no matter how well you try to hide it.
If the encryption key is a new key provided at the beginning of each session, that's almost how SSL works, your browser handles this transaction. Your server sends a public key to your browser to encrypt the requests which the server can then decrypt with a private key. In this case you've circled back to the same problem, how can you verify to whom you give out an encryption key? What would stop an attacker from requesting the encryption key?
There has to be some way you'd be able to design apps that don't require this restriction. I think the question you should be asking isn't how to restrict your api to a certain app, but how to design apps that don't require this restriction.
We might be able to help you out if you could tell us why you need this restriction.
Update
There is actually a way to verify that requests are coming from your app, but not with an api key.
For Webapps
You can use Google's reCAPTCHA to verify a user on your /register and '/login` routes, and provide an access token or start a valid user session on successful captcha response. With reCAPTCHA v3, you could even verify every user action without interrupting the user. This eliminates both the problems I mentioned in my answer above -
You don't have to store an api key into the app/web app.
The request can't be spoofed as it requires human user interaction within your app. The captcha verification success will arrive to your API from Google's reCAPTCHA server, not from your client app. This communication will be authenticated with a pre-mediated private API key shared by Google to you, which works in the same way as to how you authenticate your external domains.
For Android apps
A similar way to achieve the same thing would be via Android SafetyNet Attestation API. This checks the runtime environment and signs the response with a dynamically generated nonce that your app provides the SafetyNet API.
Please read its docs carefully to understand how you could create potential security loopholes and how to avoid them while using this API.
For iOS apps
DeviceCheck works in a similar way, except the device validity is provided to you by Apple server.
Important edit: "secured" is not the right word here! You cannot tell that a request comes from your app just because the domain is yours. The domain name is not a safe information, as it can be altered easily. See #Mythos comments below.
Initial answer:
Web applications access is secured not based on an API key, but based on a whitelist of domains. That's how we achieve security, because only you have access to the domain where you host your own application: so the request has to be coming from an app you own.
If you try some 3rd party services that provides API for web apps, that's often how they'll work: they will let you configure a set of whitelisted domains that can access your data.
If they provide you an API key, this API key is always meant to be used by a server, not a client-only app.
So if I understand you question correctly, you would do like this for each request:
Check the domain. If it's in the whitelist, perfect, you can keep going. This is meant for web apps (look for "CORS").
If not, check for a valid API token in the headers. This is meant for any app that can store this API token securely (another server for instance, or a mobile app in your scenario though I don't know mobile enough to tell how you store such a key)

Use OAuth2 or JWT for mobile application with Wordpress backend (REST API)

So.. I've read countless articles, but still can't wrap my mind on which to use; if a simple JSON Web Token is enough..
I have a Wordpress website and a mobile application of said website.
I can login in my website using email and password and I can also login on my mobile application using email and password.
The mobile application communicates with the website through the Wordpress REST API. It (the mobile app) sends the user email and password to the API, and the API returns a JWT if both are valid.
Then, I simply store the JWT in the user's device.
My main doubts are:
For a mobile app with not much sensitive user data, is that acceptable/safe enough?
For a mobile app with sensitive user data, is that acceptable/safe enough?
Or should I use OAuth2 in both cases (which is harder to implement and will take time, but it's safer (I think..))?
Thank you and apologies if duplicated.
This is more of a security compliance decision you might have to take.
As a first thing, you should think like a product owner or ask a product owner about which one to use by explaining to them, what are the advantages of OAuth 2.0 over simple JWT.
You might have to consider the following things,
what is the size of the userbase?
how sensitive is the data you are going to store?
What is the user experience you wanted to give to your users?
Also, JWT doesn't mean it is not safe enough.
One more extra thing you could do to make it more secure is adding a expiry time for your JWT with a refresh token mechanism that way even if JWT is exposed it ll be expired later sometime.
JWT is a secure solution and is often used for mobile applications.
If you choose OAuth, you have several options for authentication, because there are several grant types:
Authorization Code grant type, which is the most popular, the advantage of this is that it uses the WordPress login interface
User Credentials grant type, which has a direct trust relationship with the application, which provides the user credentials, this is often used with mobile applications
You have the option of JWT Access Tokens at the OAuth server, which provides even more security for you.
We have created an OAuth 2.0 plugin for WordPress: https://lana.codes/product/lana-passport/
You can try it with the demo, and there is also detailed documentation for it.
I personally use the OAuth plugin to be able to log in to my WordPress websites using the Single Sign On button, which uses my primary WordPress website for authentication. OAuth is more commonly used for Single Sign On solutions.

Allow application access to Azure AD protected URL without username/password

Never thought I'd run into an issue of having too much documentation! I need help with picking the right information so I can read it, understand it, and follow it.
My scenario:
I have an ASP .NET Web Application that is hosted on mywebapp.azurewebsites.net
The web app has a full REST API at mywebapp.azurewebsites.net/api/v1/dostuff/1
You can go to the site and perform all the CRUD stuff. You can also use desktop application to do the same.
I went ahead and enabled Azure AD authentication in Azure Portal. Now in order to do anything on the website, users need to sign in. It brings up the usual Microsoft Login popup and then upon successful authentication redirects back to the site.
But when it comes to the desktop app, I want the users to be able to use it without signing in. Somehow my desktop application needs to be able to make calls to the API/website and be authenticated!
At this point I am lost if there is something I need to do in manifest file, or in the web app, or elsewhere?
Most I was able to do is get an access token using client credentials/client secret.
I just need to know if what I am trying to achieve possible and which document explains the approach of doing so.
Well the fundamental problem you have is that a desktop app (like any public client) has no way of authenticating itself to AAD in a secure way.
You cannot use a client secret.
It is very easy to grab the secret from the executable, and that is basically your app's password.
You would have to make the API accept calls without authentication pretty much.
If authentication is required for access to the API,
then a user must authenticate in the app.

Is it possible to use an external Identity Provider in a Web API with ASP.NET 5?

Reading this question, #Pinpoint's answer and the further discussion on comments, I'm well aware that natively we can't add an identity provider to our apps developed with ASP.NET 5. One possible replacement for the legacy OAuthAuthorizationServerMiddleware is then provided by the AspNet.Security.OpenIdConnect.Server as I've found in many places.
Now, there is one point that I'm still unsure about all this because I'm really not an expert in security, so my knowledge about OAuth is not very deep. My doubt is the following: is it possible to use an external identity provider when using OAuth to protect one RESTful API?
Notice that I'm not talking about adding social login to one website, I'm talking about using one external identity provider in one RESTful API.
My point is, this makes me a little confused yet, because I always thought this should be a concern of my app.
So my question here is: when using OAuth and ASP.NET 5, is it possible to use an external identity provider, other than implementing one? If it is possible, how this works in short? I mean, my app still needs to be able to manage the identities of users, in the sense that it needs to manage claims and so on.
In that case, if it is really possible, how the flow would be? The external identity provider should issue the tokens? But how my app would be able to verify those tokens and manage users identities?
EDIT: One of the reasons I feel unsure about that is that when we use the UseOAuthAuthentication extension method, we set up one callback path which is described as
The request path within the application's base path where the user-agent will be returned. The middleware will process this request when it arrives.
Now, if we are developing a site, then this really does make sense. The person goes there, click a button to login with a provider like Facebook. The user is redirected to Facebook's page and then after he logs in, he is redirected to some page of the site.
On the other hand, with a RESTful API this is meaningless. There is no notion of being redirected.
This makes it seems that the usage of external providers is only for sites and not for RESTful API's. This is the main point of my question.
My doubt is the following: is it possible to use an external identity provider when using OAuth to protect one RESTful API?
Yes, it's definitely possible. This is exactly what you do when you use Azure Active Directory to protect your API endpoints:
app.UseOAuthBearerAuthentication(options => {
options.AutomaticAuthenticate = true;
options.Authority = "https://login.windows.net/tushartest.onmicrosoft.com";
options.Audience = "https://TusharTest.onmicrosoft.com/TodoListService-ManualJwt";
});
The next legitimate question is: if you can use the tokens issued by AAD to protect your API, why couldn't you do the same thing with Facebook or Google tokens?
Unlike Facebook or Google, AAD issues completely standardized tokens named JWT tokens that the OAuth2 bearer middleware can "read" and "verify" to determine whether the token is still valid and was really issued for your API (i.e if the audience attached with the token corresponds to your API. You can control this value using the resource parameter when making your authorization request).
You can't do something similar with FB or Google tokens, since they are totally opaque. Actually, it's not really surprising since these tokens have only one objective: allowing you to query FB or Google APIs, not your own ones (these social providers don't allow to set the audience of the access token).
Since you can't read the token yourself, the only option is to ask FB or Google whether it is still valid to make sure your API doesn't accept invalid tokens. That's something you can (easily) do with Facebook as they offer a "token inspection endpoint" you can query for that: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow (see the Inspecting access tokens chapter). This way, you can ensure the token is not expired and determine the user corresponding to the token.
Sadly, this approach has two downsides:
You have to make an extra HTTP call to the Facebook endpoint to validate the access token, which implies caching received tokens to avoid flooding Facebook with too many requests.
As the access token is not issued for your own API, you MUST absolutely ensure that the access token was issued to a client application you fully trust, or it will allow any third party developer to use his own FB/Google tokens with your API without having to request user's consent. This is - obviously - a major security concern.
You can find more information in the last part of this SO answer (it's for Katana and about Dropbox, but you should get the idea): OWIN/OAuth2 3rd party login: Authentication from Client App, Authorization from Web API
So my question here is: when using OAuth and ASP.NET 5, is it possible to use an external identity provider, other than implementing one? If it is possible, how this works in short? I mean, my app still needs to be able to manage the identities of users, in the sense that it needs to manage claims and so on.
In that case, if it is really possible, how the flow would be? The external identity provider should issue the tokens? But how my app would be able to verify those tokens and manage users identities?
To work around the limitations mentioned in the previous part, the best option is - as you've already figured out - to create your own authorization/authentication server. This way, your API doesn't (directly) accept FB or Google tokens but the tokens issued by your own server, that can possibly redirect your users to FB or Google for authentication.
This is exactly what this sample does: https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/vNext/samples/Mvc
The user is invited by the client application (Mvc.Client) to authenticate with your authorization server (Mvc.Server) so he can get an access token to later query the API (also in Mvc.Server). For that, the user is redirected to your authorization server, which itself offers you to authenticate with Google or Twitter.
When this external authentication step is done, the user is redirected back to your authorization server (Mvc.Server), where he's asked to give his consent for the client app (Mvc.Client) to access his personal data.
When the consent is given, the user is redirected back to the client application with the access token you can use to query the API endpoint.

Is this the correct way of using REST API + OAuth on top of the normal web page?

First of all, for the lack of words, I used "normal web page" on the title. Please let me explain that:
Recently, I have seen many websites such as shopify.com making the most out of the modern browsers support for html5 push-state and Ajax. Instead of submitting forms, requesting new pages I see them doing all that via their REST APIs. It seems to me like a very neat way to do things because it's faster (less page reload), and also allow greatly allows us to re-use the API code.
In these scenarios, the users access the service via the websites as they would normally do, however their interaction with the resources are powered by the REST APIs.
As I dive more into the documents, it seems like these API requests should be stateless yet should always have a mechanism to authorize/authenticate each request so I looked into OAuth2 for that purpose (Since I will need OAuth2 anyhow, to grant accesses to 3rd parties). Now, since in this particular circumstance the user's browser will act as the client to request the resources via REST, I want to know what is the recommended flow to do it.
Right now I plan to implement it as followed: (I'm using Symfony 2 with FOSRestBundle and FOSAuthServerBundle)
User should login via the web form as normal (Since we need to authenticate/authorize both for the normal web page as well as for the API Requests)
When the user logged in, immediately check if an OAuth client is already created for this user? If not then create it with GRANT_TYPE_IMPLICIT. If the client is already there, just retrieve it.
Proceed to normal OAuth authorize for Rest requests?
Edit 1:
Further research makes me think that I should not send back the refresh token to the JS app as this would be too dangerous if the browser is compromised. Perhaps I could store the refresh token for the user somewhere in the server backend once he/she is logged in, then can reserve a special link for the JS app to request for new access token when old one expires? This seems a bit messy to me tho.

Resources