Skip to content
This repository has been archived by the owner on Jan 20, 2024. It is now read-only.

OAuth 2.0 support #138

Open
danniehansen opened this issue Apr 15, 2019 · 23 comments
Open

OAuth 2.0 support #138

danniehansen opened this issue Apr 15, 2019 · 23 comments

Comments

@danniehansen
Copy link

danniehansen commented Apr 15, 2019

Hi,

Looks like SalesForce Marketing Cloud soon defaults to OAuth 2.0 without the possibility of using legacy authentication https://jmp.sh/tcbTj8c

Is there any plan to support packages created using OAuth 2.0? Currently getting: https://jmp.sh/5jdmXSk & is unable to find any documentation that would allow me to use OAuth 2.0

@danniehansen danniehansen changed the title Oauth 2.0 support OAuth 2.0 support Apr 15, 2019
@adjc98
Copy link

adjc98 commented Apr 16, 2019

I second that. This SDK will be deprecated in starting August of this year. Although legacy apps will still work. Any new apps created will not work with this SDK starting in August. Anyone looking into this? We just started using Salesforce Marketing Cloud a few days ago.

@jonathandezoete
Copy link

with a few tweaks i was able to fetch the access token in the sdk. REST is working, however my token is not accepted for SOAP:
SOAP Authorization failed for Oauth token: XXXXXXXXXX. Reason: ParseError.

i wonder if the problem is that an access token is nu the same as an oauth token (should be right?), or something else is wrong..
i can make a pull request if i get the connection working. Any indicators are welcome

@jonathandezoete
Copy link

jonathandezoete commented Apr 19, 2019

the following xml envelope is created:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:ns1="http://exacttarget.com/wsdl/partnerAPI">
    <SOAP-ENV:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                       SOAP-ENV:mustUnderstand="1">
            <wsse:UsernameToken>
                <wsse:Username>*</wsse:Username>
                <wsse:Password
                        Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
                    *
                </wsse:Password>
                <wsse:Nonce>R8Wv/0QcgbmTyVVNdMCpYPLWsoTWqfUzfLT+IemzB64=</wsse:Nonce>
                <wsu:Created
                        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                    2019-04-19T09:05:32Z
                </wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
        <oAuth xmlns="http://exacttarget.com">
            <oAuthToken>
                XXXX
            </oAuthToken>
        </oAuth>
    </SOAP-ENV:Header>
    <SOAP-ENV:Body>
        <ns1:DefinitionRequestMsg>
            <ns1:DescribeRequests>
                <ns1:ObjectDefinitionRequest>
                    <ns1:ObjectType>List</ns1:ObjectType>
                </ns1:ObjectDefinitionRequest>
            </ns1:DescribeRequests>
        </ns1:DefinitionRequestMsg>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

@adjc98
Copy link

adjc98 commented Apr 22, 2019

Same here, I am getting the OAuth 2.0 token no problem and Rest is working fine. I am still trying to get it to work with Soap. I am using the Client ID and Client Secret from an installed pacakage instead of a username and password.

@will-ashworth
Copy link

will-ashworth commented Apr 23, 2019

I'm in the same boat. Hopefully there's a solution. I need to read/write to a data extension.

@jonathandezoete
Copy link

jonathandezoete commented Apr 23, 2019

Got a successful login with this envelope (make sure the request goes to soap endpoint):

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:ns1="http://exacttarget.com/wsdl/partnerAPI">
<SOAP-ENV:Header>
    <fueloauth xmlns="http://exacttarget.com">
        XXXXXXXX
    </fueloauth>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
    <ns1:DefinitionRequestMsg>
        <ns1:DescribeRequests>
            <ns1:ObjectDefinitionRequest>
                <ns1:ObjectType>List</ns1:ObjectType>
            </ns1:ObjectDefinitionRequest>
        </ns1:DescribeRequests>
    </ns1:DefinitionRequestMsg>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

now lets see if i can cleanly override the client.

@will-ashworth
Copy link

Thank you @jonathandezoete

