{"action":"created","comment":{"url":"https://api.github.com/repos/api-platform/docs/pulls/comments/174735313","pull_request_review_id":104143760,"id":174735313,"diff_hunk":"@@ -0,0 +1,340 @@\n+# Adding a OAuth2 authentication using `FOSOAuthServerBundle`\n+\n+> [OAuth](https://oauth.net/2/) is an open standard for authorization, commonly used as a way for Internet users to authorize websites or applications to access their information on other websites but without giving them the passwords.[1] This mechanism is used by companies such as Google, Facebook, Microsoft and Twitter to permit the users to share information about their accounts with third party applications or websites.\n+\n+[Wikipedia](https://en.wikipedia.org/wiki/OAuth)\n+\n+API Platform allows to easily add a OAuth2-based authentication to your API using [FOSOAuthServerBundle](https://github.com/FriendsOfSymfony/FOSOAuthServerBundle).\n+\n+API Platform is fully working with [FOSOAuthServerBundle](https://github.com/FriendsOfSymfony/FOSOAuthServerBundle).\n+\n+This tutorial is based on [Getting Started With FOSOAuthServerBundle](https://github.com/FriendsOfSymfony/FOSOAuthServerBundle/blob/master/Resources/doc/index.md) and [Basic RESTful API with Symfony 2 + FOSRestBundle (JSON format only) + FOSUserBundle + FOSOauthServerBundle](https://gist.github.com/tjamps/11d617a4b318d65ca583)\n+\n+## Install FOSOauthServerBundle\n+\n+Install the bundle with composer:\n+\n+```bash\n+composer require friendsofsymfony/oauth-server-bundle\n+```\n+\n+Enable the bundle in the kernel:\n+\n+```php\n+<?php\n+// app/AppKernel.php\n+\n+public function registerBundles()\n+{\n+    $bundles = array(\n+        // ...\n+        new FOS\\OAuthServerBundle\\FOSOAuthServerBundle(),\n+    );\n+}\n+```\n+\n+## Create oauth2 entites\n+\n+Add all the following classes to your entities and run `php bin/console doctrine:schema:update --force`:\n+\n+`AppBundle/Entity/AccessToken.php`\n+\n+```php\n+<?php\n+\n+namespace AppBundle\\Entity;\n+\n+use FOS\\OAuthServerBundle\\Entity\\AccessToken as BaseAccessToken;\n+use Doctrine\\ORM\\Mapping as ORM;\n+\n+/**\n+ * @ORM\\Entity\n+ */\n+class AccessToken extends BaseAccessToken\n+{\n+    /**\n+     * @ORM\\Id\n+     * @ORM\\Column(type=\"integer\")\n+     * @ORM\\GeneratedValue(strategy=\"AUTO\")\n+     */\n+    protected $id;\n+\n+    /**\n+     * @ORM\\ManyToOne(targetEntity=\"Client\")\n+     * @ORM\\JoinColumn(nullable=false)\n+     */\n+    protected $client;\n+\n+    /**\n+     * @ORM\\ManyToOne(targetEntity=\"AppBundle\\Entity\\User\")\n+     */\n+    protected $user;\n+}\n+```\n+\n+`AppBundle/Entity/AuthCode.php`\n+\n+```php\n+<?php\n+\n+namespace AppBundle\\Entity;\n+\n+use FOS\\OAuthServerBundle\\Entity\\AuthCode as BaseAuthCode;\n+use Doctrine\\ORM\\Mapping as ORM;\n+\n+/**\n+ * @ORM\\Entity\n+ */\n+class AuthCode extends BaseAuthCode\n+{\n+    /**\n+     * @ORM\\Id\n+     * @ORM\\Column(type=\"integer\")\n+     * @ORM\\GeneratedValue(strategy=\"AUTO\")\n+     */\n+    protected $id;\n+\n+    /**\n+     * @ORM\\ManyToOne(targetEntity=\"Client\")\n+     * @ORM\\JoinColumn(nullable=false)\n+     */\n+    protected $client;\n+\n+    /**\n+     * @ORM\\ManyToOne(targetEntity=\"AppBundle\\Entity\\User\")\n+     */\n+    protected $user;\n+}\n+\n+```\n+\n+`AppBundle/Entity/Client.php`\n+\n+```php\n+<?php\n+\n+namespace AppBundle\\Entity;\n+\n+use FOS\\OAuthServerBundle\\Entity\\Client as BaseClient;\n+use Doctrine\\ORM\\Mapping as ORM;\n+\n+/**\n+ * @ORM\\Entity\n+ */\n+class Client extends BaseClient\n+{\n+    /**\n+     * @ORM\\Id\n+     * @ORM\\Column(type=\"integer\")\n+     * @ORM\\GeneratedValue(strategy=\"AUTO\")\n+     */\n+    protected $id;\n+\n+    public function __construct()\n+    {\n+        parent::__construct();\n+        // your own logic\n+    }\n+}\n+\n+```\n+\n+`AppBundle/Entity/RefreshToken.php`\n+\n+```php\n+<?php\n+\n+namespace AppBundle\\Entity;\n+\n+use FOS\\OAuthServerBundle\\Entity\\RefreshToken as BaseRefreshToken;\n+use Doctrine\\ORM\\Mapping as ORM;\n+\n+/**\n+ * @ORM\\Entity\n+ */\n+class RefreshToken extends BaseRefreshToken\n+{\n+    /**\n+     * @ORM\\Id\n+     * @ORM\\Column(type=\"integer\")\n+     * @ORM\\GeneratedValue(strategy=\"AUTO\")\n+     */\n+    protected $id;\n+\n+    /**\n+     * @ORM\\ManyToOne(targetEntity=\"Client\")\n+     * @ORM\\JoinColumn(nullable=false)\n+     */\n+    protected $client;\n+\n+    /**\n+     * @ORM\\ManyToOne(targetEntity=\"AppBundle\\Entity\\User\")\n+     */\n+    protected $user;\n+}\n+\n+```\n+\n+`AppBundle/Entity/User.php`\n+\n+Add the file from the [FOSUserBundle Integration](fosuser-bundle.md#creating-a-user-entity-with-serialization-groups).\n+\n+## Security Configuration\n+\n+```yaml\n+# To get started with security, check out the documentation:\n+# http://symfony.com/doc/current/book/security.html\n+security:\n+\n+    encoders:\n+        FOS\\UserBundle\\Model\\UserInterface: bcrypt\n+\n+    providers:\n+        fos_user_bundle:\n+            id: fos_user.user_provider.username\n+\n+    firewalls:\n+        # disables authentication for assets and the profiler, adapt it according to your needs\n+        dev:\n+            pattern: ^/(_(profiler|wdt)|css|images|js)/\n+            security: false\n+\n+        oauth_token:\n+            pattern:    ^/oauth/v2/token\n+            security:   false\n+\n+        oauth_authorize:\n+            pattern:    ^/oauth/v2/auth\n+            # Add your favorite authentication process here\n+\n+        api_docs:\n+            pattern: ^/(|docs.json|docs.jsonld|index.json)$\n+            form_login: false            \n+            provider: fos_user_bundle\n+            http_basic:\n+                realm: \"Please enter your login data.\"\n+\n+        api:\n+            pattern:   ^/.+\n+            fos_oauth: true\n+            stateless: true\n+            anonymous: true\n+\n+    access_control:\n+        - { path: ^/.+, roles: [ IS_AUTHENTICATED_FULLY ] }\n+\n+```\n+\n+## Routing Configuration\n+\n+```yaml\n+api:\n+    resource: '.'\n+    type:     'api_platform'\n+\n+fos_oauth_server_token:\n+    resource: \"@FOSOAuthServerBundle/Resources/config/routing/token.xml\"\n+\n+fos_oauth_server_authorize:\n+    resource: \"@FOSOAuthServerBundle/Resources/config/routing/authorize.xml\"\n+```\n+\n+## Create clients\n+\n+Add this class to `AppBundle/Command/CreateOAuthClientCommand.php` to generate oauth clients via console:\n+\n+```php\n+<?php\n+\n+namespace AppBundle\\Command;\n+\n+use AppBundle\\Entity\\Client;\n+use Symfony\\Bundle\\FrameworkBundle\\Command\\ContainerAwareCommand;\n+use Symfony\\Component\\Console\\Input\\InputArgument;\n+use Symfony\\Component\\Console\\Input\\InputInterface;\n+use Symfony\\Component\\Console\\Output\\OutputInterface;\n+use Symfony\\Component\\HttpFoundation\\Request;\n+\n+class CreateOAuthClientCommand extends ContainerAwareCommand\n+{\n+    protected function configure()\n+    {\n+        $this\n+            ->setName('oauth:client:create')\n+            ->setDescription('Create OAuth Client')\n+            ->addArgument(\n+                'grantType',\n+                InputArgument::REQUIRED,\n+                'Grant Type?'\n+            )\n+            ->addArgument(\n+                'redirectUri',\n+                InputArgument::OPTIONAL,\n+                'Redirect URI?'\n+            );\n+    }\n+\n+    protected function execute(InputInterface $input, OutputInterface $output)\n+    {\n+        $container = $this->getContainer();\n+        $redirectUri = $input->getArgument('redirectUri');\n+        $grantType = $input->getArgument('grantType');\n+\n+        $clientManager = $container->get('fos_oauth_server.client_manager.default');\n+        /** @var Client $client */\n+        $client = $clientManager->createClient();\n+        $client->setRedirectUris($redirectUri ? [$redirectUri] : []);\n+        $client->setAllowedGrantTypes([$grantType]);\n+        $clientManager->updateClient($client);\n+\n+        $output->writeln(sprintf(\"<info>The client <comment>%s</comment> was created with <comment>%s</comment> as public id and <comment>%s</comment> as secret</info>\",\n+            $client->getId(),\n+            $client->getPublicId(),\n+            $client->getSecret()\n+        ));\n+    }\n+}\n+```\n+\n+Now you can generate two clients. One for our swagger api documentation and one for our application that wants to get data from our api.\n+\n+```bash\n+# Swagger api documentation client\n+php bin/console oauth:client:create password\n+\n+# Application client\n+php bin/console oauth:client:create client_credentials\n+```\n+\n+## OAuth2 Configuration\n+\n+Add the following code to your `app/config/config.yml` and replace the `clientId` and `clientSecret` with the data from the generated application client with the `client_credentials` grant type.\n+\n+```yaml\n+# ...\n+fos_oauth_server:\n+    db_driver: orm       # Drivers available: orm, mongodb, or propel\n+    client_class:        AppBundle\\Entity\\Client\n+    access_token_class:  AppBundle\\Entity\\AccessToken\n+    refresh_token_class: AppBundle\\Entity\\RefreshToken\n+    auth_code_class:     AppBundle\\Entity\\AuthCode\n+    service:\n+        user_provider: fos_user.user_provider.username\n+        options:\n+            access_token_lifetime: 10800\n+            supported_scopes: user","path":"core/oauth2.md","position":325,"original_position":325,"commit_id":"ed356c95669307202e43aa5099a44fef0c0ac2a0","original_commit_id":"ed356c95669307202e43aa5099a44fef0c0ac2a0","user":{"login":"dunglas","id":57224,"avatar_url":"https://avatars2.githubusercontent.com/u/57224?v=4","gravatar_id":"","url":"https://api.github.com/users/dunglas","html_url":"https://github.com/dunglas","followers_url":"https://api.github.com/users/dunglas/followers","following_url":"https://api.github.com/users/dunglas/following{/other_user}","gists_url":"https://api.github.com/users/dunglas/gists{/gist_id}","starred_url":"https://api.github.com/users/dunglas/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dunglas/subscriptions","organizations_url":"https://api.github.com/users/dunglas/orgs","repos_url":"https://api.github.com/users/dunglas/repos","events_url":"https://api.github.com/users/dunglas/events{/privacy}","received_events_url":"https://api.github.com/users/dunglas/received_events","type":"User","site_admin":false},"body":"The full docs are available here: https://api-platform.com/docs\r\nAnd also in this GitHub repository.\r\n\r\nI really want to merge this one, but it need to be rebased and finished first...","created_at":"2018-03-15T10:23:53Z","updated_at":"2018-03-15T10:23:53Z","html_url":"https://github.com/api-platform/docs/pull/182#discussion_r174735313","pull_request_url":"https://api.github.com/repos/api-platform/docs/pulls/182","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/api-platform/docs/pulls/comments/174735313"},"html":{"href":"https://github.com/api-platform/docs/pull/182#discussion_r174735313"},"pull_request":{"href":"https://api.github.com/repos/api-platform/docs/pulls/182"}},"in_reply_to_id":115086203},"pull_request":{"url":"https://api.github.com/repos/api-platform/docs/pulls/182","id":110315176,"html_url":"https://github.com/api-platform/docs/pull/182","diff_url":"https://github.com/api-platform/docs/pull/182.diff","patch_url":"https://github.com/api-platform/docs/pull/182.patch","issue_url":"https://api.github.com/repos/api-platform/docs/issues/182","number":182,"state":"open","locked":false,"title":"added oauth2 documentation","user":{"login":"iCodr8","id":1264033,"avatar_url":"https://avatars0.githubusercontent.com/u/1264033?v=4","gravatar_id":"","url":"https://api.github.com/users/iCodr8","html_url":"https://github.com/iCodr8","followers_url":"https://api.github.com/users/iCodr8/followers","following_url":"https://api.github.com/users/iCodr8/following{/other_user}","gists_url":"https://api.github.com/users/iCodr8/gists{/gist_id}","starred_url":"https://api.github.com/users/iCodr8/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iCodr8/subscriptions","organizations_url":"https://api.github.com/users/iCodr8/orgs","repos_url":"https://api.github.com/users/iCodr8/repos","events_url":"https://api.github.com/users/iCodr8/events{/privacy}","received_events_url":"https://api.github.com/users/iCodr8/received_events","type":"User","site_admin":false},"body":"Documentation for the OAuth2 integration as promised in #180.","created_at":"2017-03-12T21:04:02Z","updated_at":"2018-03-15T10:23:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cf48d465b02804495f606c094856e32550ed29c5","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":846980396,"url":"https://api.github.com/repos/api-platform/docs/labels/Needs%20Work","name":"Needs Work","color":"b60205","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/api-platform/docs/pulls/182/commits","review_comments_url":"https://api.github.com/repos/api-platform/docs/pulls/182/comments","review_comment_url":"https://api.github.com/repos/api-platform/docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/api-platform/docs/issues/182/comments","statuses_url":"https://api.github.com/repos/api-platform/docs/statuses/ed356c95669307202e43aa5099a44fef0c0ac2a0","head":{"label":"Craffft:feature/oauth2-docs","ref":"feature/oauth2-docs","sha":"ed356c95669307202e43aa5099a44fef0c0ac2a0","user":{"login":"Craffft","id":11056372,"avatar_url":"https://avatars2.githubusercontent.com/u/11056372?v=4","gravatar_id":"","url":"https://api.github.com/users/Craffft","html_url":"https://github.com/Craffft","followers_url":"https://api.github.com/users/Craffft/followers","following_url":"https://api.github.com/users/Craffft/following{/other_user}","gists_url":"https://api.github.com/users/Craffft/gists{/gist_id}","starred_url":"https://api.github.com/users/Craffft/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Craffft/subscriptions","organizations_url":"https://api.github.com/users/Craffft/orgs","repos_url":"https://api.github.com/users/Craffft/repos","events_url":"https://api.github.com/users/Craffft/events{/privacy}","received_events_url":"https://api.github.com/users/Craffft/received_events","type":"Organization","site_admin":false},"repo":null},"base":{"label":"api-platform:master","ref":"master","sha":"2d3b4bb533b66fb556e81a2c852d6ccb7ab74da5","user":{"login":"api-platform","id":13420081,"avatar_url":"https://avatars3.githubusercontent.com/u/13420081?v=4","gravatar_id":"","url":"https://api.github.com/users/api-platform","html_url":"https://github.com/api-platform","followers_url":"https://api.github.com/users/api-platform/followers","following_url":"https://api.github.com/users/api-platform/following{/other_user}","gists_url":"https://api.github.com/users/api-platform/gists{/gist_id}","starred_url":"https://api.github.com/users/api-platform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/api-platform/subscriptions","organizations_url":"https://api.github.com/users/api-platform/orgs","repos_url":"https://api.github.com/users/api-platform/repos","events_url":"https://api.github.com/users/api-platform/events{/privacy}","received_events_url":"https://api.github.com/users/api-platform/received_events","type":"Organization","site_admin":false},"repo":{"id":38251565,"name":"docs","full_name":"api-platform/docs","owner":{"login":"api-platform","id":13420081,"avatar_url":"https://avatars3.githubusercontent.com/u/13420081?v=4","gravatar_id":"","url":"https://api.github.com/users/api-platform","html_url":"https://github.com/api-platform","followers_url":"https://api.github.com/users/api-platform/followers","following_url":"https://api.github.com/users/api-platform/following{/other_user}","gists_url":"https://api.github.com/users/api-platform/gists{/gist_id}","starred_url":"https://api.github.com/users/api-platform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/api-platform/subscriptions","organizations_url":"https://api.github.com/users/api-platform/orgs","repos_url":"https://api.github.com/users/api-platform/repos","events_url":"https://api.github.com/users/api-platform/events{/privacy}","received_events_url":"https://api.github.com/users/api-platform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/api-platform/docs","description":"API Platform documentation","fork":false,"url":"https://api.github.com/repos/api-platform/docs","forks_url":"https://api.github.com/repos/api-platform/docs/forks","keys_url":"https://api.github.com/repos/api-platform/docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/api-platform/docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/api-platform/docs/teams","hooks_url":"https://api.github.com/repos/api-platform/docs/hooks","issue_events_url":"https://api.github.com/repos/api-platform/docs/issues/events{/number}","events_url":"https://api.github.com/repos/api-platform/docs/events","assignees_url":"https://api.github.com/repos/api-platform/docs/assignees{/user}","branches_url":"https://api.github.com/repos/api-platform/docs/branches{/branch}","tags_url":"https://api.github.com/repos/api-platform/docs/tags","blobs_url":"https://api.github.com/repos/api-platform/docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/api-platform/docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/api-platform/docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/api-platform/docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/api-platform/docs/statuses/{sha}","languages_url":"https://api.github.com/repos/api-platform/docs/languages","stargazers_url":"https://api.github.com/repos/api-platform/docs/stargazers","contributors_url":"https://api.github.com/repos/api-platform/docs/contributors","subscribers_url":"https://api.github.com/repos/api-platform/docs/subscribers","subscription_url":"https://api.github.com/repos/api-platform/docs/subscription","commits_url":"https://api.github.com/repos/api-platform/docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/api-platform/docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/api-platform/docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/api-platform/docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/api-platform/docs/contents/{+path}","compare_url":"https://api.github.com/repos/api-platform/docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/api-platform/docs/merges","archive_url":"https://api.github.com/repos/api-platform/docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/api-platform/docs/downloads","issues_url":"https://api.github.com/repos/api-platform/docs/issues{/number}","pulls_url":"https://api.github.com/repos/api-platform/docs/pulls{/number}","milestones_url":"https://api.github.com/repos/api-platform/docs/milestones{/number}","notifications_url":"https://api.github.com/repos/api-platform/docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/api-platform/docs/labels{/name}","releases_url":"https://api.github.com/repos/api-platform/docs/releases{/id}","deployments_url":"https://api.github.com/repos/api-platform/docs/deployments","created_at":"2015-06-29T14:19:34Z","updated_at":"2018-03-15T10:09:20Z","pushed_at":"2018-03-15T10:13:54Z","git_url":"git://github.com/api-platform/docs.git","ssh_url":"git@github.com:api-platform/docs.git","clone_url":"https://github.com/api-platform/docs.git","svn_url":"https://github.com/api-platform/docs","homepage":"https://api-platform.com/docs/","size":8093,"stargazers_count":47,"watchers_count":47,"language":null,"has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":179,"mirror_url":null,"archived":false,"open_issues_count":30,"license":null,"forks":179,"open_issues":30,"watchers":47,"default_branch":"2.2"}},"_links":{"self":{"href":"https://api.github.com/repos/api-platform/docs/pulls/182"},"html":{"href":"https://github.com/api-platform/docs/pull/182"},"issue":{"href":"https://api.github.com/repos/api-platform/docs/issues/182"},"comments":{"href":"https://api.github.com/repos/api-platform/docs/issues/182/comments"},"review_comments":{"href":"https://api.github.com/repos/api-platform/docs/pulls/182/comments"},"review_comment":{"href":"https://api.github.com/repos/api-platform/docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/api-platform/docs/pulls/182/commits"},"statuses":{"href":"https://api.github.com/repos/api-platform/docs/statuses/ed356c95669307202e43aa5099a44fef0c0ac2a0"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"dunglas"}}