TheNetworg / oauth2-azure

Azure AD provider for the OAuth 2.0 Client.
https://packagist.org/packages/thenetworg/oauth2-azure
MIT License
231 stars 108 forks source link

Cant get the resource owner #104

Closed NormySan closed 4 years ago

NormySan commented 4 years ago

I've got a frontend application that logs in with Azure through the MSAL JavaScript package using the version 2 API. I then make requests against a Symfony application where I've implemented this package inside of a custom authenticator.

But I'm having issues creating the access token and getting the resource owner, the problem seems to be related to there not being idToken or idTokenClaims properties on the created access token.

When inspecting the resource owner (account) in the frontend there definitely is both id token and id token claims as a part of the token but this somehow never gets picked up when using the same token in the backend with this library.

This is a snippet of the code I have attempting to get the resource owner based in the bearer token from the authentication header, the token is the credentials variable.

$accessToken = $this->azure->getAccessToken('jwt_bearer', [
    'scope' => 'User.Read',
    'assertion' => $credentials,
    'requested_token_use' => 'on_behalf_of',
]);

$owner = $this->azure->getResourceOwner($accessToken);

Maybe I'm doing something wrong here and should be calling different methods? I've tried to find where the problem could be located but it's super hard to navigate the code base when not really knowing what to look for.

NormySan commented 4 years ago

So I got this working after manually doing the required calls to get the token from the OAuth API and the credentials from the Graph API.

The following are the requests I did with the help of Guzzle, maybe this can be of help to someone else facing the same issues.

$client = new Client();

$tokenResponse = $client->post('https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token', [
    'form_params' => [
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'client_id' => '<client-id>',
        'client_secret' => '<client-secret>',
        'assertion' => $credentials,
        'scope' => 'https://graph.microsoft.com/user.read offline_access',
        'requested_token_use' => 'on_behalf_of',
    ],
]);

$token = json_decode($tokenResponse->getBody()->getContents());

$graphResponse = $client->get('https://graph.microsoft.com/v1.0/me', [
    'headers' => [
        'Authorization' => "Bearer {$token->access_token}",
    ],
]);

$me = json_decode($graphResponse->getBody()->getContents());
hajekj commented 4 years ago

Right. This is happening, because id_token is returned only to the user's application, but whenever you receive it on API, you should look into the Bearer token for claims first - I wouldn't call Microsoft Graph in this case - with each request especially - it seems quite excessive, if you just need the values from the token.

What you should use instead is following way: https://github.com/TheNetworg/oauth2-azure#protecting-your-api---experimental

tldr; parse the token and use the claims from it.

NormySan commented 4 years ago

You're right, I only need the get the user data on the very first request to the API to create the user in the database.

I'll give the provided example another try and see if it works to get the user this time around.

Thanks for your reply!

NormySan commented 4 years ago

I've implemented the example in the readme and everything works great. I also learned that you can include additional data with the token with some configuration in the Azure Portal so the token now includes all the data required without having to call the Graph API :)