remoteAuthRequest static method

Future<Map<String, String>> remoteAuthRequest({
  1. required String clientId,
  2. required String redirectUri,
  3. String? deviceName,
  4. String? state,
})

This method allows the user to grant access to the app to allow it to connect to their bridge.

This is step 1. Step 2 is TokenRepo.fetchRemoteToken.

clientId Identifies the client that is making the request. The value passed in this parameter must exactly match the value you receive from hue.

redirectUri This parameter must exactly match the one configured in your hue developer account.

deviceName The device name should be the name of the app or device accessing the remote API. The deviceName is used in the user’s “My Apps” overview in the Hue Account (visualized as: “appName on deviceName”).

state Provides any state that might be useful to your application upon receipt of the response. The Hue Authorization Server round-trips this parameter, so your application receives the same value it sent. To mitigate against cross-site request forgery (CSRF), a long (30+ digit), random number is prepended to state. When the response is received from Hue, it is recommended that you compare the string returned from this method, to the one that is returned from Hue.

Returns a map with the key url and state. The url is the URL that the user needs to visit to grant access to the app. The state value is what is sent with the GET request. This is prepended with the long, random number. Between the random number and the provided state will be a - (dash).

Implementation

static Future<Map<String, String>> remoteAuthRequest({
  required String clientId,
  required String redirectUri,
  String? deviceName,
  String? state,
}) async {
  final StringBuffer urlBuffer =
      StringBuffer('https://api.meethue.com/v2/oauth2/authorize?');
  final StringBuffer stateBuffer = StringBuffer();

  // Generate a random code verifier.
  final String codeVerifier = base64Url
      .encode(List.generate(32, (index) => MiscTools.randInt(0, 255)));

  // Calculate the code challenge using SHA-256.
  final String codeChallenge =
      base64Url.encode(sha256.convert(utf8.encode(codeVerifier)).bytes);

  // Write the URI.
  urlBuffer.write('${ApiFields.clientId}=$clientId');
  urlBuffer.write('&${ApiFields.responseType}=code');
  urlBuffer.write('&${ApiFields.codeChallengeMethod}=S256');
  urlBuffer.write('&${ApiFields.codeChallenge}=$codeChallenge');
  urlBuffer.write('&${ApiFields.state}=');
  stateBuffer.write(MiscTools.randInt(1, 123).toString());
  for (int i = 0; i < MiscTools.randInt(30, 44); i++) {
    stateBuffer.write(MiscTools.randInt(0, 123).toString());
  }
  urlBuffer.write(stateBuffer.toString());
  if (state != null && state.isNotEmpty) {
    urlBuffer.write('-$state');
  }
  urlBuffer.write('&${ApiFields.redirectUri}=$redirectUri');
  if (deviceName != null && deviceName.isNotEmpty) {
    urlBuffer.write('&${ApiFields.deviceName}=$deviceName');
  }

  return {'url': urlBuffer.toString(), 'state': stateBuffer.toString()};
}