Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to get user's Authorization Codes for OAuth, directly from Azure AD and without a web browser redirect? #236

Open
paladini opened this issue Sep 22, 2022 · 5 comments

Comments

@paladini
Copy link

Hey @Garethp , I've seen some of your code examples like https://github.com/Garethp/php-ews/blob/master/examples/basic/authenticatingWithOAuth.php and I would like to thank you so much for implementing OAuth for this old Microsoft API (EWS). However, I've a specific case in which I need to do OAuth in behalf of an user from an Azure Active Directory (Azure AD) registered under a specific tenant. It must be done from our back-end application that users has no interactions at all, so I cannot redirect the user to an OAuth permission page like usually we would make. I need to get the users permissions (or the user's authorization token) by other way.

Possibilities

I've seen that we can request authorization code from MSAL client to get tokens (also 2 ). I'm not sure if there's a way to get authenticating codes via MSAL by using EWS or if it's only possible through Graph API.

It's possible to do that from your library? Can you give some instructions or example code? I know that I may be asking too much, but kind of confused yet about all these APIs and ways of retrieving authorization codes to use in OAuth in your library.

Notes

Note: when I'm saying authorization codes that are needed for OAuth, I'm talking about those from this variable 'code':

@paladini paladini changed the title Is it possible Is it possible to get user's Authorization Codes for OAuth, directly from Azure AD and without a web browser redirect? Sep 22, 2022
@Garethp
Copy link
Owner

Garethp commented Sep 22, 2022

This answer may not be helpful, but it may be possible to do what you're asking. I can't comment on MSAL as I've not heard of it before, but the second link is explicitly about EWS so it should be possible to implement the "Get a token with app-only auth" example from it. The problem here is that they're only giving an example in C# with their Managed API which makes it quite difficult to figure out how to do that.

This library acts as somewhat thing wrapper around Microsoft's SOAP service, it's why the Manual Usage example in the README looks the way it does, it gets translated to XML in a very similar shape (This is the documentation for the CreateItem call that the "Manual Usage" section is using). So as long as you can find an XML/SOAP example of doing things, making it work in this library shouldn't be too difficult.

Usually their examples that use the Managed API are also accompanied by similar documentation for their SOAP service, this is a good example of them showing how to do things in both C# and XML.

While the example that you posted doesn't have any XML accompanying it, I would guess that it also uses the SOAP XML service under the hood (though I can't be sure), so there should be a way of making the same calls but I can't tell you how. If you're able to find out how to do it with XML, I can help show you how to do it with this library and maybe even add it as a function to this library.

@paladini
Copy link
Author

Thank you so much for this fast reply, @Garethp ! I'm really hurrying here because MS is going to drop the Basic Auth very soon.

This answer may not be helpful, but it may be possible to do what you're asking. I can't comment on MSAL as I've not heard of it before, but the second link is explicitly about EWS so it should be possible to implement the "Get a token with app-only auth" example from it. The problem here is that they're only giving an example in C# with their Managed API which makes it quite difficult to figure out how to do that.

This library acts as somewhat thing wrapper around Microsoft's SOAP service, it's why the Manual Usage example in the README looks the way it does, it gets translated to XML in a very similar shape (This is the documentation for the CreateItem call that the "Manual Usage" section is using). So as long as you can find an XML/SOAP example of doing things, making it work in this library shouldn't be too difficult.

Usually their examples that use the Managed API are also accompanied by similar documentation for their SOAP service, this is a good example of them showing how to do things in both C# and XML.

While the example that you posted doesn't have any XML accompanying it, I would guess that it also uses the SOAP XML service under the hood (though I can't be sure), so there should be a way of making the same calls but I can't tell you how. If you're able to find out how to do it with XML, I can help show you how to do it with this library and maybe even add it as a function to this library.

