Trouble getting Authorization Code programatically

Forum for users and developers of Bullhorn's new REST API service.

Moderators: StaffingSupport, s.emmons, BullhornSupport

Post Reply
cubicbrent
User
Posts: 2
Joined: Wed Jan 10, 2018 11:29 am

Trouble getting Authorization Code programatically

Post by cubicbrent » Wed Feb 14, 2018 12:33 pm

Hello Support - hopefully someone can help me out here, as I've been banging my head against this brick wall for a couple of days.

I cannot for the live of me figure out how to get this code programatically. I can get the code just fine in Postman after manually logging in, but not in the browser or via code.

https://auth.bullhornstaffing.com/oauth ... _type=code
&redirect_uri={optional redirect_uri}&state={recommended state value}&username={username}&password={password}&action=Login is the URL I am trying to use.

If I just do the basic URL without the login action and I manually login via the browser (https://auth.bullhornstaffing.com/oauth ... _type=code) I get this error "Authorization Code not received", but there is a callback code in the URL at that time.

However, using Postman and logging in when prompted spits out a code just fine. I just need this process automated!

I am using PHP for my code. Any help would be greatly appreciated, this is urgent and I am struggling!

scaffrey
User
Posts: 3
Joined: Fri Feb 03, 2017 9:02 am

Re: Trouble getting Authorization Code programatically

Post by scaffrey » Mon Feb 19, 2018 10:02 am

Hi, since you are able to run the API authorisation successfully but are having issues translating this into an automated PHP process Bullhorn Support would not be able to assist with this.

Apologies that I could not provide you with an answer, I would suggest that perhaps a PHP forum would better serve your needs.
Bullhorn Support UK: 44 800 032 2848
Bullhorn Support US: 1 617-478-9126
Bullhorn Support Australia: 61 28 073 5089
Bullhorn Support International: 1 617-478-9131

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Mon Mar 19, 2018 5:21 pm

Any progress yet?

The secret is to use the curl -V url in the docs and make sure:
1) you don't follow the redirect, and
2) you get headers.

In my codebase that means I have to make sure:

