alancting/oauth2-microsoft-openid

Microsoft Azure Active Directory (Azure AD), Microsoft Active Directory Federation Services (ADFS) OpenId Integration for Symfony

1.0.2 2020-11-10 12:54 UTC

This package is auto-updated.

Last update: 2024-04-10 20:31:54 UTC


README

Packagist GitHub Test Coverage Status GitHub license

Microsoft Adfs / AzureAD OpenId Integration for Symfony

Microsoft Azure Active Directory (Azure AD), Microsoft Active Directory Federation Services (Adfs) OpenId Integration for Symfony

  • Login with Adfs / AzureAd
    • All token handling is wrapped in the guard authenticator
  • Easy to get the stored tokens from a registered service

This bundle integrates with knpuniversity/oauth2-client-bundle

This package provides Microsoft OAuth 2.0 support for the PHP League's OAuth 2.0 Client.

Forked From stevenmaguire/oauth2-microsoft

Installation

To install, use composer:

composer require alancting/oauth2-microsoft-openid

Get Start

Step 1 - Include in the bundles

# config/bundles.php
return [
    Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
    ...
    Alancting\OAuth2\OpenId\Client\MicrosoftBundle::class => ['all' => true],
];

Step 2 - Configure the provider

We make use of the configuration from knpuniversity/oauth2-client-bundle

Adfs

# config/packages/knpu_oauth2_client.yaml
knpu_oauth2_client:
  clients:
    microsoft_openid:
      type: generic
      provider_class: Alancting\OAuth2\OpenId\Client\Provider\AdfsProvider
      client_class: Alancting\OAuth2\OpenId\Client\Client\AdfsClient
      client_id: "%env(ADFS_CLIENT_ID)%"
      client_secret: "%env(ADFS_CLIENT_SECRET)%"
      redirect_route: microsoft_openid_connect
      provider_options:
        hostname: "%env(ADFS_HOSTNAME)%"
        user_key: unique_name
        microsoft_resource_scopes:
          - profile
          - offline_access
        other_resource_scopes:
          - "%env(ADFS_API_RESOURCE_1)%"
          - "%env(ADFS_API_RESOURCE_2)%"

Azure Ad

# config/packages/knpu_oauth2_client.yaml
knpu_oauth2_client:
  clients:
    microsoft_openid:
      type: generic
      provider_class: Alancting\OAuth2\OpenId\Client\Provider\AzureAdProvider
      client_class: Alancting\OAuth2\OpenId\Client\Client\AzureAdClient
      client_id: "%env(AZURE_AD_CLIENT_ID)%"
      client_secret: "%env(AZURE_AD_CLIENT_SECRET)%"
      redirect_route: microsoft_openid_connect
      provider_options:
        tenant: "%env(AZURE_AD_TENANT)%"
        tenant_id: "%env(AZURE_AD_TENANT_ID)%"
        user_key: upn
        microsoft_resource_scopes:
          - profile
          - offline_access
        other_resource_scopes:
          - "%env(AZURE_AD_API_RESOURCE_1)%"
          - "%env(AZURE_AD_API_RESOURCE_2)%"

Step 3 - Configure the use authenticator

Adfs

# config/packages/security.yaml
security:
  providers:
    microsoft_openid_oauth:
      id: alancting.microsoft.user_provider
  firewalls:
    secure_firewall:
        pattern: ^/([a-z])
          anonymous: ~
          logout:
            path: microsoft_openid_logout
            success_handler: App\Utility\LogoutHandler
          guard:
            provider: microsoft_openid_oauth
            authenticators:
              - alancting.microsoft.adfs.authenticator

Azure Ad

# config/packages/security.yaml
security:
  providers:
    microsoft_openid_oauth:
      id: alancting.microsoft.user_provider
  firewalls:
    secure_firewall:
        pattern: ^/([a-z])
          anonymous: ~
          logout:
            path: microsoft_openid_logout
            success_handler: App\Utility\LogoutHandler
          guard:
            provider: microsoft_openid_oauth
            authenticators:
              - alancting.microsoft.azure_ad.authenticator

Step 4 - Register pathsserver

We need to register two path to communicate with the OAuth2 server

  1. connect
  2. logout

Adfs

namespace App\Controller;

use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;

