#Install Symfony and the bundles
Create New Symfony Project
symfony new {project_name} lts
Require Bundles
composer require jms/serializer-bundle
composer require friendsofsymfony/user-bundle
composer require friendsofsymfony/oauth-server-bundle
composer require nelmio/api-doc-bundle
##Add Bundles to AppKernel.php to enable the downloaded bundles
// app/AppKernel.php
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
// ...
new FOS\UserBundle\FOSUserBundle(),
new FOS\OAuthServerBundle\FOSOAuthServerBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
//..
);
// ...
}
}
#Configuration ##Edit config.yml file app/config/config.yml
#...
nelmio_api_doc: ~
fos_user:
db_driver: orm # other valid values are 'mongodb', 'couchdb' and 'propel'
firewall_name: main
user_class: AppBundle\Entity\User
fos_oauth_server:
db_driver: orm
client_class: AppBundle\Entity\Client
access_token_class: AppBundle\Entity\AccessToken
refresh_token_class: AppBundle\Entity\RefreshToken
auth_code_class: AppBundle\Entity\AuthCode
service:
user_provider: fos_user.user_manager
options:
supported_scopes: user
# Changing tokens and authcode lifetime
access_token_lifetime: 86400 # 1 day
refresh_token_lifetime: 1209600 # 14 days
#auth_code_lifetime: 30
#Security
# To get started with security, check out the documentation:
# http://symfony.com/doc/current/book/security.html
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username
firewalls:
# disables authentication for assets and the profiler, adapt it according to your needs
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
oauth_token:
pattern: ^/oauth/v2/token
security: false
api_doc:
pattern: ^/api/doc
security: false
api:
pattern: ^/api
fos_oauth: true
stateless: true
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_token_generator: security.csrf.token_manager
logout: true
anonymous: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, role: IS_AUTHENTICATED_FULLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
# - { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
#Routing
# app/config/routing.yml
NelmioApiDocBundle:
resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
prefix: /api/doc
app:
resource: "@AppBundle/Controller/"
type: annotation
api:
resource: "@AppBundle/Controller/UsersController.php"
type: annotation
prefix: "/api"
user:
resource: "@FOSUserBundle/Resources/config/routing/security.xml"
fos_oauth_server_token:
resource: "@FOSOAuthServerBundle/Resources/config/routing/token.xml"
fos_oauth_server_authorize:
resource: "@FOSOAuthServerBundle/Resources/config/routing/authorize.xml"
#Creating Models ##Create User Model
<?php
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
##Create Model Class for OAuth
<?php
// src/AppBundle/Entity/Client.php
namespace AppBundle\Entity;
use FOS\OAuthServerBundle\Entity\Client as BaseClient;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class Client extends BaseClient
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
}
}
<?php
// src/AppBundle/Entity/AccessToken.php
namespace AppBundle\Entity;
use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class AccessToken extends BaseAccessToken
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Client")
* @ORM\JoinColumn(nullable=false)
*/
protected $client;
/**
* @ORM\ManyToOne(targetEntity="User")
*/
protected $user;
}
<?php
// src/AppBundle/Entity/RefreshToken.php
namespace AppBundle\Entity;
use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class RefreshToken extends BaseRefreshToken
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Client")
* @ORM\JoinColumn(nullable=false)
*/
protected $client;
/**
* @ORM\ManyToOne(targetEntity="User")
*/
protected $user;
}
<?php
// src/AppBundle/Entity/AuthCode.php
namespace AppBundle\Entity;
use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
*/
class AuthCode extends BaseAuthCode
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Client")
* @ORM\JoinColumn(nullable=false)
*/
protected $client;
/**
* @ORM\ManyToOne(targetEntity="User")
*/
protected $user;
}
You can now update your database schema :
php app/console doctrine:schema:update --force
#Creating Sample Controller We already have the default controller from fresh installation #UserController
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\User;
use AppBundle\Form\UserType;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class UsersController extends Controller
{
/**
* Response with all users registered on the database
*
* @ApiDoc(
* section="User",
* resource=true,
* description="Get all users",
* statusCodes={
* 200="Returned when successful"
* },
* tags={
* "stable" = "#4A7023",
* "need validations" = "#ff0000"
* }
* )
* @Route("users")
* @Method("GET")
*/
public function getAction()
{
//security.yml is configured to allow anonymous access to controllers
//checking for authorization in each controller allows more flexibility
//to change this remove anonymous: true in security.yml on firewall
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) { //ROLE_USER ROLE_ADMIN
throw $this->createAccessDeniedException();
}
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository("AppBundle:User");
$users = $repository->findAll();
$data = $this->container->get('jms_serializer')
->serialize($users, 'json');
return new Response($data, 200, array("content-type"=>"application/json"));
}
/**
* Create a new user
*
* @ApiDoc(
* section="User",
* description="Create a new User",
* input="AppBundle\Form\UserType",
* output="AppBundle\Entity\User",
* statusCodes={
* 200="Returned when successful"
* },
* tags={
* "stable" = "#4A7023",
* "need validations" = "#ff0000"
* }
* )
* @Route("users")
* @Method("POST")
*/
public function postAction(Request $request)
{
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->createUser();
$user->setEnabled(true);
$form = $this->createForm(UserType::class, $user);
$form->handleRequest($request);
// $form->setData(json_decode($request->getContent(),true));
$form->submit(json_decode($request->getContent(),true));
if ($form->isValid()) {
$user->setPlainPassword($user->getPassword());
$userManager->updateUser($user);
$data = $this->container->get('jms_serializer')
->serialize($user, 'json');
return new Response($data, 200);
}
$data = $this->container->get('jms_serializer')
->serialize($form->getErrors(true), 'json');
return new Response($data, 400);
}
}
##Create UserType Form
<?php
// src/AppBundle/Form/UserType.php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class UserType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', TextType::class)
->add('email', EmailType::class)
->add('password', PasswordType::class);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User',
'csrf_protection' => false
));
}
}
##Create admin user
$ php app/console fos:user:create
Please choose a username:admin
Please choose an email:admin@example.com
Please choose a password:admin
Created user admin
##Promote User
php app/console fos:user:promote admin --super
#Create Command File
Execute function creates the client if you don't wan't to use console command file you can user this function to create client. For more information visit official docs : Creating A Client
<?php
//src/AppBundle/Command/CreateClientCommand.php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class CreateClientCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('acme:oauth-server:client:create')
->setDescription('Creates a new client')
->addOption(
'redirect-uri',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets redirect uri for client. Use this option multiple times to set multiple redirect URIs.',
null
)
->addOption(
'grant-type',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets allowed grant type for client. Use this option multiple times to set multiple grant types..',
null
)
->setHelp(
<<<EOT
The <info>%command.name%</info>command creates a new client.
<info>php %command.full_name% [--redirect-uri=...] [--grant-type=...] name</info>
EOT
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$clientManager = $this->getContainer()->get('fos_oauth_server.client_manager.default');
$client = $clientManager->createClient();
$client->setRedirectUris($input->getOption('redirect-uri'));
$client->setAllowedGrantTypes($input->getOption('grant-type'));
$clientManager->updateClient($client);
$output->writeln(
sprintf(
'Added a new client with public id <info>%s</info>, secret <info>%s</info>',
$client->getPublicId(),
$client->getSecret()
)
);
}
}
#Create An OAuth Client Only use the grant-type you intend to use.
php app/console acme:oauth-server:client:create --redirect-uri="http://127.0.0.1:8000/" --grant-type="authorization_code" --grant-type="password" --grant-type="refresh_token" --grant-type="token" --grant-type="client_credentials"
#Run app
php app/console server:run
##Get User Access & Refresh Tokens Browse to the following URL while Replacing CLIENTID, CLIENTSECRET, USERNAME, & PASSWORD with your values:
http://127.0.0.1:8000/app_dev.php/oauth/v2/token?client_id=__CLIENTID__&client_secret=__CLIENTSECRET__&grant_type=password&username=USERNAME&password=PASSWORD
##Get New Access & Refresh Tokens with Refresh Token Browse to the following URL while Replacing CLIENTID, CLIENTSECRET, REFRESHTOKEN with your values:
http://127.0.0.1:8000/app_dev.php/oauth/v2/token?client_id=__CLIENTID__&client_secret=__CLIENTSECRET__&grant_type=refresh_token&refresh_token=__REFRESHTOKEN__
##See Authorization Failure:
The following will return a access_denied error:
curl http://127.0.0.1:8000/app_dev.php/users
##See Authorization Success:
The following will return successful set of users (json).
curl -H "Authorization: Bearer ACCESS_TOKEN" -H "Accept: application/json" http://127.0.0.1:8000/app_dev.php/users
##Create user with curl
curl -X POST -H "Authorization: Bearer ACCESS_TOKEN" -H "Content-Type: application/json" -H "Accept: application/json" -d '{"user":{"username": "username", "password": "secretpass", "email": "test@test.com"}}' http://127.0.0.1:8000/app_dev.php/api/users
##Api Docs
http://127.0.0.1:8000/app_dev.php/api/doc