Skip to content

OAuth Server

Your Ibexa DXP instance can be used as an OAuth2 server, combining the roles of an Authorization Server and a Resource Server. Client applications, such as mobile apps, are able to authenticate a user, and then access this user's resources.

OAuth2 Server

Server installation

Ibexa DXP Oauth2 server package is ibexa/oauth2-server and isn't part of the default installation. You can install it with the following command:

1
composer require ibexa/oauth2-server --with-all-dependencies

Add the tables needed by the bundle:

```bash CREATE TABLE ibexa_oauth2_client (id SERIAL NOT NULL, client_name VARCHAR(128) NOT NULL, client_identifier VARCHAR(32) NOT NULL, client_secret VARCHAR(128) DEFAULT NULL, client_active BOOLEAN DEFAULT 'false' NOT NULL, client_plain_pkce BOOLEAN DEFAULT 'false' NOT NULL, PRIMARY KEY(id));

CREATE UNIQUE INDEX ibexa_oauth2_client_identifier_idx ON ibexa_oauth2_client (client_identifier); CREATE TABLE ibexa_oauth2_client_redirect_uri (id SERIAL NOT NULL, client_id INT NOT NULL, client_redirect_uri VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_redirect_uri_client_id_idx ON ibexa_oauth2_client_redirect_uri (client_id); CREATE INDEX ibexa_oauth2_client_redirect_uri_client_redirect_uri_idx ON ibexa_oauth2_client_redirect_uri (client_redirect_uri); CREATE UNIQUE INDEX ibexa_oauth2_client_redirect_uri_unique_idx ON ibexa_oauth2_client_redirect_uri (client_id, client_redirect_uri); CREATE TABLE ibexa_oauth2_client_grant (id SERIAL NOT NULL, client_id INT NOT NULL, client_grant VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_grant_client_id_idx ON ibexa_oauth2_client_grant (client_id); CREATE INDEX ibexa_oauth2_client_grant_client_grant_idx ON ibexa_oauth2_client_grant (client_grant); CREATE UNIQUE INDEX ibexa_oauth2_client_grant_unique_idx ON ibexa_oauth2_client_grant (client_id, client_grant); CREATE TABLE ibexa_oauth2_client_token (id SERIAL NOT NULL, client_id INT NOT NULL, token_id INT NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_token_client_id_idx ON ibexa_oauth2_client_token (client_id); CREATE INDEX ibexa_oauth2_client_token_token_id_idx ON ibexa_oauth2_client_token (token_id); CREATE UNIQUE INDEX ibexa_oauth2_client_token_unique_idx ON ibexa_oauth2_client_token (client_id, token_id); CREATE TABLE ibexa_oauth2_client_scope (id SERIAL NOT NULL, client_id INT NOT NULL, client_scope VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_scope_client_id_idx ON ibexa_oauth2_client_scope (client_id); CREATE INDEX ibexa_oauth2_client_scope_client_scope_idx ON ibexa_oauth2_client_scope (client_scope); CREATE UNIQUE INDEX ibexa_oauth2_client_scope_unique_idx ON ibexa_oauth2_client_scope (client_id, client_scope); CREATE TABLE ibexa_oauth2_token_scope (id SERIAL NOT NULL, token_id INT NOT NULL, token_scope VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_token_scope_token_id_idx ON ibexa_oauth2_token_scope (token_id); CREATE INDEX ibexa_oauth2_token_scope_scope_idx ON ibexa_oauth2_token_scope (token_scope); CREATE UNIQUE INDEX ibexa_oauth2_token_scope_unique_idx ON ibexa_oauth2_token_scope (token_id, token_scope); CREATE TABLE ibexa_oauth2_refresh_access_token (id SERIAL NOT NULL, access_token_id INT NOT NULL, refresh_token_id INT NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_refresh_access_token_access_token_id_idx ON ibexa_oauth2_refresh_access_token (access_token_id); CREATE INDEX ibexa_oauth2_refresh_access_token_refresh_token_id_idx ON ibexa_oauth2_refresh_access_token (refresh_token_id); CREATE UNIQUE INDEX ibexa_oauth2_refresh_access_token_unique_idx ON ibexa_oauth2_refresh_access_token (access_token_id, refresh_token_id); CREATE TABLE ibexa_oauth2_consent (id SERIAL NOT NULL, user_identifier VARCHAR(150) NOT NULL, client_identifier VARCHAR(32) NOT NULL, created INT DEFAULT 0 NOT NULL, updated INT DEFAULT 0 NOT NULL, PRIMARY KEY(id)); CREATE INDEX IDX_40497C0FD0494586 ON ibexa_oauth2_consent (user_identifier); CREATE INDEX IDX_40497C0FE77ABE2B ON ibexa_oauth2_consent (client_identifier); CREATE INDEX ibexa_oauth2_consent_consent_idx ON ibexa_oauth2_consent (user_identifier, client_identifier); CREATE UNIQUE INDEX ibexa_oauth2_consent_unique_idx ON ibexa_oauth2_consent (user_identifier, client_identifier); CREATE TABLE ibexa_oauth2_consent_scope (id SERIAL NOT NULL, consent_id INT NOT NULL, consent_scope VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_consent_scope_consent_id_idx ON ibexa_oauth2_consent_scope (consent_id); CREATE INDEX ibexa_oauth2_consent_scope_consent_scope_idx ON ibexa_oauth2_consent_scope (consent_scope); CREATE UNIQUE INDEX ibexa_oauth2_consent_scope_unique_idx ON ibexa_oauth2_consent_scope (consent_id, consent_scope); ALTER TABLE ibexa_oauth2_client_redirect_uri ADD CONSTRAINT ibexa_oauth2_client_redirect_uri_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_grant ADD CONSTRAINT ibexa_oauth2_client_grant_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_token ADD CONSTRAINT ibexa_oauth2_client_token_client_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_token ADD CONSTRAINT ibexa_oauth2_client_token_token_fk FOREIGN KEY (token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_scope ADD CONSTRAINT ibexa_oauth2_client_scope_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_token_scope ADD CONSTRAINT ibexa_oauth2_token_scope_fk FOREIGN KEY (token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_refresh_access_token ADD CONSTRAINT ibexa_oauth2_refresh_access_token_access_token_fk FOREIGN KEY (access_token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_refresh_access_token ADD CONSTRAINT ibexa_oauth2_refresh_access_token_refresh_token_fk FOREIGN KEY (refresh_token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_consent ADD CONSTRAINT ibexa_oauth2_consent_user_fk FOREIGN KEY (user_identifier) REFERENCES ezuser (login) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_consent ADD CONSTRAINT ibexa_oauth2_consent_client_fk FOREIGN KEY (client_identifier) REFERENCES ibexa_oauth2_client (client_identifier) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_consent_scope ADD CONSTRAINT ibexa_oauth2_consent_scope_fk FOREIGN KEY (consent_id) REFERENCES ibexa_oauth2_consent (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;

1
```

