Securing my Symfony API with Azure & call Graph

Viewed 49

I did an SPA that gets an access token from Azure, and an API with which I need to securely communicate. My users are Azure ones so I followed these Microsoft instructions to register the API and the related scopes.

          Custom                  Custom
           SPA       AzureAD       API        Graph
          ──┼───────────┼───────────┼───────────┼──
            │           │           │           │
Access      │ ────────> │           │           │
Token       │ <──────── │           │           │
            │           │           │           │
Access some │ ────────────────────> │           │
resource    │           │           │           │
            │           │           │           │
Check the   │           │ <──────── │           │
token       │           │ ────────> │           │     ╮  Both things
            │           │           │           │     │  I need to do
Get info    │           │           │ ────────> │     ╯  with Symfony
about the user          │           │ <──────── │
            │           │           │           │
Return the  │ <──────────────────── │           │
resource    │           │           │           │

Now I need to validate the token from the API with php (Symfony 4) and eventually get some info about the user with Graph on behalf of him.

I guess there are plenty of Symfony bundles there to help me do that, I'd like to avoid reinventing the wheel and I guess I should use the "On Behalf Of" flow, am I right ?

So my question is: Can someone point me to some known bundles and some examples ? Should I do an authenticator guard ?

1 Answers

thenetworg/oauth2-azure's wiki helped me with that

I've finally created an authentication guard for which the interesting part relies on the getCredentials():

public function getCredentials(Request $request)
{
    $accessToken = explode(' ', $request->headers->get($this->tokenHeader))[1];

    // Gets the latest signature keys from Microsoft
    $keys = (new Azure())->getJwtVerificationKeys();

    // Validates and returns the decoded token
    return (array)JWT::decode($accessToken, $keys, ['RS256']);
}

My full authenticator is available in this gist

The Azure class can be found in thenetworg/oauth2-azure package and JWT comes from firebase/php-jwt (which is a dependency of the former)

Signature keys from Microsoft are cached following the official recommendations, I'm talking about it in a related issue

// First tries to use the standard cached keys, then falls back on a shorter
// cache (if signature check failed) which forces the "long" cache refresh
foreach ([0, 1] as $try) {
    $firstTry = $try === 0;
    try {
        $keys = $firstTry ? $this->getKeys() : $this->getKeysShort();
        return (array)JWT::decode($accessToken, $keys);
    } catch (SignatureInvalidException $e) {
        if ($firstTry) continue;
        throw $e;
    }
}

Check the implementation of getKeys functions in the gist

Related