class AdfsController extends AbstractController
{
    /**
     * After going to microsoft, you're redirected back here
     * because this is the "redirect_route" you configured
     * in config/packages/knpu_oauth2_client.yaml
     *
     * @Route("/adfs/connect", name="microsoft_openid_connect")
     */
    public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
    {
        return new Response();
    }

    /**
     * After going to microsoft, you're redirected back here
     * because this is the "redirect_route" you configured
     * in config/packages/knpu_oauth2_client.yaml
     *
     * @Route("/adfs/logout", name="microsoft_openid_logout")
     */
    public function logoutAction(Request $request, ClientRegistry $clientRegistry)
    {
        return new Response();
    }
}

Azure Ad

namespace App\Controller;

use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;

class AzureAdController extends AbstractController
{
    /**
     * After going to microsoft, you're redirected back here
     * because this is the "redirect_route" you configured
     * in config/packages/knpu_oauth2_client.yaml
     *
     * @Route("/azure_ad/connect", name="microsoft_openid_connect")
     */
    public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
    {
        return new Response();
    }

    /**
     * After going to microsoft, you're redirected back here
     * because this is the "redirect_route" you configured
     * in config/packages/knpu_oauth2_client.yaml
     *
     * @Route("/azure_ad/logout", name="microsoft_openid_logout")
     */
    public function logoutAction(Request $request, ClientRegistry $clientRegistry)
    {
        return new Response();
    }
}

Usage

After user login,

  • You can get the login credentials
  • User is logged in with the roles: ROLE_USER and ROLE_OAUTH_USER

Adfs

use Alancting\OAuth2\OpenId\Client\Client\AdfsClient;

public index(AdfsClient $adfsClient)
{
    /**
     * Get credential for main scope
     */
    $mainScopeCredential = $adfsClient->getOAuthCredential();

    // Get access token
    $accessToken = $mainScopeCredential->getAccessToken();
    // Get id token
    $idTokenJWT = $mainScopeCredential->getIdTokenJWT();
    // Get id token payload
    $idTokenPayload = $idTokenJWT->getPayload();
    // Get value for a specific attr from id token payload
    $idTokenPayloadAttr1 = $idTokenJWT->get('attr1');

    /**
     * If have other resource scopes, you can loop to fetch credentials for other scopes
     */
    $otherScopeCredentials = [];
    foreach ($mainScopeCredential->getOtherResourceCredentials() as $scope => $credential) {
        $otherScopeCredentials[$scope] = $credential;
    }

    /**
     * You can also get the credential from scope name by
     */
    $otherScopeCredential = $mainScopeCredential->getOtherResourceCredential('other_scope_name');
}

Azure Ad

use Alancting\OAuth2\OpenId\Client\Client\AzureAdClient;

public index(AzureAdClient $azureAdClient)
{
    /**
     * Get credential for main scope
     */
    $mainScopeCredential = $azureAdClient->getOAuthCredential();

    // Get access token
    $accessToken = $mainScopeCredential->getAccessToken();
    // Get id token
    $idTokenJWT = $mainScopeCredential->getIdTokenJWT();
    // Get id token payload
    $idTokenPayload = $idTokenJWT->getPayload();
    // Get value for a specific attr from id token payload
    $idTokenPayloadAttr1 = $idTokenJWT->get('attr1');

    /**
     * If have other resource scopes, you can loop to fetch credentials for other scopes
     */
    $otherScopeCredentials = [];
    foreach ($mainScopeCredential->getOtherResourceCredentials() as $scope => $credential) {
        $otherScopeCredentials[$scope] = $credential;
    }

    /**
     * You can also get the credential from scope name by
     */
    $otherScopeCredential = $mainScopeCredential->getOtherResourceCredential('other_scope_name');
}

Logout Handling

In symfony, to logout a user, you should use

  • 4.4: Logout success handler
  • 5.x+: Logout event

After your app go to logout handler / event, you should redirect user to the Adfs / Azure AD logout Url, you can get the url by

// Logout url for Adfs
$logoutUrl = $adfsClient->getLogoutUrl();

// Logout url for Azure Ad
$logoutUrl = $azureAdClient->getLogoutUrl();

Tests

Run the tests using phpunit:

$ composer install
$ composer run test

Contributing

Please see CONTRIBUTING for details.

Credits

License

The MIT License (MIT). Please see License File for more information.