Code: Select all

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_MAXREDIRS, 0);
curl_setopt($ch, CURLOPT_HEADER=>true);
The code is in the initial response but not in the redirect (which is usually http://www.bullhorn.com).

Step 1:

Code: Select all

https://auth.bullhornstaffing.com/oauth/authorize?client_id={client_id}&response_type=code
&redirect_uri={optional redirect_uri}&state={recommended state value}&username={username}&password={password}&action=Login
So set your curl options to not follow redirects, then parse the response and take the substring before the HTML stuff starts. That substring holds the headers.

Then parse your headers to pull out the code.

I use the following:

Code: Select all

//...$authResponse is what I get back from calling Step 1 via curl...
$html_start = strpos($authResponse, '<!DOCTYPE html>');
$headers = substr($authResponse, 0, $html_start);
if (preg_match("|Location: (https?://\S+)|", $headers, $m)) {
			//Location is in $m[1]
			if (preg_match("|code=(\S+)\&client_id|", $m[1], $n)) {
				$code = urldecode($n[1]);
And then I use the code to ask for a refresh token using the next step (Step 2):

Code: Select all

https://auth.bullhornstaffing.com/oauth/token?grant_type=authorization_code&code={auth_code}&client_id={client_id}&client_secret={client_secret}&redirect_uri={optional redirect_uri}
You're going to get back a response with an access token and a refresh token.
Store the refresh token for the next login (so you don't have to go through the authorize process again) and the access token to use immediately.

Step 3:

Code: Select all

https://rest.bullhornstaffing.com/rest-services/login?version=2.0&access_token={xxxxxxxx}
That call gets you your BhRestToken which you can attach to all subsequent calls to validate your login. When it expires, just use the refresh token to ask for another access token (Step 4):

Code: Select all

https://auth.bullhornstaffing.com/oauth/token?grant_type=refresh_token&refresh_token={refresh_token}&client_id={client_id}&client_secret={client_secret}
That returns you an access token, so you can go back to step 3 with your new access token and get a new BhRestToken.

That process took me a long time to get right, but as long as I have proper credentials from my client (client_id, client_secret, username, password) I just plug in the right values and don't think about logging in any more.

I'm coming back to this code because I'm setting up a new client. Hopefully this post is helpful.

Dave Block
North Creek Consulting, Inc.

fcdjohn
User
Posts: 1
Joined: Mon Mar 26, 2018 1:11 pm

Re: Trouble getting Authorization Code programatically

Post by fcdjohn » Mon Mar 26, 2018 3:24 pm

Dave,

Are you sure that this method is still working? It seems like for the most part as far as the auth code it's the right idea, but for some reason, it doesn't seem to work. Curl does return what you're outlining, but the headers don't contain relevant info, and it's actually returning the HTML to the consent page. Does that sound about right? This isn't terribly well documented other than a couple lines in the docs.


--John

shughesoptimumhit
User
Posts: 3
Joined: Thu Mar 29, 2018 1:30 pm

Re: Trouble getting Authorization Code programatically

Post by shughesoptimumhit » Thu Mar 29, 2018 1:33 pm

I am having the same issue fcdjohn is talking about. The documentation makes it seem as if one should expect a json response with the auth code but it instead returns html.

mbecke7
User
Posts: 1
Joined: Mon Apr 02, 2018 10:19 am

Re: Trouble getting Authorization Code programatically

Post by mbecke7 » Mon Apr 02, 2018 10:21 am

Has anyone been able to get this to work? I cannot get the authorization code programmtically before of the consent form.

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Mon May 21, 2018 7:42 pm

Hi people,

I've been working on non-Bullhorn projects for the past while, but I'm back at the coal face. It does seem like there have been changes, so I'll post what works as I fight through authorization with a new client here in this thread.

I tend to cheat if I can get through manually and steal the tokens from the URL - but I'll let you know if I can get that to work.

Dave
North Creek
Back into the Bullhorn World right now

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Tue May 22, 2018 1:51 pm

First issue with this client - I had to get my IP whitelisted with Bullhorn. That will be awkward as we move from my test box to staging, to production, but hopefully it won't take long to add an IP to an account somewhere.

Bullhorn Support- is there a way a customer can add their developer's IP address to their account somewhere so this step doesn't have to go through you?

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Wed May 23, 2018 12:23 pm

Got some help from support - my client is in the EMEA zone, so I had to add that to the urls (auth-emea and rest-emea) and I was able to get a manual login to the point where I got an authorization code.

The next step is to use the code to get an access token using

Code: Select all

https://auth.bullhornstaffing.com/oauth/token?grant_type=authorization_code&code={auth_code}&client_id={client_id}&client_secret={client_secret}&redirect_uri={optional redirect_uri}
(straight from the docs).

This is returning me

Code: Select all

[
  ["error"]=>
  string(13) "invalid_grant"
  ["error_description"]=>
  string(48) "Invalid, expired, or revoked authorization code."
]
(using auth-emea instead of auth in the url).

I'll keep updating here as I make progress.

It really appears they have shut down the automated login uri.

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Wed May 23, 2018 3:02 pm

Okay, I'm now able to log in (using the manual step to log in initially, and then storing the auth code I received from that step).

The issue was the difference between the automatic login (where I was extracting the code from the data I received via curl in PHP) and the manual login (copy and paste from the browser bar).

In the manual step, I copied directly the code, and it had been url-encoded. Once I url-decoded the supplied code, it was accepted and I was able to carry on and log in.

A support ticket has been generated through my client about the loss of the automated login workflow. I will update the forum with the result of that query.

In the meantime, if you copy/paste the code from the browser bar, remember to urldecode it!

Happy coding!
Dave
North Creek

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Mon Jun 11, 2018 10:57 am

Over the weekend my auth code expired, so the code did what it was programmed to do and tried to get a new auth code programatically.

As we seem to have confirmed, that option seems to have been removed and so I needed to log in manually again in order to get a new auth code.

Thankfully, after my previous work, that auth code was good enough to restart the rest of the process and so my client's code is back running again.

*This is a problem, Bullhorn*. We can't have clients who depend on our integration code having to manually log in every 2-3 weeks in order to use the REST API.

I will be asking my client to open up a support ticket asking for a better resolution to this.

DaveNorthCreek
User
Posts: 89
Joined: Fri Nov 20, 2015 2:04 pm

Re: Trouble getting Authorization Code programatically

Post by DaveNorthCreek » Mon Jun 11, 2018 11:57 am

Curiouser and curiouser.

I was able to get a code from the following URI:

Code: Select all

https://auth-emea.bullhornstaffing.com/oauth/authorize?client_id={CLIENT_ID}&response_type=code&redirect_uri=http%3A%2F%2Fwww.bullhorn.com&state=random_string&username={USERNAME}&password={PASSWORD}&action=Login 
once I added in the redirect_uri parameter.

I got the expected headers

Code: Select all

HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Date: Mon, 11 Jun 2018 15:36:07 GMT
Location: https://www.bullhorn.com/?code={NEW_CODE}&client_id={CLIENT_ID}&state=random_string
But supplying this {NEW_CODE} to the next step

Code: Select all

https://auth-emea.bullhornstaffing.com/oauth/token?code=22%3A2c3fbe53-f268-44dd-adad-3366162852eb&client_id=cfa052e4-9556-44fd-88ad-43731c92fe6c&client_secret=rsAMtUcMcW2lnc1S2s9dLgxr&grant_type=authorization_code 
got me the following response:

Code: Select all

[2018-06-11 09:36:19] local.DEBUG: array(2) {
  ["error"]=>
  string(13) "invalid_grant"
  ["error_description"]=>
  string(22) "Mismatch redirect uri."
}
According to this post from 5 years ago:
viewtopic.php?f=104&t=14309&p=56385&hil ... uri#p56385

I can just remove the redirect_uri parameter from the request and things will work, but as I said at the beginning, the redirect_uri parameter was the missing piece that got the whole process to work.

****SO, I felt like I was back at square one, but I must have missed something*****

I ran the whole thing again without the redirect URI, and the problem was that my code was looking for a valid HTML body, but the change was that the server returns this:

Code: Select all

HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID={REDACTED}; Path=/oauth/; HttpOnly
Location: http://auth-emea.bullhornstaffing.com/oauth/207.228.78.97?code={CODE}&client_id={CLIENT_ID}&state=random_string
Content-Length: 0
Date: Mon, 11 Jun 2018 15:49:17 GMT

HTTP/1.1 502 Connection refused
Date: Mon, 11 Jun 2018 15:49:17 GMT
Connection: close
Cache-Control: no-store
Content-Type: text/html
Content-Language: en
Content-Length: 213

<HEAD><TITLE>Connection refused</TITLE></HEAD>
<BODY BGCOLOR="white" FGCOLOR="black">
<FONT FACE="Helvetica,Arial"><B>
 Connection refused</B></FONT>

<!-- default "Connection refused" response (502) -->
</BODY>
I had been looking for <!DOCTYPE html> as a signifier of the end of the headers but this 502 connection refused was just going straight to <HEAD>.

I changed my code to look for '<' (since there are no angle brackets in a valid header, right?) and everything started working again.

So it looks like the big change that messed me up (and apparently not only me) was the change in the response HTML away from the DOCTYPE declaration to just <HEAD>.

Handcrafted code is fragile - I will keep reporting if this breaks again.

Post Reply