OAuth2 client credentials implementations

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.

OK, I’ll try that. Thanks.

Btw, I was able to get over the authentication problem. Now I’m getting this response:

{
  "error":"invalid_request",
  "error_description":"Missing grant type"
}

You probably forgot to include the grant type in your authorization request
'grant_type' should have 'client_credentials' as value.

I did add the grant type.
I just managed to get it to work. When I used Content-Type of application/x-www-form-urlencoded it started working. I’ve been using multipart before, because that’s what they say in the guide.
I don’t know why.

That is definitely an error in the documentation, the RFC clearly states all requests are application/x-www-form-urlencoded.

I guess I just assumed that in all of my code, until now I didn’t even notice that part of the guide, or perhaps the old documentation was different.

1 Like

Hello there!

Has someone made oauth authentication with react? I’m learning new stuff with react and spent couple of hours debugging because access token expired (need to handle errors better in future…). Was planning to make it possible to get access token directly but have no idea how to continue

Unless you are talking about the experimental server-side rendering you can’t use react to handle API requests and token generation.

It is a severe security risk to expose you credentials or even the generated token to the client. You must use a back-end server to handle all API requests.

I created this proxy to help people who doesn’t want to deal with the back-end part.

C# (using System.Text.Json)

    public class BlizzardAccessToken // Blizzard Access Token Json > C# Class 
    {
        [JsonInclude]
        [JsonPropertyName("access_token")]
        public string access_token { get; private set; }
        [JsonInclude]
        [JsonPropertyName("token_type")]
        public string token_type { get; private set; }
        private int _expires_in; // Backing Field
        [JsonInclude]
        [JsonPropertyName("expires_in")]
        public int expires_in // Seconds
        {
            get
            {
                return this._expires_in;
            }
            private set
            {
                this._expires_in = value;
                DateTime now = DateTime.Now;
                TimeSpan time = new TimeSpan(0, 0, value); // Hours , Minutes, Seconds
                this.expire_date = now.Add(time);
            }
        }
        public DateTime expire_date { get; private set; }
        [JsonInclude]
        [JsonPropertyName("scope")]
        public string scope { get; private set; }
    }


        private async Task RequestToken() // method to get token
        {
            try
            {
                await Program.Log("Requesting new BlizzAPI Token...");
                using (var request = new HttpRequestMessage(new HttpMethod("POST"), $"https://{this.Config.Region}.battle.net/oauth/token"))
                {
                    var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{this.Config.client_id}:{this.Config.client_secret}")); // Specify Client ID/Secret
                    request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
                    request.Content = new StringContent("grant_type=client_credentials");
                    request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");

                    var client = this.ClientFactory.CreateClient("ApiClient"); // Get HTTP Client
                    using (var response = await client.SendAsync(request)) // Send HTTP request
                    await using (var result = await response.Content.ReadAsStreamAsync()) // Get Result
                    {
                        this.Token = await JsonSerializer.DeserializeAsync<BlizzardAccessToken>(result, new JsonSerializerOptions() { IgnoreNullValues = true }); // De-serialize Json
                        if (this.Token.access_token is null) throw new Exception($"Error obtaining token:\n{response}");
                        this.TokenExpTimer_Start(); // Start Auto-Renewing Timer
                        await Program.Log($"BlizzAPI Token obtained! Valid until {this.Token.expire_date} (Auto-Renewing).");
                    }
                }
            }
            catch (Exception ex)
            {
                await Program.Log(ex.ToString());
            }
        }
1 Like

NodeJS (using node-fetch)

import fetch from 'node-fetch';

let appId = 'YOUR APP ID';
let appSecret = 'YOUR APP SECRET';

let request = fetch('https://us.battle.net/oauth/token', {
  body: new URLSearchParams({ grant_type: 'client_credentials' }),
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + Buffer.from(`${appId}:${appSecret}`).toString('base64')
  }
})
.then(response => response.json())
.then(json => console.log(json));

I am new to php but my client want to add a button on his login page which redirects to battle.net website login page and user enter their credential then get authorised from battle.net and get redirected to his website. (i.e Oauth)
how can i add this on a click of button, i have seen the curl code but didn’t get it.
i have the client_id and client secret key with me.
Any help will be highly appreciated. Thanks in advance.

I’ve been using this for years now but for some odd reasons it’s broken since last week. Any idea on how should I fix it? Apparently the token isn’t necessary in the URI, don’t know how to rewrite the request.

Thanks for your help ^^

Did this function stop working ? Or did whatever request you do after this function stop working? As far as I know this function should still work.

It is not allowed anymore as part of the query string. If you get the token with the first function and use it as part of the query string in subsequent requests it most certainly won’t work. You must pass the token as a Bearer token in the Authorization header.

Indeed, the function works as intended in my spreadsheet.
However, the request to the Blizzard API I do after this function doesn’t work anymore.
I use : “https ://eu.api.blizzard.com/profile/wow/character/{realmSlug}/{characterName}?namespace=profile-eu&locale=fr_FR&access_token=XXXXX”

How can I pass the token as a Bearer Token in the Authorization header?
Thanks a lot for your help ^^

PowerShell

function Get-WowToken {
    [CmdletBinding()]
    param (
        $clientId,
        $clientSecret,
        $region='us'
    )
    $wowCreds = @{
        client_id = $clientId
        client_secret = $clientSecret
        grant_type = 'client_credentials'
    }
    Try {
        $tokenData = Invoke-RestMethod "https://$region.battle.net/oauth/token" -Body $wowCreds -Method Post
        return $tokenData
    } Catch {
        return $_.Exception.Response
    }
}

You must add the header on every request using the bearer token. Something like this should work:

function fetchCharacterData(region, token, realmSlug, characterName) {
  var options = {
    'method': 'get',
    'headers': {
      'Authorization': 'Bearer ' + token
    }
  };
  var url = 'https://' + region + '.api.blizzard.com/profile/wow/character/' + realmSlug + '/' + characterName + '?namespace=profile-eu&locale=fr_FR';
  var response = UrlFetchApp.fetch(url, options);
  return JSON.parse(response.getContentText())
}

Please note I haven’t actually tried this code, some adjusts may be required but that is the general idea.

Thanks, the function seems to work but I got this error : “Request failed for https ://eu.api.blizzard.com/ returned code 401”
I made a test on Blizzard game-data-API website and I also got the error : “401 Unauthorized”
https ://imgur.com/we0MpgH

Do you have any idea on how can I fix this ?

The official API docs are indeed broken right now. But the idea is to pass the access_token as an Authorization: Bearer header. If you do that your code should work again.