remoteAuthRequest static method

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

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: “

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.

encrypter When the state value is stored locally, it is encrypted. This parameter allows you to provide your own encryption method. This will be used in addition to the default encryption method. This will be performed before the default encryption method.

Returns the state value that 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<String> remoteAuthRequest({
  required String clientId,
  required String redirectUri,
  String? deviceName,
  String? state,
  String Function(String plaintext)? encrypter,
}) 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");
  }

  // Write the state secret to local storage.
  await LocalStorageRepo.write(
    content: stateBuffer.toString(),
    folder: Folder.tmp,
    fileName: stateSecretFile,
    encrypter: encrypter,
  );

  // Call the service.
  await BridgeDiscoveryService.remoteAuthRequest(url: urlBuffer.toString());

  return stateBuffer.toString();
}