OAuth integration into Nette Framework

Installs: 185

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 2

Forks: 1

Open Issues: 0

Type:project

v1.0.0 2024-01-29 01:14 UTC

This package is auto-updated.

Last update: 2024-11-29 03:04:58 UTC


README

OAuth

👤 OAuth integration into Nette Framework

Checks Coverage Status Total Downloads Latest Version PHP Version

Installation

$ composer require 68publishers/oauth

Configuration

Facebook

$ composer require league/oauth2-facebook
extensions:
    68publishers.oauth: SixtyEightPublishers\OAuth\Bridge\Nette\DI\OAuthExtension
    68publishers.facebook: SixtyEightPublishers\OAuth\Bridge\Nette\DI\FacebookOAuthExtension

68publishers.facebook:
    flowName: facebook # default, not necessary to define
    config:
        enabled: true # default, not necessary to define
        clientId: '<client id>'
        clientSecret: '<client id>'
        graphApiVersion: '<graph api version>'
        options: [] # additional options that are passed into the client
    authenticator: App\OAuth\FacebookAuthenticator

Azure

$ composer require thenetworg/oauth2-azure
extensions:
    68publishers.oauth: SixtyEightPublishers\OAuth\Bridge\Nette\DI\OAuthExtension
    68publishers.azure: SixtyEightPublishers\OAuth\Bridge\Nette\DI\FacebookOAuthExtension

68publishers.azure:
    flowName: azure # default, not necessary to define
    config:
        enabled: true # default, not necessary to define
        clientId: '<client id>'
        clientSecret: '<client id>'
        tenantId: '<tenant id>' # optional, use this option only if your Azure Entra ID application is configured as a single tenant.
        options: [] # additional options that are passed into the client
    authenticator: App\OAuth\AzureAuthenticator

Integration

Lazy configuration

Sometimes it may be desirable to provide the configuration for an OAuth client dynamically if, for example, we have settings stored in a database. We can do this with the following implementation:

namespace App\OAuth\Config;

use SixtyEightPublishers\OAuth\Config\Config;
use SixtyEightPublishers\OAuth\Config\LazyConfig;
use App\SettingsProvider;

final class AzureConfig extends LazyConfig
{
    public function __construct(SettingsProvider $provider) {
        parent::__construct(
            configFactory: static function (): Config {
                return new Config(
                    flowEnabled: $provider->get('azure.enabled'),
                    options: [
                        'clientId' => $provider->get('azure.clientId'),
                        'clientSecret' => $provider->get('azure.clientSecret'),
                    ],
                );
            }
        );
    }
}
# ...

68publishers.azure:
    config: App\OAuth\Config\AzureConfig

# ...

Implementing Authenticator

Authenticator is a class implementing the AuthenticatorInterface interface. This class should return the identity of the user and throw an AuthenticationException exception in case of any problem.

namespace App\OAuth;

use SixtyEightPublishers\OAuth\Authentication\AuthenticatorInterface;
use SixtyEightPublishers\OAuth\Exception\AuthenticationException;
use SixtyEightPublishers\OAuth\Authorization\AuthorizationResult;
use Nette\Security\IIdentity;
use Nette\Security\SimpleIdentity;

final class AzureAuthenticator implements AuthenticatorInterface
{
    public function authenticate(string $flowName, AuthorizationResult $authorizationResult): IIdentity
    {
        $accessToken = $authorizationResult->accessToken;
        $resourceOwner = $authorizationResult->resourceOwner;
        
        if ($userCannotBeAuthenticated) {
            throw new AuthenticationException('User can not be authenticated.');
        }
        
        return new SimpleIdentity(/* ... */);
    }
}

Implementing OAuth Presenter

The OAuthPresenterTrait trait is used for simple implementation. Next, you need to define three methods that determine what should happen if the authentication is successful or fails. All three methods should redirect at the end.

namespace App\Presenter;

use Nette\Application\UI\Presenter;
use SixtyEightPublishers\OAuth\Bridge\Nette\Application\OAuthPresenterTrait;
use SixtyEightPublishers\OAuth\Exception\OAuthExceptionInterface;

final class OAuthPresenter extends Presenter
{
    use OAuthPresenterTrait;
 
    protected function onAuthorizationRedirectFailed(string $flowName, OAuthExceptionInterface $error): void
    {
        $this->flashMessage('Authentication failed', 'error');
        $this->redirect('SignIn:');
    }

    abstract protected function onAuthenticationFailed(string $flowName, OAuthExceptionInterface $error): void
    {
        $this->flashMessage('Authentication failed', 'error');
        $this->redirect('SignIn:');
    }

    abstract protected function onUserAuthenticated(string $flowName): void
    {
        $this->flashMessage('You have been successfully logged in', 'success');
        $this->redirect('Homepage:');
    }
}

Login button

The login button can be rendered simply as follows

<a n:href="OAuth:authorize, type => 'azure'">Login via Azure</a>

If you store the request (back link) using Presenter::storeRequest() you can also pass it the URL. Your OAuthPresenter will then automatically redirect to this link after successful authentication.

<a n:href="OAuth:authorize, type => 'azure', backLink => $backLink">Login via Azure</a>

License

The package is distributed under the MIT License. See LICENSE for more information.