Any idea if there are any examples of making the requests the newer way in Postman or PHP? Right now, the SDK is dead to me without proper authentication (unless I'm missing something obvious), and I'm willing to custom code something, but having a hard time locating examples of a working authentication scheme for the OAuth 2.0 stuff in Postman while testing queries against the endpoints.

We're doing everything through Marketing Cloud (formerly Exact Target), so I think I'm asking this in the right place.

@jonathandezoete
Copy link

Hi @will-ashworth

You can use the SDK no problem, just change the client. Havent had the time to do a clean fork, but if you substitute the ET_Client with the attached client php file.
Then you can make a SOAP call like this:

$client = new SQZL_ET_Client(true, false,
    [
        "baseUrl" => '..',
        "baseAuthUrl" => '..',
        'baseSoapUrl' => '..',
        'appsignature' => 'none',
        "clientid" => '..',
        "clientsecret" => '..',
        "sdl" => 0
    ]);
$client->setInternalAuthToken('', "**ACCESS_TOKEN**");

$getList = new ET_List();
$getList->authStub = $client;
$getResponse = $getList->get();

SQZL_ET_Client.zip

For REST calls i just use guzzle.

@garek007
Copy link

@jonathandezoete this is pretty cool, how much of the ET_Client did you have to modify?

@jonathandezoete
Copy link

Not so much. See for yourself: https://www.diffnow.com/report/38kdi

@garek007
Copy link

garek007 commented Apr 25, 2019

@jonathandezoete I dropped this file into the src folder, but I don't think it's autoloading. I see that your namespace is different. Is this meant to be put into another directory? Update. I ended up changing the namespace to FuelSdk since it's dropped in the same folder. You have a different class name so no need to create a new namspace. I'm guessing when you posted that it's plucked straight out of a project you're working on. Now I'm getting a new error.

Undefined index: tenantKey in C:\wamp64\www\fuel-project\vendor\salesforce-mc\fuel-sdk-php\src\SQZL_ET_Client.php on line 75

Ok I got that fixed by adding a parameter to the function call and just set tenantKey to "whatever". I'm not sure what that's used for. So I also wasn't sure where to set the default WSDL save location so I set the first parameter to false. I had to change line 79 to use my specific wsdl endpoint with the specific stack so

https://webservice.s7.exacttarget.com/etframework.wsdl

So it seems that things are getting passed without failure, but I still don't think I'm connecting. I do a var_dump of $client and I don't see anything like an access token in there. I also don't know what to do with the next line

$client->setInternalAuthToken('', "ACCESS_TOKEN");

@jonathandezoete
Copy link

@garek007 correct, didnt do anything besides copy it ;)
The error you see is because the sdk has "== null" statements rather than a "!isset". I don't know why.
I worked around that by setting the $this->tenantKey = $params['tenantKey']; in the changed class constructor. you can also just update the statements.

@jonathandezoete
Copy link

