API Project - Part 8 - CORS Requests
NOTE that if we are pressed for time, we could potentially skip this step!
We will run into a big problem when we try to connect our front-end (the Vue app you are building in Adv Wev) to this project. The problem arises because when you run the Vue app, it is launched on a different server than the Apache server that we are using for this project. We'll definitely be talking about this in class, but if you want to simulate the problem right now, then use the Live Server extension in VSCode to run the LoginControllerTests.html page (if you have the extension installed you'll see a button that says Go Live in the lower right corner of VSCode).
When you run the LoginController test page like this, you should see that the URL is something like http://127.0.0.1:5500/tests/LoginControllerTests.html. This is not our Apache server, but rather a server created by VSCode that runs on port 5500. If you try to log in now, you'll see an error in the console log.
The problem arises because the request is coming a different server than the one that hosts our API project, this is known as a Cross Origin Request (CORS). By default, browsers will not allow CORS requests unless the server specifically allows them.
We can configure the server to allow CORS requests by sending certain response headers. I've actually put this code in the config file, but commented out. Look in the config file for a comment that says '// TODO: uncomment this code when we start dealing with CORS requests'. If you uncomment this code, then you should be able to log in. The response headers that are getting set declare that the server will allow CORS requests. Again, we can talk more about this in class, but the main purpose for this it to help minimize malicious behavior from browsers (security!). Dealing with CORS issues can make you pull your hair out. And as you'll see in a minute, we now have another problem to deal with.
I learned (the hard way), that browsers will not send cookies when they make CORS requests. Without the PHPSESSID cookie, our server cannot use session variables.
There are various ways that we can attempt to deal with this (and I tried many of them). But I settled on creating a custom header that will be used to send the session id back and forth between the browser and the server. I called the custom header x-id. If you create your own headers, it's common to have them begin with x-id.
If you look at the LoginController class, you should see a comment that says '// TODO: send the session id in the x-id header'. Replace that comment with this code:
//send the session id in the x-id header
$sess_id = session_id();
header("x-id: $sess_id");
The PHP function session_id() will return the ID of the session (the session ID is generated by PHP when we call session_start() which we have in our config file). Then we use the header() to create our custom header (x-id) and set it to the ID of the session.
Now go ahead and login (by using the Live Server plugin to launch LoginControllerTests.html) and observe in the Network tab that the x-id header was included in the response.
So now, when you login successfully, the server is sending the session ID in our custom header.
The next problem we have to solve is how to make the browser send the session ID back to the server with every request made after logging in. I've already added that code to the LoginControllerTests.html file. Axios has something called interceptors that allow you to 'intercept' each request made and alter it before sending it. We can talk about this code in class.
Now we have one more problem to solve: when a request comes in we need to look for the x-id header and use it to restore the session on the server. I have already added code to solve this problem too. It's in the config file under a comment that says '// SESSION HANDLING (and authentication)...' Look at this code (I have included lots of comments) and let me know if you want to discuss it.
Wow! That was complicated. There are other ways to solve this problem, but I found all of them to be even more complicated than our solution.
For those of you who will be connecting your Vue app to this API, we'll have to make sure that the Vue app is sending the x-id header in each request. We'll create an Axios intercepter just like we did in the LoginControllerTests.html file.
For more info on CORS: