Oauth2-server: Implementing league/oauth2-server with symfony 3.x

Created on 5 Nov 2017  路  9Comments  路  Source: thephpleague/oauth2-server

I'm attempting to implement league/oauth2-server using symfony 3.x and Doctrine, feeding a MySql database. Per code in the example shown here http://oauth2.thephpleague.com/authorization-server/auth-code-grant/, it would appear one needs to implement one's own storage for tokens etc (which makes sense).

This example asks for multiple Repositories:

   // Init our repositories
$clientRepository = new ClientRepository(); // instance of ClientRepositoryInterface
$scopeRepository = new ScopeRepository(); // instance of ScopeRepositoryInterface
$accessTokenRepository = new AccessTokenRepository(); // instance of AccessTokenRepositoryInterface
$authCodeRepository = new AuthCodeRepository(); // instance of AuthCodeRepositoryInterface
$refreshTokenRepository = new RefreshTokenRepository(); // instance of RefreshTokenRepositoryInterface

I've tried using both PHP Repositories and symfony repositories, with little or no luck.

Has anyone else done this, and can give examples of the repository code?

Improvement Idea

Most helpful comment

@pilotcurler I know this has been a while, but for others' benefit who Google their way here..

Symfony 3+ DI wants the services type-hinted in the controller endpoints and entity constructors.

My bundle services.yml looks a bit like this:

League\OAuth2\Server\AuthorizationServer:
    class:       League\OAuth2\Server\AuthorizationServer
    arguments:
        - '@MyAuthBundle\Repository\ClientRepository'
        - '@MyAuthBundle\Repository\AccessTokenRepository'
        - '@MyAuthBundle\Repository\ScopeRepository'
        - "%oauth2_private_key%"
        - "%oauth2_encryption_key%"

League\OAuth2\Server\Grant\PasswordGrant:
    class:    League\OAuth2\Server\Grant\PasswordGrant
    arguments:
        - '@MyAuthBundle\Repository\UserRepository'
        - '@MyAuthBundle\Repository\RefreshTokenRepository'

League\OAuth2\Server\Grant\RefreshTokenGrant:
    class:    League\OAuth2\Server\Grant\RefreshTokenGrant
    arguments:
        - '@MyAuthBundle\Repository\RefreshTokenRepository'`

..Then you grab them in the various constructors & controllers, ie:

#MyAuthBundle/Controller/TokenController.php

public function tokenAction(AuthorizationServer $server, PasswordGrant $passwordGrant, RefreshTokenGrant $refreshTokenGrant, RequestInterface $request ): Response
    {
        $passwordGrant->setRefreshTokenTTL(new \DateInterval('P1M'));
//etc

You'll need some PSR7 jiggery-pokery too:

use Psr\Http\Message\RequestInterface;
use Zend\Diactoros\Response; //implements Psr\Http\Message\ResponseInterface

(edit:)
Also worth mentioning that I had an issue using the vendor repositories, in that I got tied up in knots trying to implement League\OAuth2\Server\Repositories(whatever)RepositoryInterface and extend Doctrine\ORM\EntityRepository with the same class, so eventually gave up and split them into separate classes, passing the Doctrine Manager for each entity to the Repository:

use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use MyAuthBundle\Doctrine\ORM\AccessTokenManager;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;

/**
 * Class AccessTokenRepo
 * @package MyAuthBundle\Service\OAuthRepository
 * @author ...
 */
class AccessTokenRepo implements AccessTokenRepositoryInterface {

    /**
     * @var AccessTokenManager
     */
    private $accessTokenManager;

    /**
     * AccessTokenRepo constructor.
     * @param AccessTokenManager $accessTokenManager
     */
    public function __construct(AccessTokenManager $accessTokenManager)
    {
        $this->accessTokenManager = $accessTokenManager;
    }

Not an even slightly elegant solution, but it works.
HTH ppl

All 9 comments

@pilotcurler It's very tricky to put anything in the documentation that will give solid examples for specific setups as there is just so much variety from one app to another, but I can see how this is a little tricky to get going. Improving the docs is something we're working on.

Basically, implementing the interfaces these examples identify will go some way to helping you to write the correct classes (and probably infer your database structure), but the specifics of the structure and functionality implementation is up to you.

The documentation for each of these interfaces is on the League site. Please look in the menu on the left under Repository Interfaces.

In general, your repository classes are the go-between from the oauth2-server library's functionality to your application's persistent storage mechanism (in your case, MySQL through Doctrine), so in most cases these will be very specific to your application and not likely found generalised elsewhere.

I'm not _au fait_ with the particulars of Symfony, but it should be straightforward enough to create these classes. You just need to write a (repository) class for each of those repository interfaces. Then you can reliably pass instances of those classes into the new \League\OAuth2\Server\AuthorizationServer() as appropriate.

I know it's not a Symfony implementation, but I'd encourage you to look over the Laravel Passport implementation of oauth2-server as it may guide you in the right direction. The src/Bridge/ folder contains clear and simple implementations of all of the concrete repository and entity classes required by this library.

If anyone is prepared to share a Symfony-/Doctrine-specific implementation, I'd be happy to look at getting it added into our examples.

I did do a complete Symfony 3 integration, but on a client/proprietary project, I cannot share any code. As @simonhamp stated, every bit of the implementation is tied to the client's business.

First step in doing this is to provide services to your container the right way, but sadly a lot of this library's components are not stateless, and you should not share them in the end, but because PHP dies with the end of the request, just putting everything in the service container do work, even if it's not really future proof.

You will need a few compiler passes if you need it to be configurable.

Second step is implementing your own repositories. Scope and user repositories will be heavily coupled to your business so it's not easy to share or would probably be counter productive to attempt to make it generic.

Client repository, in the other side, may be quite generic, but its implementation will vary depending on how you need clients to be registered (by users themselves ? by an admin ? hardcoded or by configuration ?).

Third but optional step is to implement repositories for various access codes and tokens, but this is only if you wish to get rid of the JWT token. I had to for technical reasons because one of the consumers had HTTP header size limitations, JWT were way too big.

And last, but the bigger and harder step, is implementing correctly the controllers, and once again, it'll depend on your business, on how you wish to build the various screens, etc...

I'm not sure a generic implementation is really possible.

@pilotcurler did you manage to make progress with this? Effectively you need to put functionality in your repository implementations to call your Doctrine models which connect up to your MySQL database as stated by @simonhamp. Please do let us know how you got on with this or if there is anything else we can do to assist. Many thanks

@pilotcurler I'm going to close this issue as there has been no update on it in a while now. I aim to update the documentation to hopefully make it clearer how to implement the package which should help people in the future that have similar issues to you.

If you do have any more concerns please feel free to get back in touch.

@pilotcurler I know this has been a while, but for others' benefit who Google their way here..

Symfony 3+ DI wants the services type-hinted in the controller endpoints and entity constructors.

My bundle services.yml looks a bit like this:

League\OAuth2\Server\AuthorizationServer:
    class:       League\OAuth2\Server\AuthorizationServer
    arguments:
        - '@MyAuthBundle\Repository\ClientRepository'
        - '@MyAuthBundle\Repository\AccessTokenRepository'
        - '@MyAuthBundle\Repository\ScopeRepository'
        - "%oauth2_private_key%"
        - "%oauth2_encryption_key%"

League\OAuth2\Server\Grant\PasswordGrant:
    class:    League\OAuth2\Server\Grant\PasswordGrant
    arguments:
        - '@MyAuthBundle\Repository\UserRepository'
        - '@MyAuthBundle\Repository\RefreshTokenRepository'

League\OAuth2\Server\Grant\RefreshTokenGrant:
    class:    League\OAuth2\Server\Grant\RefreshTokenGrant
    arguments:
        - '@MyAuthBundle\Repository\RefreshTokenRepository'`