the wdsl is fine. you should first get your access token and put that with the setInternalAuthToken().
you can get it with guzzle. try something like this:

                $api = new Client();
                $result = $api->request('POST', $auth_url . '/v2/token' , ['json' => ['client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => "client_credentials"]]);
                $tokenInfo = json_decode($result->getBody()->getContents(), true);
                $this->currentAccessToken = $tokenInfo['access_token'];

@garek007
Copy link

Thanks @jonathandezoete I think I see what you're doing here. A few more questions and some things I don't understand.

If I am using Guzzle and passing client_id and client_secret to the auth URL and then getting a token that I can then use in client, what would I still need to make the new SQZL_ET_Client call? I understand that I need to construct the object but I guess I'm wondering why we also need to pass the credentials to it as well? Seems like we're already doing it once with Guzzle.

Secondly, I've been just instantiating a new object all over the place. I know this is not recommended, but I'm not sure how to simply reuse the access token for subsequent calls.

@garek007
Copy link

Ok so I was able to connect using the code below and the getList request worked.

<?php
require __DIR__ . '/vendor/autoload.php';
use FuelSdk\ET_Client;
use FuelSdk\SQZL_ET_Client;
use FuelSdk\ET_List;
use GuzzleHttp\Client;

//Next, create an instance of the ET_Client class:
$auth_url = 'https://mcvszr8q726sp9j-0n98r70tppp1.auth.marketingcloudapis.com/';
$clientId = 'shhhhSecret';
$clientSecret = 'shhhhSecret';

$api = new Client();
$result = $api->request('POST', $auth_url . '/v2/token' , ['json' => ['client_id' => $clientId, 'client_secret' => $clientSecret, 'grant_type' => "client_credentials"]]);
$tokenInfo = json_decode($result->getBody()->getContents(), true);


$myclient = new SQZL_ET_Client(false, false,
  [
      "baseUrl" => 'https://mcvszr8q726sp9j-0n98r70tppp1.auth.marketingcloudapis.com/',
      "baseAuthUrl" => 'https://mcvszr8q726sp9j-0n98r70tppp1.auth.marketingcloudapis.com/',
      'baseSoapUrl' => 'https://mcvszr8q726sp9j-0n98r70tppp1.soap.marketingcloudapis.com/',
      'appsignature' => 'none',
      "clientid" => 'shhhhSecret',
      "clientsecret" => 'shhhhSecret',
      "sdl" => 0
  ]);


$myclient->setInternalAuthToken('', $tokenInfo['access_token']);


$getList = new ET_List();

$getList->authStub = $myclient;

$getResponse = $getList->get();

var_dump($getResponse);

This is awesome @jonathandezoete thanks for sending this. The thing I still don't get, is why am I getting this error

Notice: Undefined index: tenantKey in C:\wamp64\www\fuel-project\vendor\salesforce-mc\fuel-sdk-php\src\SQZL_ET_Client.php on line 75

and how do I persist my authorization for subsequent calls (ie page to page) without instantiating a new object each time?

@jonathandezoete
Copy link

My colleague tidied things up a bit:

ET_Client.zip

@garek007 Thats probably because you are using a different tenantkey than is used in the constructor (the previously mentioned == null comparison).
For saving the token you can just reuse the $myclient. for saving the token you can put it in a local var, use your own caching mechanism or implement the ET_CacheService from the original client.

@garek007
Copy link

Thanks @jonathandezoete !

@pfortin-expertime
Copy link

pfortin-expertime commented May 14, 2019

Thanks a lot @jonathandezoete and @garek007 !

But now I have this issue when I try to get list : $getResponse = $getList->get();

Could not resolve host: Service.asmx

Do you have the same error ?

@pfortin-expertime
Copy link

Update: the baseSoapUrl wasn't correct

pfortin-expertime added a commit to pfortin-expertime/FuelSDK-PHP that referenced this issue May 15, 2019
@pfortin-expertime
Copy link

pfortin-expertime commented May 16, 2019

Hi guys,

I've created a fork here (please use v1.2.4) based on the branch Oauth2Implementation thanks to the work of @sfcbetiuc

All you have to do is pass a new parameter "useOAuth2Authentication" and set true as value.

        $params = [
            "clientid" => XXXX,
            "clientsecret" => XXXXX,
            'appsignature' => 'none',
            "sdl" => 0,
            "xmlloc" => $xmlloc,
            "tenantKey" => "yourwhateverkey",
            "useOAuth2Authentication" => 'true'
        ];

        $client = new ET_Client(false, false, $params);

@garek007
Copy link

this is awesome! thanks @pfortin-expertime

@adjc98
Copy link

adjc98 commented May 16, 2019

That's awesome! Anyway we can get it merged into this repository?

@garek007
Copy link

3 years later and I find this. I'm doing well with the api, but looking at ET_Client.php and I can't figure out for the life of me what tenantKey is supposed to be. I've tried it with my subdomain, MID, nothing works. Looking at ET_Client.php I don't even see how/where it is set.

Regarding the if ($this->tenantTokens[$tenantKey] == null) statements, I did change at least one to isset() in my forked repo.

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

No branches or pull requests

6 participants