Skip to content
This repository has been archived by the owner on Jul 16, 2020. It is now read-only.

Authorization

JoshSnider edited this page Apr 19, 2018 · 7 revisions

Authorization to Mixer is different depending on where your game is running.

The C++ SDK takes an authorization token as a parameter to the interactive_open_session function. You are free to supply either of these tokens:

Mixer OAuth

If you want to obtain a Mixer OAuth token you can do so using the provided authorization helper functions. At a high level the order of operations to do this are as follows.

  1. Using your Client ID (obtained here), request a shortCode from Mixer using the interactive_auth_get_short_code function.
int err = 0;
char shortCode[7];
size_t shortCodeLength = sizeof(shortCode);
char shortCodeHandle[1024];
size_t shortCodeHandleLength = sizeof(shortCodeHandle);

// Get an OAuth short code from the user. For more information about OAuth see: https://oauth.net/2/
err = interactive_auth_get_short_code(CLIENT_ID, nullptr, shortCode, &shortCodeLength, shortCodeHandle, &shortCodeHandleLength);
if (err) return err;
  1. If you are on a platform where you can open a web browser or your engine has an embedded browser you can open https://www.mixer.com/go?code=<shortCode> which will allow them to either deny or approve the request.
// On Windows, pop the browser for the user to approve access.
std::string authUrl = std::string("https://www.mixer.com/go?code=") + shortCode;
ShellExecuteA(0, 0, authUrl.c_str(), nullptr, nullptr, SW_SHOW);
  1. Meanwhile your code can wait on this response using the interactive_auth_wait_short_code function.
// Wait for OAuth token response.
char refreshTokenBuffer[1024];
size_t refreshTokenLength = sizeof(refreshTokenBuffer);
err = interactive_auth_wait_short_code(CLIENT_ID, nullptr, shortCodeHandle, refreshTokenBuffer, &refreshTokenLength);
if (err)
{
	if (MIXER_ERROR_TIMED_OUT == err)
	{
		std::cout << "Authorization timed out, user did not approve access within the time limit." << std::endl;
	}
	else if (MIXER_ERROR_AUTH_DENIED == err)
	{
		std::cout << "User denied access." << std::endl;
	}
		return err;
}
  1. If the function succeeds, the populated buffer is now a json blob that can be used to refresh access when necessary. Consider this blob a user secret, store it securely.
  2. Now the authorization header string that should be passed to interactive_open_session can be parsed from the json blob using the interactive_auth_parse_refresh_token function. For future sessions, your code should check if the token needs to be refreshed using the interactive_auth_is_token_stale function and if so, call interactive_auth_refresh_token to get a new json blob that replaces the previous one.
// Extract the authorization header from the refresh token.
char authBuffer[1024];
size_t authBufferLength = sizeof(authBuffer);
err = interactive_auth_parse_refresh_token(refreshTokenBuffer, authBuffer, &authBufferLength);
if (err) return err;

Xbox Live Token Authorization

On Xbox, you have platform support for accessing the signed in User's access token. You should pass the Xbox Live token string obtained from the System user as the authorization parameter to interactive_open_session.

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;

int GetXToken(std::string& token)
{
	std::wstring mixerRelyingParty = L"https://mixer.com";
	std::wstring authRequestHeaders = L"";
	auto platformHttp = ref new Platform::String(L"POST");
	auto platformUrl = ref new Platform::String(mixerRelyingParty.c_str());
	auto platformHeaders = ref new Platform::String(authRequestHeaders.c_str());

	std::wstring wstrReturnedToken = L"";

	HRESULT hr = S_OK;

	// Note: This would fail certification. You must pop TCUI and allow a user to be chosen.
	Windows::Xbox::System::User^ currentUser = Windows::Xbox::System::User::Users->GetAt(0);
	if (nullptr == currentUser)
	{
		OutputDebugStringA("No user signed in. Please sign in a user and try this sample again.");
		return E_ABORT;
	}

	try
	{
		// Make platform call to get token.
		auto asyncOp = currentUser->GetTokenAndSignatureAsync(platformHttp, platformUrl, platformHeaders);

		// Construct an object that waits for the AsyncOperation to finish
		task<GetTokenAndSignatureResult^> asyncTask = create_task(asyncOp);

		// Capture the async then so we can ensure the lambda finishes before continuing
		auto asyncFinalise = asyncTask.then(
			[&wstrReturnedToken, &hr](
				task<GetTokenAndSignatureResult^> operation)
		{
			try
			{
				GetTokenAndSignatureResult^ result = operation.get();

				if (result->Token->IsEmpty())
				{
					hr = E_UNEXPECTED;
					return;
				}

				wstrReturnedToken = result->Token->Data();
				hr = S_OK;
			}
			catch (Platform::Exception ^ e)
			{
				hr = e->HResult;
			}
		});

		// Clean up the async task
		asyncTask.wait();
		asyncOp->Close();

		// Wait for the lambda to finish.
		asyncFinalise.wait();

		// Check for any failures
		if (FAILED(hr))
		{
			return hr;
		}

		// Convert data to utf8
		token = converter.to_bytes(wstrReturnedToken);
	}
	catch (Platform::Exception^ e)
	{
		return e->HResult;
	}

	return S_OK;
}
Clone this wiki locally