..Then you grab them in the various constructors & controllers, ie:

#MyAuthBundle/Controller/TokenController.php

public function tokenAction(AuthorizationServer $server, PasswordGrant $passwordGrant, RefreshTokenGrant $refreshTokenGrant, RequestInterface $request ): Response
    {
        $passwordGrant->setRefreshTokenTTL(new \DateInterval('P1M'));
//etc

You'll need some PSR7 jiggery-pokery too:

use Psr\Http\Message\RequestInterface;
use Zend\Diactoros\Response; //implements Psr\Http\Message\ResponseInterface

(edit:)
Also worth mentioning that I had an issue using the vendor repositories, in that I got tied up in knots trying to implement League\OAuth2\Server\Repositories(whatever)RepositoryInterface and extend Doctrine\ORM\EntityRepository with the same class, so eventually gave up and split them into separate classes, passing the Doctrine Manager for each entity to the Repository:

use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
use MyAuthBundle\Doctrine\ORM\AccessTokenManager;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;

/**
 * Class AccessTokenRepo
 * @package MyAuthBundle\Service\OAuthRepository
 * @author ...
 */
class AccessTokenRepo implements AccessTokenRepositoryInterface {

    /**
     * @var AccessTokenManager
     */
    private $accessTokenManager;

    /**
     * AccessTokenRepo constructor.
     * @param AccessTokenManager $accessTokenManager
     */
    public function __construct(AccessTokenManager $accessTokenManager)
    {
        $this->accessTokenManager = $accessTokenManager;
    }

Not an even slightly elegant solution, but it works.
HTH ppl

Thanks for providing this @gingabeard

Has there been anymore progress on example implementations? I've been banging my head against a wall trying to figure out how to get this setup with symfony.

I was able to get it setup using bshaffer/oauth2-server-php after a
significant amount of futzing, but no changes to bshaffer code. PHP 7.2.
Symfony 4. I can reliably generate tokens, and have integrated a database
to store them.

From: Robert Quinn notifications@github.com
Sent: Thursday, December 26, 2019 11:04 AM
To: thephpleague/oauth2-server oauth2-server@noreply.github.com
Cc: Doug git@marksmansystems.com; Mention mention@noreply.github.com
Subject: Re: [thephpleague/oauth2-server] Implementing league/oauth2-server
with symfony 3.x (#808)

Has there been anymore progress on example implementations? I've been
banging my head against a wall trying to figure out how to get this setup
with symfony.

-
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
ications&email_token=AHFTUWUFQLZ6EJKNBGRHSQTQ2TIVTA5CNFSM4ECKENNKYY3PNVWWK3T
UL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHVX4PI#issuecomment-569081
405> , or unsubscribe
TIVTANCNFSM4ECKENNA> .
M4ECKENNKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHVX4PI
.gif>

I'm not too familiar with Symfony myself but this community implementation might be of use: https://github.com/trikoder/oauth2-bundle

Was this page helpful?
0 / 5 - 0 ratings