Chapters
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3, <8.0
Subscribe to download the code!Compatible PHP versions: ^7.1.3, <8.0
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Hello API Security + API Docs on Production?
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Friends! Welcome to part 2 of our API Platform series - the one where we're talking all about ice cream, um, security. We're talking about security, not uh, ice cream. Hmm. Um, it's going to be almost as awesome as ice cream though, because the topic of security - especially API security - is fascinating! We've got API tokens, session-based authentication, CSRF attacks, dragon attacks and the challenge of securing our API Platform application down to the smallest details, like letting different users see different records or even returning or accepting different fields based on the user. Yep, we're going to take this wonderful base that API platform has given us and shape it to act exactly like we need from a security perspective.
The great thing about API platform is that it's basically just... Symfony security. They didn't reinvent the wheel at all. If you haven't gone through our Symfony Security tutorial yet, now would be a good time: you'll feel much more dangerous after.
Anyways, let's dive into this! To put the lock down on your API Platform security skills, download the course code from this page and code along with me. After you unzip the file, you'll find a start/
directory that has the same code you see here. Open up the README.md
file for all the details on getting the app set up. If you coded through part 1 of this tutorial, um, you rock, but also, I recommend downloading the new course code because I upgraded a few dependencies and added a frontend to the site.
Anyways, one of the last steps in the README will be to open a terminal, move into the project and run:
yarn encore dev --watch
to run Encore and build some JavaScript that'll power a small frontend. To make things more realistic, we'll do a little bit of work in JavaScript to see how it interacts with our API from an authentication standpoint. Next, open another terminal and start the Symfony local web server:
symfony serve
Once that starts, you should be able to fly back over to your browser and open up https://localhost:8000
to see... Cheese Whiz! The peer-to-peer cheese-selling app we build in part 1. Actually, this is our brand new Vue.js-powered frontend. OOOOooOOO. Go to /api
. Ah yes, this is the API we built: we have a CheeseListing
resource, a User
resource, they're related to each other and we've customized a ton of stuff. In a bit, we'll start making this frontend talk to the API.
Hiding the Docs on Production?
But before we get there, head back to /api
to see our beautiful, interactive, Swagger documentation. I know some of you are probably thinking: I know, this is great for development, but how can I disable this for production?
The answer is... you shouldn't!
Well first, let me show you how you can disable this on production and then I'll try to convince you to keep it.
Open up config/packages/api_platform.yaml
. API Platform is highly configurable. So, reminder time: if you go to an open terminal, you can see all your current configuration - including any default values - by running:
php bin/console debug:config api_platform
You can also run:
php bin/console config:dump api_platform
to see an example tree of all the possible keys with some explanations. One of the options is called enable_docs
. Copy this. The goal is to disable the docs only in production, but let's start by disabling them everywhere to see how it works.
Set enable_docs
to false.
api_platform: | |
Show Lines
|
// ... lines 2 - 17 |
enable_docs: false |
Ok, go back and refresh /api
. Um... there is absolutely no change! That's due to a small dev-only bug with a few of these options: when we change those options, they're not causing the routing cache to rebuild automatically. No big problem, clear that cache manually with:
php bin/console cache:clear
Fly back over, refresh and... yep! The documentation is gone. Oh... but instead of a 404, it's a 500 error!
It turns out that going to /api
to see the docs was just a convenience. The documentation was really stored at /api/docs
and this is now a 404. You could also go to /api/docs.json
or /api/docs.jsonld
before, but now it's all gone.
One of the unfortunate things about removing the documentation is that it wasn't just rendered as HTML. In part 1 of this series, we talked about JSON-LD and Hydra, and how API Platform generates machine-readable documentation to explain your API. If I go to /api/cheeses.jsonld
, this advertises that we can go to /api/contexts/cheeses
to get more "context", more machine-readable "meaning". Whelp, that doesn't work anymore. The point is: if you disable documentation, realize that you're also disabling the machine-friendly documentation.
And if you want to fix the 500 on /api
, you also need to disable the "entrypoint". Right now, if we go to /api/index.jsonld
, we get a, sort of, "homepage" for our API, which tells us what URLs we could go to next to discover more. When we go to /api
, that's the HTML entrypoint and that's... totally broken. To disable that page set enable_entrypoint
to false. Rebuild the cache:
api_platform: | |
Show Lines
|
// ... lines 2 - 18 |
enable_entrypoint: false |
php bin/console cache:clear
then go refresh. Now we get a 404 on this and /api
.
So to fully disable your docs without a 500 error, you need both of these keys. To make this only happen in production, copy them, delete them, and, in the config/packages/prod
directory, create a new api_platform.yaml
file. Inside, start with api_platform:
then paste.
api_platform: | |
enable_docs: false | |
enable_entrypoint: false |
If we changed to the prod
environment and rebuilt the cache, we'd be done!
But instead... I'm going to comment this out... for two reasons. First, I like the documentation, I like the machine-readable documentation and I like the "entrypoint": the documentation homepage. And second, more importantly, if you want to hide your documentation so that nobody will use your API, that's a bad plan. That's security through obscurity. If your API lives out on the web, you need to assume people will find it and you need to properly secure it. Hey! That's the topic of this tutorial!
Rebuild the cache one more time.
At the end of the day, if you're ok keeping the machine-readable docs and the entrypoint stuff, but you really don't want to expose the pretty HTML docs, you could always create an event subscriber on the kernel.request
event - now called the RequestEvent
in Symfony 4.3 - and, if the URL is /api
and the request format is HTML, return a 404.
Tip
You can see an example here: https://bit.ly/2YmR6Uh
Ok, let's get into the real action: let's start figuring out how we're going to let users of our API log in.
47 Comments
Thanks, exactly what I needed.
Hey hanen
Can you double check that a package.json
file exists at the root of your project?
Also, could you try running yarn watch
instead?
Cheers!
hi Diego
webpack is watching my files, In my public directory create 3 files: runtime.js , app.css& app.js
Oh, great, so Webpack is working now as expected, right?
I had always problems to start chapter 2 of api platform tutorial because of issues during instalation of this project.
Now i using a 8.1 version of php on Ubuntu and after read all comments i think the simplest solution is:
1) Choose the php 8.0 version by this command:
sudo update-alternatives --config php
or install 8.0 if you don't have it (is many tutorials on web how to install 8.0) and then choose that version by:
sudo update-alternatives --config php
(Below is comment by Weaverryan author of this tutorial)
2) In composer.json, find all "4.3." and replace with "4.4.". Symfony 4.4 has proper PHP 8 support, but 4.3 does not.
3) Run composer up --ignore-platform-reqs
And thats all, you can go now through the all commands from readme:
- php bin/console doctrine:database:create
- php bin/console doctrine:migrations:migrate
- yarn install
- yarn encore dev --watch
- symfony serve -d
For me that's work.
Thanks for posting your solution kkedzierski! We're going to update this tutorial for API Platform 3 soon, but in the mean time, this is very helpful!
How to make code you created in previous course part-1 work with this code:(even with php 8)
-->from start directory add following:-
add asset folder
add bootstrap.php
add controller
add frontend template folder
add package.json (if not present)
add webpackencore.yaml(inside confing/packages)
run composer install
run composer update
yarn install
yarn encore dev-server
It worked for me in php 8 !
Thanks for posting Sakshi G. - awesome!
Yeah, It worked for me too! Thank you Sakshi G. sharing this! :)
I am using PHP 8.1 and can't run `composer install`... any ideas? I am using Windows 10 and not interested in using any *AMP programs.
Hey Budmanz,
Yeah, that's a known issue in this tutorial, the course code support only PHP version ^7.1.3 that does not allow to PHP 8, we show this as in a JS tooltip when you try to download the course code. Possible solutions would be to tweak that PHP version in composer.json, but then you may need to upgrade dependencies to fetch new ones that will support PHP 8. But it will mean that your code may be slightly different from one we're showing in this tutorial. I'd recommend you to use a legacy PHP 7.4 to follow this course if you can.
Cheers!
Thanks, Victor! I will try your suggestion. I have used SF since SF2 but never encountered a project like the one I am doing now where I need to consume api's with authentication (JWT). So, I think this is the wrong tutorial for my purpose; do you have one that you can recommend for me?
Thanks,
Bud
Hey Bud,
Oh, nice, since Sf 2! I started using Symfony since that version as well :)
If you're looking for JWT course, you probably need to look at this one: https://symfonycasts.com/sc... - but this is the 4th episode, you may want to watch 3 previous I suppose, there's the link to the course group: https://symfonycasts.com/tr... - well, those tutorials are based on the older version of Symfony but JWT concepts we're teaching in that 4th course are still valid for today.
Well, JWT is redundant in case when only YOUR app is sending API requests to the server, because in this case you can simplify the system dramatically asking users to log in into their account first and then all the API requests will be authenticated, we're talking about the difference in these videos IIRC: https://symfonycasts.com/sc... and https://symfonycasts.com/sc... and show the simpler way instead of JWT. But if you really need JWT in your project - then look at those course I mentioned above probably, we haven't talked about JWT in other courses unfortunately.
Oh, or take a look at this video too: https://symfonycasts.com/sc... - might be useful for you I suppose.
I hope that helps!
Cheers!
Hey pasquale_pellicani,
The first part of this tutorial is here: https://symfonycasts.com/screencast/api-platform2 . You can easily see the related courses on the track page: https://symfonycasts.com/tracks/rest#api-platform-2
Cheers!
After set up of the project using php 7.4 and open up browser i am getting
(1/1) ParseError
syntax error, unexpected token "match"
in Negotiator.php line 41
at DebugClassLoader->loadClass()
Hi Mehul-J,
I've had the same problem. Probably you've managed your problem till now, but if someone will have same issue, maybe my solution will help. In my case increasing version of symfony to 4.4, api platform core to version 2.6 and adding "willdurand/negotiation": "3.0.0"
in require
section in composer.json
helped. You need to be aware that also on require-dev
section the Symfony packages versions also need to be increased. After this, you only need to run composer update
instead of composer install
.
Kind regards,
Jakub
Hey @Mehul-J!
Hmm. The match
function was introduced in php 8. So, somehow it seems like you got a version of the project that's only compatible with php 8, but while using PHP 7.4. Did you download the course code from this page (that should actually only work with php 7.*)? Or did you setup the project a different way?
Cheers!
I followed the instructions of the read me and got this error?
[Semantical Error] The annotation "@ApiResource" in class App\Entity\CheeseListing was never imported. Did you maybe forget to add a "use" statement for this annotation?
I deleted the ApiResource() annotation from the cheeselisting entity so that I could isolate the issue and also view the front end but I got another error:
[Semantical Error] The annotation "@ORM\Entity" in class App\Entity\CheeseListing was never imported. Did you maybe forget to add a "use" statement for this annotation?
Any idea on how to proceed? Kind regards
Hey mercelot
That's unexpected :)
Makes me think you didn't run composer install
or perhaps something odd happening when installing your vendors. Could you try the following
- Remove completely the
vendor
directory - Run
composer install
- Try again, if the problem persists. Delete Symfony's cache manually
rm -r var/cache/*
and try again
If nothing worked, let me know. Cheers!
Hello, I have tried the following procedure without success.
composer.json : "php": "^7.1.3|^8.0"
composer install --ignore-platform-reqs
this gives me the following error :
[Semantical Error] The annotation "@ApiResource" in class App\Entity\User was never imported. Did you maybe forget to add a "use" statement for this annotation?
Thanks
Double check the use statemens on your User class, you may be missing one. The tutorial starts with these ones:
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
Hello,
Thank you for your reply, I have checked all the imports, no one is missing but the error persists.
Thanks
Hey Guerber C.!
Sorry about the troubles - that's not the experience we want! I just tried it locally. The problem is that the code, unfortunately, only works with PHP 7: some of the dependencies are too old to support PHP 8, and so it gives you this odd error. However, you CAN get it working with PHP 8 without too much trouble. Here's what I did:
A) In composer.json, find all "4.3." and replace with "4.4.". Symfony 4.4 has proper PHP 8 support, but 4.3 does not.
B) Run composer up --ignore-platform-reqs
.
That should get things working. Or, at least for me, it was able to install all the dependencies without any trouble :). It's possible you still may hit some PHP 8 issues if some dependencies are still too old, and there may be minor differences between the tutorial and what you see in your code... but those should be minor.
I hope this helps! The tutorial is still really solid - but as newer PHP versions are released, sometimes these tutorials have trouble (and we intentionally don't update the download code because we want it to match the video exactly).
Cheers!
Hi. Tried to make the code work with PHP 8.0 and Symfony 4.4. But after updating the composer.json and trying to run composer update I run into
Script cache:clear returned with error code 255
!! PHP Fatal error:
Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException:
Attempted to load class "DoctrineCacheBundle" from namespace
"Doctrine\Bundle\DoctrineCacheBundle".
Hey Daniel,
DoctrineCacheBundle is abandoned as you can see here: https://github.com/doctrine... - you should avoid using it. If it was just a dependency that you do not use - just remove it. If you use it - probably consider replacing it in favor of Symfony Cache component. Most probably that bundle isn't a required dependency now, so you can just remove that line from the bundles.php list and it should work. But if you need that bundle, make sure you have "doctrine/doctrine-cache-bundle" installed in your project, and make sure that "Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle" class exist there.
I hope this helps!
Cheers!
I've got an error unable to fetch the response from the backend: unexpected EOF - not sure what the offending file is
Hey Mike L. !
Hmmm. Yea... I've seen that error, but it's rare. I assume you're using the symfony web server? If so, try running symfony server:log
and then try again. Assuming you get this same error, go back and check your terminal. Hopefully you will see an error in the logs on the screen that will help :).
Cheers!
To save others time. The package is realy outdated now. In order to make this run in windows 10 you need to install Phython 2 and set the systemvariable, not the last Version 3 - they are not compatible. then you need to downgrade yarn to version 1.22: "yarn set version 1.22" and you need .net Famework 2. then you could use the commands from the read me. if you still get "encore" errors do: "composer require symfony/webpack-encore-bundle" like hanene suggests.
but maybe its time to update the course. ;)
Hey Jens W.!
Ah, you're absolutely right! The problem is a not-too-important (but still-totally-breaking-the-build) dependency of node-sass
. This dependency is a pain, as you constantly need new versions of it for new operating systems so that it can build. And... it actually builds an executable, which requires other dependencies (which is why you hit the python thing). Fortunately, the JS world has fixed this and you can now use sass
(a pure JS binary for sass) instead of node-sass
.
I've just updated the course download code to include sass instead - you should be able to easily build without any issues now :). But if you have any other issues, please let us know. And thanks for reporting this!
Cheers!
Hey Ryan, works great now! :)
btw. i saw you on symfony world. i thought: man you know this voice. gosh .. thats the guy from symfocast. made my day!
Hey Jens W.!
Sweet! Happy to hear it - i've updated a bunch other courses to fix this problem too :).
> btw. i saw you on symfony world. i thought: man you know this voice. gosh .. thats the guy from symfocast. made my day!
Ha! I hope you enjoyed it - it was fun to at least - "kind of" - get together with people ;).
Cheers!
I installed Yarn as described here https://yarnpkg.com/getting-started/install#per-project-install – it installed version 2.0.0-rc.31 for this project. After that yarn install
fails:
<br />➜ start git:(master) ✗ yarn install<br />➤ YN0000: ┌ Resolution step<br />➤ YN0032: │ nan@npm:2.14.0: Implicit dependencies on node-gyp are discouraged<br />➤ YN0032: │ evp_bytestokey@npm:1.0.3: Implicit dependencies on node-gyp are discouraged<br />➤ YN0002: │ root-workspace-0b6124@workspace:. doesn't provide jquery@1.9.1 - 3 requested by bootstrap@npm:4.3.1<br />➤ YN0002: │ root-workspace-0b6124@workspace:. doesn't provide popper.js@^1.14.7 requested by bootstrap@npm:4.3.1<br />➤ YN0002: │ root-workspace-0b6124@workspace:. doesn't provide webpack@^3.0.0 || ^4.0.0 requested by sass-loader@npm:7.1.0<br />➤ YN0002: │ root-workspace-0b6124@workspace:. doesn't provide css-loader@* requested by vue-loader@npm:15.7.1<br />➤ YN0002: │ root-workspace-0b6124@workspace:. doesn't provide webpack@^4.1.0 || ^5.0.0-0 requested by vue-loader@npm:15.7.1<br />➤ YN0000: └ Completed in 10.41s<br />➤ YN0000: ┌ Fetch step<br />➤ YN0000: └ Completed in 22.52s<br />➤ YN0000: ┌ Link step<br />➤ YN0007: │ core-js@npm:3.1.4 must be built because it never did before or the last one failed<br />➤ YN0007: │ node-sass@npm:4.12.0 must be built because it never did before or the last one failed<br />➤ YN0007: │ fsevents@patch:fsevents@npm%3A1.2.9#builtin<compat/fsevents>::version=1.2.9&hash=77dfe6 must be built because it never did before or the last one failed<br />➤ YN0007: │ core-js-pure@npm:3.1.4 must be built because it never did before or the last one failed<br />➤ YN0000: └ Completed in 3.54m<br />➤ YN0000: Done with warnings in 4.09m<br />
<b>Using the globally installey version 1.22.4 of Yarn gives me warnings as well – but seems to work:</b><br />➜ start git:(a1a3cfd) yarn install<br />yarn install v1.22.4<br />[1/4] 🔍 Resolving packages...<br />[2/4] 🚚 Fetching packages...<br />warning mini-css-extract-plugin@0.4.2: Invalid bin field for "mini-css-extract-plugin".<br />[3/4] 🔗 Linking dependencies...<br />warning " > bootstrap@4.3.1" has unmet peer dependency "jquery@1.9.1 - 3".<br />warning " > bootstrap@4.3.1" has unmet peer dependency "popper.js@^1.14.7".<br />warning " > sass-loader@7.1.0" has unmet peer dependency "webpack@^3.0.0 || ^4.0.0".<br />warning " > vue-loader@15.7.1" has unmet peer dependency "css-loader@*".<br />warning " > vue-loader@15.7.1" has unmet peer dependency "webpack@^4.1.0 || ^5.0.0-0".<br />[4/4] 🔨 Building fresh packages...<br />✨ Done in 477.86s.<br />
<b>My setup:</b>
MacOS 10.15.4
Node 13.12.0
Npm 6.14.4
hey Roland W.
Sorry getting you confused with this yarn versions. Unfortunately not everything is compatible with Yarn v2. This version of yarn is completely new and there is no backward compatibility with v1. I'll check if we can add a note about it!
Thank you for your feedback.
Cheers!
4:10 I always pipe this output through `bat -l yaml` to get syntax highlighting. https://github.com/sharkdp/bat
Haha, yea - that's awesome!
Hey Tomasz,
Thanks for this tip, it might me useful when working in console :)
Cheers!
Hi. Is there any ability to get those docs as static html?
Hey tmp0000,
Hm, not sure if it's possible to do out of the box... You can do right click somewhere on the docs and save the current page as HTML, but you would need to do this for every HTML page :) Well, you can output the docs to JSON or Yaml format using the specific console command for it:
$ bin/console api:openapi:export
Probably, you can write a little script that will iterate the output data from that command and run curl request to get those pages automatically, but you would also need to think about assets in this case.
I hope this helps!
Cheers!
Hello
I would like to combine Session and JwtBundle
I explain I want to allow a connection via the Session and a second connection for my Api via JwtBundle.
I tested the explanation that is on the course JWT REST video 1 (2 Firewalls) but when I connected A I made an ajax call that returned a 401.
Thanks for your help
Hey @zakaria!
The problem with 2 firewalls is that only 1 firewall can be active for each request. 2 firewalls works great if you want (for example) 1 firewall to be active for all URLs starting with /api
(and maybe you use JWT for this firewall) and another firewall for all the other URLs (and maybe you use a form login for this).
In your case, you want the same URLs (e.g. /api/cheeses
) to allow session-based authentication or JWT. The way to do that is with one firewall, and then just two "keys" under that firewall (e.g. json_login
for the session-based stuff and also whatever "jwt" authentication mechanism you need). The only "catch" is that, on a technical level, if someone uses JWT, your Symfony app will start a session for that and try to return a cookie (any API client will just ignore the cookie, but a session was technically started). That's just due to the fact that a firewall is either completely stateless (no sessions) or completely stateful (always sessions) - so your firewall will always use a session, even if the user is authenticating with JWT.
Let me know if this helps!
Cheers!
I don't know if it is just me, but when I try using the api platform interface to create a user, it doesn't bcrypt the password, any idea why that is?
Hey Eric H.!
That's correct! We haven't handled that yet - we'll do it around chapter 12 :).
Cheers!
Hi when this tutorial will be available ?
Hi Htun htun H.!
We'll start releasing this tutorial next week :)
Cheers!
Awesome !!!! can't wait to try this out :)
"Houston: no signs of life"
Start the conversation!
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.1.3, <8.0",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^2.1", // v2.4.5
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.13.2
"doctrine/doctrine-bundle": "^1.6", // 1.11.2
"doctrine/doctrine-migrations-bundle": "^2.0", // v2.0.0
"doctrine/orm": "^2.4.5", // v2.7.2
"nelmio/cors-bundle": "^1.5", // 1.5.6
"nesbot/carbon": "^2.17", // 2.21.3
"phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
"symfony/asset": "4.3.*", // v4.3.2
"symfony/console": "4.3.*", // v4.3.2
"symfony/dotenv": "4.3.*", // v4.3.2
"symfony/expression-language": "4.3.*", // v4.3.2
"symfony/flex": "^1.1", // v1.21.6
"symfony/framework-bundle": "4.3.*", // v4.3.2
"symfony/http-client": "4.3.*", // v4.3.3
"symfony/monolog-bundle": "^3.4", // v3.4.0
"symfony/security-bundle": "4.3.*", // v4.3.2
"symfony/twig-bundle": "4.3.*", // v4.3.2
"symfony/validator": "4.3.*", // v4.3.2
"symfony/webpack-encore-bundle": "^1.6", // v1.6.2
"symfony/yaml": "4.3.*" // v4.3.2
},
"require-dev": {
"hautelook/alice-bundle": "^2.5", // 2.7.3
"symfony/browser-kit": "4.3.*", // v4.3.3
"symfony/css-selector": "4.3.*", // v4.3.3
"symfony/maker-bundle": "^1.11", // v1.12.0
"symfony/phpunit-bridge": "^4.3", // v4.3.3
"symfony/stopwatch": "4.3.*", // v4.3.2
"symfony/web-profiler-bundle": "4.3.*" // v4.3.2
}
}
Hi everyone... When I execute yarn encore dev --watch command ..I get this error
yarn run v1.15.2
error Couldn't find a package.json file in "C:\\users\\hanen\\sites\\api_platform"
I run these commands for installing Encore on Symfony : composer require symfony/webpack-encore-bundle
yarn install
it works