So currently your implementation for OAuth only works for users giving their explicit permission by a web browser redirect? There's some other way I haven't mentioned here that may help me do the same as from your example (without improving your lib's code) but having the authorization from Azure AD to access resources from all users registered in it?

@lilhater
Copy link

lilhater commented Oct 4, 2022

How did you go with this @paladini?
I would also like a way to get a token without the users being prompted for a login.

@j-applese3d
Copy link

j-applese3d commented Oct 26, 2022

I got it to work though I'm not sure what all the different settings on the Azure side were needed.
In my case, I'm using EWS to read calendar events for some meeting rooms, so if you are actually trying to login as someone else, this might not be helpful.
Anyways here's the PHP code I used:

function getO365Token(): string {
    // If we already have a user token, just return it
    if (file_exists('./token')) {
        $mod = filemtime('./token');
        $val = json_decode(file_get_contents('./token'), true);
        // Tokens are valid for one hour, after that it needs to be refreshed
        if ($mod + getInt($val['expires_in']) > time()) {
            logger("Token is still active.");
            return $val['access_token'];
        }
        logger("Token is expired. getting a new one! $mod + {$val['expires_in']} < " . time());
    }

    // \Curl is a custom wrapper class around php's curl functions.
    // you could achieve the same effect by doing a system `curl -X POST <url> --data '<data>'` call...
    $c = new \Curl(\Curl::TYPE_POST);
    $c->dontDecode();
    $c->setBody(
        "grant_type=client_credentials" .
        "&client_id=" . EWS_AZURE_CLIENT_ID .
        "&client_secret=" . EWS_AZURE_CLIENT_SECRET .
        "&scope=https://outlook.office365.com/.default"
    );
    $c->setUrl("https://login.microsoftonline.com/" . EWS_AZURE_TENANT_ID . "/oauth2/v2.0/token");
    $resp = $c->exec();

    file_put_contents('./token', $resp);
    return json_decode($resp, true)['access_token'];
}


$ews = API::withCallbackToken('outlook.office365.com', getO365Token(), [
    'impersonation' => $emailAddress,
]);
// use like normal
$r = $ews->getClient()->GetUserOofSettings($request);

Hopefully, this is helpful.

@muhamadnazmi99
Copy link

I got it to work though I'm not sure what all the different settings on the Azure side were needed. In my case, I'm using EWS to read calendar events for some meeting rooms, so if you are actually trying to login as someone else, this might not be helpful. Anyways here's the PHP code I used:

function getO365Token(): string {
    // If we already have a user token, just return it
    if (file_exists('./token')) {
        $mod = filemtime('./token');
        $val = json_decode(file_get_contents('./token'), true);
        // Tokens are valid for one hour, after that it needs to be refreshed
        if ($mod + getInt($val['expires_in']) > time()) {
            logger("Token is still active.");
            return $val['access_token'];
        }
        logger("Token is expired. getting a new one! $mod + {$val['expires_in']} < " . time());
    }

    // \Curl is a custom wrapper class around php's curl functions.
    // you could achieve the same effect by doing a system `curl -X POST <url> --data '<data>'` call...
    $c = new \Curl(\Curl::TYPE_POST);
    $c->dontDecode();
    $c->setBody(
        "grant_type=client_credentials" .
        "&client_id=" . EWS_AZURE_CLIENT_ID .
        "&client_secret=" . EWS_AZURE_CLIENT_SECRET .
        "&scope=https://outlook.office365.com/.default"
    );
    $c->setUrl("https://login.microsoftonline.com/" . EWS_AZURE_TENANT_ID . "/oauth2/v2.0/token");
    $resp = $c->exec();

    file_put_contents('./token', $resp);
    return json_decode($resp, true)['access_token'];
}


$ews = API::withCallbackToken('outlook.office365.com', getO365Token(), [
    'impersonation' => $emailAddress,
]);
// use like normal
$r = $ews->getClient()->GetUserOofSettings($request);

Hopefully, this is helpful.

can i see the custom curl class. I dont understand about curl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants