How to implement a REST APIs with Symfony 4 + FOSRestBundle + FOSUserBundle + FOSOauthServerBundle using main Oauth2 code flows
In this gist I will explain you how to create a basic REST APIs system with Symfony 4 and FOSOauthServerBundle using main Oauth2 code flows. The flows that we implement will be:
- Authorization code
- Implicit
- Password credentials
I will separate the gist into two configuration parts. The first part is the common configuration that is equal for all Oauth2 code flows above. In the second part I will explain, for each code flows above, the basic configuration type that you need. So let's coding!
The first step is to download Symfony and the related bundles.
composer create-project symfony/skeleton oauth2-server
cd oauth2-server
composer require friendsofsymfony/rest-bundle
composer require jms/serializer-bundle
composer require nelmio/api-doc-bundle
composer require friendsofsymfony/user-bundle "~2.0@dev"
composer require friendsofsymfony/oauth-server-bundle
Below I will explain for each bundle what they do and how to configure them.
In the config/packages/fos_rest.yaml file insert these configuration options:
fos_rest:
routing_loader:
default_format: html
include_format: true
format_listener:
enabled: true
rules:
- { path: '^/api', priorities: ['json', 'xml'], fallback_format: json, prefer_extension: false }
- { path: '^/', priorities: ['html'], fallback_format: html, prefer_extension: false }
view:
view_response_listener: true
With the rules above our application will serve for the routes starting with /api only resources formatted in json/xml, instead for all remaining routes it will render simple html pages. The configuration option view_response_listener makes it possible to simply return a View instance from action controllers.
Documentation: https://symfony.com/doc/master/bundles/FOSRestBundle/index.html
In the config/packages/jms_serializer.yaml file insert these configuration options:
jms_serializer:
visitors:
xml:
format_output: '%kernel.debug%'
JMSSerializerBundle allows you to serialize your data into a requested output format such as JSON, XML, or YAML.
Documentation: https://jmsyst.com/bundles/JMSSerializerBundle
In the config/packages/nelmio_api_doc.yaml file insert these configuration options:
nelmio_api_doc:
documentation:
info:
title: Oauth Server App
description: This is my oauth2 server app
version: 1.0.0
securityDefinitions:
Bearer:
type: apiKey
description: 'Value: Bearer {access_token}'
name: Authorization
in: header
areas:
path_patterns:
- ^/api(?!/doc$)
In the config/routes.yaml file insert this route option:
NelmioApiDocBundle:
resource: "@NelmioApiDocBundle/Resources/config/routing/swaggerui.xml"
prefix: /api/doc
NelmioApiDocBundle is a Symfony's bundle that allow us to generate documentation for our APIs.
Documentation: https://symfony.com/doc/current/bundles/NelmioApiDocBundle/index.html
In the config/packages/fos_user.yaml file insert these configuration options:
fos_user:
db_driver: orm
user_class: App\Entity\User
firewall_name: main
from_email:
address: john@example.com
sender_name: john@example.com
In the config/routes.yaml file insert this route option:
fos_user:
resource: "@FOSUserBundle/Resources/config/routing/all.xml"
In the config/packages/framework.yaml file insert this line at the end of file:
templating:
engines: twig
Now let's to create our entity User class:
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
/**
* @ORM\Table("users")
* @ORM\Entity(repositoryClass="App\Repository\UserRepository")
*/
class User extends BaseUser
{
/**
* @ORM\Id()
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
protected $id;
public function getId(): ?int
{
return $this->id;
}
}
I do it step by step as you have, but when i try GET localhost:8000/api/users response is:
{"error": "access_denied", "error_description": "OAuth2 authentication required"}
Could you help me?
Note: previous respone was {"access_token":"ZmFkZjQ1NzdjYTY0ZGMwNDYyZDkyNWM1NjU3MmUwZjNiNjIwYTgxYWNmOWZjZDIwZmUyODIwNDFlOWNhZDRmYQ","expires_in":3600,"token_type":"bearer","scope":null,"refresh_token":"Yjk2MmYzMzA1MWU4YTc1YWU2ZTVlMWQyYTI4N2I3NjA5YWE4ZGM4OGMwZDFjYTc1MzJjMDJiZTA2ODE0ZTFiOQ"}