```bash CREATE TABLE ibexa_oauth2_client (id SERIAL NOT NULL, client_name VARCHAR(128) NOT NULL, client_identifier VARCHAR(32) NOT NULL, client_secret VARCHAR(128) DEFAULT NULL, client_active BOOLEAN DEFAULT 'false' NOT NULL, client_plain_pkce BOOLEAN DEFAULT 'false' NOT NULL, PRIMARY KEY(id));

CREATE UNIQUE INDEX ibexa_oauth2_client_identifier_idx ON ibexa_oauth2_client (client_identifier); CREATE TABLE ibexa_oauth2_client_redirect_uri (id SERIAL NOT NULL, client_id INT NOT NULL, client_redirect_uri VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_redirect_uri_client_id_idx ON ibexa_oauth2_client_redirect_uri (client_id); CREATE INDEX ibexa_oauth2_client_redirect_uri_client_redirect_uri_idx ON ibexa_oauth2_client_redirect_uri (client_redirect_uri); CREATE UNIQUE INDEX ibexa_oauth2_client_redirect_uri_unique_idx ON ibexa_oauth2_client_redirect_uri (client_id, client_redirect_uri); CREATE TABLE ibexa_oauth2_client_grant (id SERIAL NOT NULL, client_id INT NOT NULL, client_grant VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_grant_client_id_idx ON ibexa_oauth2_client_grant (client_id); CREATE INDEX ibexa_oauth2_client_grant_client_grant_idx ON ibexa_oauth2_client_grant (client_grant); CREATE UNIQUE INDEX ibexa_oauth2_client_grant_unique_idx ON ibexa_oauth2_client_grant (client_id, client_grant); CREATE TABLE ibexa_oauth2_client_token (id SERIAL NOT NULL, client_id INT NOT NULL, token_id INT NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_token_client_id_idx ON ibexa_oauth2_client_token (client_id); CREATE INDEX ibexa_oauth2_client_token_token_id_idx ON ibexa_oauth2_client_token (token_id); CREATE UNIQUE INDEX ibexa_oauth2_client_token_unique_idx ON ibexa_oauth2_client_token (client_id, token_id); CREATE TABLE ibexa_oauth2_client_scope (id SERIAL NOT NULL, client_id INT NOT NULL, client_scope VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_client_scope_client_id_idx ON ibexa_oauth2_client_scope (client_id); CREATE INDEX ibexa_oauth2_client_scope_client_scope_idx ON ibexa_oauth2_client_scope (client_scope); CREATE UNIQUE INDEX ibexa_oauth2_client_scope_unique_idx ON ibexa_oauth2_client_scope (client_id, client_scope); CREATE TABLE ibexa_oauth2_token_scope (id SERIAL NOT NULL, token_id INT NOT NULL, token_scope VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_token_scope_token_id_idx ON ibexa_oauth2_token_scope (token_id); CREATE INDEX ibexa_oauth2_token_scope_scope_idx ON ibexa_oauth2_token_scope (token_scope); CREATE UNIQUE INDEX ibexa_oauth2_token_scope_unique_idx ON ibexa_oauth2_token_scope (token_id, token_scope); CREATE TABLE ibexa_oauth2_refresh_access_token (id SERIAL NOT NULL, access_token_id INT NOT NULL, refresh_token_id INT NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_refresh_access_token_access_token_id_idx ON ibexa_oauth2_refresh_access_token (access_token_id); CREATE INDEX ibexa_oauth2_refresh_access_token_refresh_token_id_idx ON ibexa_oauth2_refresh_access_token (refresh_token_id); CREATE UNIQUE INDEX ibexa_oauth2_refresh_access_token_unique_idx ON ibexa_oauth2_refresh_access_token (access_token_id, refresh_token_id); CREATE TABLE ibexa_oauth2_consent (id SERIAL NOT NULL, user_identifier VARCHAR(150) NOT NULL, client_identifier VARCHAR(32) NOT NULL, created INT DEFAULT 0 NOT NULL, updated INT DEFAULT 0 NOT NULL, PRIMARY KEY(id)); CREATE INDEX IDX_40497C0FD0494586 ON ibexa_oauth2_consent (user_identifier); CREATE INDEX IDX_40497C0FE77ABE2B ON ibexa_oauth2_consent (client_identifier); CREATE INDEX ibexa_oauth2_consent_consent_idx ON ibexa_oauth2_consent (user_identifier, client_identifier); CREATE UNIQUE INDEX ibexa_oauth2_consent_unique_idx ON ibexa_oauth2_consent (user_identifier, client_identifier); CREATE TABLE ibexa_oauth2_consent_scope (id SERIAL NOT NULL, consent_id INT NOT NULL, consent_scope VARCHAR(255) NOT NULL, PRIMARY KEY(id)); CREATE INDEX ibexa_oauth2_consent_scope_consent_id_idx ON ibexa_oauth2_consent_scope (consent_id); CREATE INDEX ibexa_oauth2_consent_scope_consent_scope_idx ON ibexa_oauth2_consent_scope (consent_scope); CREATE UNIQUE INDEX ibexa_oauth2_consent_scope_unique_idx ON ibexa_oauth2_consent_scope (consent_id, consent_scope); ALTER TABLE ibexa_oauth2_client_redirect_uri ADD CONSTRAINT ibexa_oauth2_client_redirect_uri_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_grant ADD CONSTRAINT ibexa_oauth2_client_grant_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_token ADD CONSTRAINT ibexa_oauth2_client_token_client_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_token ADD CONSTRAINT ibexa_oauth2_client_token_token_fk FOREIGN KEY (token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_client_scope ADD CONSTRAINT ibexa_oauth2_client_scope_fk FOREIGN KEY (client_id) REFERENCES ibexa_oauth2_client (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_token_scope ADD CONSTRAINT ibexa_oauth2_token_scope_fk FOREIGN KEY (token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_refresh_access_token ADD CONSTRAINT ibexa_oauth2_refresh_access_token_access_token_fk FOREIGN KEY (access_token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_refresh_access_token ADD CONSTRAINT ibexa_oauth2_refresh_access_token_refresh_token_fk FOREIGN KEY (refresh_token_id) REFERENCES ibexa_token (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_consent ADD CONSTRAINT ibexa_oauth2_consent_user_fk FOREIGN KEY (user_identifier) REFERENCES ezuser (login) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_consent ADD CONSTRAINT ibexa_oauth2_consent_client_fk FOREIGN KEY (client_identifier) REFERENCES ibexa_oauth2_client (client_identifier) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE; ALTER TABLE ibexa_oauth2_consent_scope ADD CONSTRAINT ibexa_oauth2_consent_scope_fk FOREIGN KEY (consent_id) REFERENCES ibexa_oauth2_consent (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE;

1
```

