OAuth2 client credentials implementations

NodeJS

function createAccessToken(apiKey, apiSecret, region = 'us') {
    return new Promise((resolve, reject) => {
        let credentials = Buffer.from(`${apiKey}:${apiSecret}`);

        const requestOptions = {
            host: `${region}.battle.net`,
            path: '/oauth/token',
            method: 'POST',
            headers: {
                'Authorization': `Basic ${credentials.toString('base64')}`,
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        };

        let responseData = '';

        function requestHandler(res) {
            res.on('data', (chunk) => {
                responseData += chunk;
            });
            res.on('end', () => {
                let data = JSON.parse(responseData);
                resolve(data);
            });
        }

        let request = require('https').request(requestOptions, requestHandler);
        request.write('grant_type=client_credentials');
        request.end();

        request.on('error', (error) => {
            reject(error);
        });
    });
}
5 Likes

I’m trying to get connected to the API for a school project (data visualization) but the project has to be with R. I have my client set-up, but can’t figure out how to get the access token. Can you assist?

Unfortunately no.

You might wanna try asking around the Community Discord Server. Maybe someone over there can help you.

EDIT: I thought it would take longer but it was actually easier than I anticipated. Here is a working function for retrieving the token:

R

require("httr")
require("jsonlite")

createAccessToken <- function(apiKey, apiSecret, region = "us") 
{
  response <- POST(
    paste("https://", region, ".battle.net/oauth/token", sep = ""),
    authenticate(apiKey, apiSecret),
    body = list(grant_type="client_credentials")
  )
  return(fromJSON(content(response, "text"), flatten = TRUE))
}
2 Likes

This page on accessing RESTful APIs using R might help:
hxxps://www.programmableweb.com/news/how-to-access-any-restful-api-using-r-language/how-to/2017/07/21

2 Likes

Thank you both! Now if I could get past the

Client error: (403) Forbidden

Problem…

Thanks for these, Schiller :smiley:

I was wondering if you had a PHP example for requesting Battle.net login/authorization for a user. I was trying tonight but had no luck.

I was trying to set it up using curl, as follows:

$curl_handle = curl_init();
try
{
  curl_setopt($curl_handle, CURLOPT_URL, "https://{$realm}.battle.net/oauth/authorize");
  curl_setopt($curl_handle, CURLOPT_POSTFIELDS, ['scope' => 'wow.profile']);
  curl_setopt($curl_handle, CURLOPT_POSTFIELDS, ['redirect_uri' => '<my redirect url>']);
  curl_setopt($curl_handle, CURLOPT_POSTFIELDS, ['response_type' => 'code']);
  curl_setopt($curl_handle, CURLOPT_USERPWD, $ClientID . ':' . $ClientSecret);
  curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl_handle, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);
  $response = curl_exec($curl_handle);
  $status = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
  
  if ($status !== 200)
  {
    throw new Exception('Failed to get Battle.net authorization.');
  }
  return;
}
finally
{
  curl_close($curl_handle);
}

Yes, I originally wrote this function for Feral’s php lib: blizzard_api/request_handler.php · master · David Matthew / Blizzard API PHP · GitLab

There are also helper functions for generating the sign in with bnet link in the same file.

1 Like

Thank you! I’ll check it out and can hopefully adapt it to my site :slight_smile:

Since I already have a lot of auth code in my pages I’d prefer to just adapt it rather than switch entirely to another lib, if I can.

I do not recommend the switching either, it is just a reference for PHP code. Hit me on discord if you need any help.

1 Like

Just checking, is it ok to include your client ID nakedly in the URL you’re using to request authorization? I know the Client ID isn’t the sensitive part, but I’ve never done it that way and wanted to be sure.

You must, client ID is what identify which application is trying to authorize an user. The client secret and access_token on the other hand should never leak to the client side.

1 Like

Thanks :slight_smile: I noticed the authorization token is returned by Blizzard as part of the URL too but I assume that’s ok and I’m not doing it wrong.

The authorization code must be exchanged by your server combined with your secret to actually yield an access_token. The authorization code on itself gives no access to any resource so it is safe.

1 Like

All my changes are now public in WCM and apparently working as intended :slight_smile: I still keep expecting an avalanche of bug reports though :joy:

I just wanted to say thanks again for all your help. Without it, I would have taken weeks or months of trial and error to get it running.

VB NET

    '//Add RestSharp to your nuget package manager
    '//imports RestSharp at the top
    '//Set api key
    Dim api_key As String = "{your api key here}"
    Dim api_secret As String = "{your api secret here}"
    Dim region As String = "EU"
    '//encode the creds
    Dim encoded As String = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(api_key + ":" + api_secret))
    Dim Rclient As New RestClient("https://" & region & ".battle.net/oauth/token")
    Rclient.Timeout = -1
    Dim rRequest As New RestRequest(Method.POST)
    rRequest.AddParameter("grant_type", "client_credentials")
    rRequest.AddHeader("Authorization", "Basic " & encoded)
    rRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded")
    Dim rResponse As IRestResponse = Rclient.Execute(rRequest)
    '//write out the access token
    MsgBox(rResponse.Content)

Hope this helps someone who needs it. Can be converted to C# Easily for any .NET people out there.

Obviously the links are butchered as I cannot post links here, so just remove the spacing. :slight_smile:

1 Like

Pascal

Tested with Lazarus/Freepascal and probably Delphi. Some configuration of the proper OpenSSL libraries might be required.

function TForm1.CreateAccessToken(const ClientID, ClientSecret: string): string;
var
  HTTP: TIdHttp;
  SSLHandler: TIdSSLIOHandlerSocketOpenSSL;
  FormData: TIdMultipartFormDataStream;
  Response: TStringStream;
begin
  HTTP := TIdHttp.Create(nil);
  FormData := TIdMultipartFormDataStream.Create;
  Response := TStringStream.Create('');
  SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create;
  try
    try
      // SSL support
      SSLHandler.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2];
      HTTP.IOHandler := SSLHandler;

      // Authorization header
      HTTP.Request.BasicAuthentication := True;
      HTTP.Request.UserName := ClientID;
      HTTP.Request.Password := ClientSecret;

      // Body payload
      FormData.AddFormField('grant_type', 'client_credentials');

      // Excecute the request
      HTTP.Post('https://us.battle.net/oauth/token', FormData, Response);

      Result := Response.DataString;
    except
      on E:Exception do
        // Handle exceptions or
        raise;
    end
  finally
    Response.Free;
    FormData.Free;
    SSLHandler.Free;
    HTTP.Free;
  end
end;        

thanks! you are a champ!

Thank you! Lovin how active this community is

Hi,
I’m trying to get a client running in java 11, with the java HttpClient class (not the apache one), but I’m getting stuck on getting the authentication token.
I tried extending the Authenticator class and passing that to the HttpClient builder. I also tried to add the client id and secret in the POST body, and any other variation I could think of or adapt from examples I’ve seen in other languages.

I keep getting 401, with this error:

{"error":"unauthorized","error_description":"An Authentication object was not found in the SecurityContext"}

Can anyone help? Maybe you already have an implementation with the Java Httpclient?

Thanks!

Sorry, I can’t help with this one, I hate Java.

I would advise you to create a separate topic asking for help with this specific situation to give it more visibility on the forum. If possible provide a sample code and someone will reply eventually.