Then, in config/bundles.php, at the end of an array with a list of bundles, add the following two lines :

1
2
3
4
5
6
7
<?php

return [
    // A lot of bundles…
    Ibexa\Bundle\OAuth2Server\IbexaOAuth2ServerBundle::class => ['all' => true],
    League\Bundle\OAuth2ServerBundle\LeagueOAuth2ServerBundle::class => ['all' => true],
];

Authorization Server configuration

Keys

To configure the server, you need private and public keys.

For more information, see Generating public and private keys.

You also need an encryption key.

For more information, see Generating encryption keys.

Set the following environment variables:

1
2
3
4
OAUTH2_PUBLIC_KEY_PATH=/somewhere/safe/key.public
OAUTH2_PRIVATE_KEY_PATH=/somewhere/safe/key.private
OAUTH2_PRIVATE_KEY_PASSPHRASE=some_passphrase_or_empty
OAUTH2_ENCRYPTION_KEY=1234567890123456789012345678901234567890

Service, routes, and security configurations

Uncomment the whole service configuration file: config/packages/ibexa_oauth2_server.yaml. Tweak the values if necessary.

Uncomment the whole routes configuration file: config/routes/ibexa_oauth2_server.yaml.

In config/packages/security.yaml, uncomment the following three lines under the access_control key:

1
2
3
4
5
6
7
security:
    #…

    # Uncomment authorize access control if you wish to use product as an OAuth2 Server
    access_control:
        - { path: ^/authorize/jwks$, roles: ~ }
        - { path: ^/authorize, roles: IS_AUTHENTICATED_REMEMBERED }

In config/packages/security.yaml, uncomment the three following lines under the oauth2_token key:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
security:
    #…
    firewall:
        #…

        # Uncomment oauth2_token firewall if you wish to use product as an OAuth2 Server.
        # Use oauth2 guard any other (for example ibexa_front) firewall you wish to be
        # exposed as OAuth2-available resource. Example:
        #    guard:
        #        authenticators:
        #            - Ibexa\OAuth2Server\Security\Guard\OAuth2Authenticator
        oauth2_token:
            pattern: ^/token$
            security: false

Resource Server configuration

To allow resource routes to be accessible through OAuth authorization, you must define a firewall by using Ibexa\OAuth2Server\Security\Guard\OAuth2Authenticator.

The following firewall example allows the REST API to be accessed as an OAuth resource. It must be placed before the firewall with a less restrictive pattern like ibexa_front.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
    #…
    firewall:
        #…

        ibexa_rest_oauth:
            pattern: ^/api/ibexa/v2
            user_checker: Ibexa\Core\MVC\Symfony\Security\UserChecker
            anonymous: ~
            guard:
                authenticators:
                    - Ibexa\OAuth2Server\Security\Guard\OAuth2Authenticator
                entry_point: Ibexa\OAuth2Server\Security\Guard\OAuth2Authenticator
            stateless: true

        ibexa_front:
            pattern: ^/
            #…

Client

Add a client

You need the client redirect URIs to create a client. You also need to agree on an identifier and a secret with the client. There is only one default scope.

Use league:oauth2-server:create-client command to create a client. For example:

1
2
php bin/console league:oauth2-server:create-client 'Example OAuth2 Client' example-oauth2-client 9876543210987654321098765432109876543210 --scope=default \
  --redirect-uri=https://example.com/oauth2-callback

Note

You can call --redirect-uri multiple times.

Alternatively, you could add redirect URIs after you create a client, by using the league:oauth2-server:update-client command. For example:

1
2
php bin/console league:oauth2-server:update-client example-oauth2-client \
  --add-redirect-uri=https://example.com/another-oauth2-callback

Other commands let you list all the configured clients (league:oauth2-server:list-clients) or delete a client (league:oauth2-server:delete-client).

Note

For a list of all the commands that you can use maintain your clients, in a terminal, run bin/console list league:oauth2-server. To see usage details for each of the commands, run bin/console help <command> .

For more information, see the package's online documentation.

Information needed by the client

Your OAuth2 client needs the following information to be able to use your Oauth server:

  • The URL of the Ibexa DXP used as an oauth server
  • The client identifier
  • The client secret
  • The scope (default)