Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authenticator corrupts request body #388

Closed
InAnadea opened this issue Dec 7, 2022 · 2 comments · Fixed by #390 or #497
Closed

Authenticator corrupts request body #388

InAnadea opened this issue Dec 7, 2022 · 2 comments · Fixed by #390 or #497
Assignees
Labels
bug Something isn't working

Comments

@InAnadea
Copy link

InAnadea commented Dec 7, 2022

Steps to Reproduce

When I added an authenticator for ChopperClient, my POST request started giving an HTTP code 400.

Just add an authenticator for the client.

ServerApi.create(
  client: ChopperClient(
    baseUrl: Environment().config.baseUrl,
    authenticator: MyAuthenticator(localDataSource), // here
    errorConverter: const ServerErrorConverter(),
    converter: JsonSerializableConverter(),
    interceptors: [
      ChopperLoggingInterceptor(),
      ChopperCurlInterceptor(),
    ],
  ),
);

class MyAuthenticator extends Authenticator {
  final LocalDataSource localDataSource;

  MyAuthenticator(this.localDataSource);

  @override
  FutureOr<Request?> authenticate(
    Request request,
    Response response, [
    Request? originalRequest,
  ]) async {
    if (response.statusCode == 401) {
      final authModel = await localDataSource.getAuthModelFromCache();
      String newToken = authModel.token;

      final Map<String, String> updatedHeaders =
          Map<String, String>.of(request.headers);

      newToken = 'Bearer $newToken';
      updatedHeaders.update(
        'Authorization',
        (String _) => newToken,
        ifAbsent: () => newToken,
      );
      return request.copyWith(
        headers: updatedHeaders,
      );
    }
    return null;
  }
}

I'm debugged ChopperClient's code and here after authenticator!.authenticate(req, res, request) body converts to string.

Screenshot 2022-12-07 at 13 27 59

Expected results:
The request should save the body type after request.copyWith.

Actual results:
The authenticator converts the body to string.

[Global Loggy] 👻 13:35:37.198690 INFO - --> POST https://xxx/api/administration/add-admin
[Global Loggy] 👻 13:35:37.198868 INFO - content-type: application/json; charset=utf-8
[Global Loggy] 👻 13:35:37.199273 INFO - {"email":"asdf@asdf.asdf"}
[Global Loggy] 👻 13:35:37.199460 INFO - --> END POST (26-byte body)

[Global Loggy] 👻 13:35:39.315634 INFO - --> POST https://xxx/api/administration/add-admin
[Global Loggy] 👻 13:35:39.316050 INFO - content-type: application/json; charset=utf-8
[Global Loggy] 👻 13:35:39.316252 INFO - Authorization: xxxx
[Global Loggy] 👻 13:35:39.316526 INFO - "{\"email\":\"asdf@asdf.asdf\"}"
[Global Loggy] 👻 13:35:39.316773 INFO - --> END POST (32-byte body)
Code sample
ServerApi.create(
  client: ChopperClient(
    baseUrl: Environment().config.baseUrl,
    authenticator: MyAuthenticator(localDataSource), // here
    errorConverter: const ServerErrorConverter(),
    converter: JsonSerializableConverter(),
    interceptors: [
      ChopperLoggingInterceptor(),
      ChopperCurlInterceptor(),
    ],
  ),
);

class MyAuthenticator extends Authenticator {
  final LocalDataSource localDataSource;

  MyAuthenticator(this.localDataSource);

  @override
  FutureOr<Request?> authenticate(
    Request request,
    Response response, [
    Request? originalRequest,
  ]) async {
    if (response.statusCode == 401) {
      final authModel = await localDataSource.getAuthModelFromCache();
      String newToken = authModel.token;

      final Map<String, String> updatedHeaders =
          Map<String, String>.of(request.headers);

      newToken = 'Bearer $newToken';
      updatedHeaders.update(
        'Authorization',
        (String _) => newToken,
        ifAbsent: () => newToken,
      );
      return request.copyWith(
        headers: updatedHeaders,
      );
    }
    return null;
  }
}
Logs
[Global Loggy] 👻 13:35:37.198690 INFO - --> POST https://xxx/api/administration/add-admin
[Global Loggy] 👻 13:35:37.198868 INFO - content-type: application/json; charset=utf-8
[Global Loggy] 👻 13:35:37.199273 INFO - {"email":"asdf@asdf.asdf"}
[Global Loggy] 👻 13:35:37.199460 INFO - --> END POST (26-byte body)

[Global Loggy] 👻 13:35:39.315634 INFO - --> POST https://xxx/api/administration/add-admin
[Global Loggy] 👻 13:35:39.316050 INFO - content-type: application/json; charset=utf-8
[Global Loggy] 👻 13:35:39.316252 INFO - Authorization: xxxx
[Global Loggy] 👻 13:35:39.316526 INFO - "{\"email\":\"asdf@asdf.asdf\"}"
[Global Loggy] 👻 13:35:39.316773 INFO - --> END POST (32-byte body)
Dart SDK version: 2.18.2 (stable) (Tue Sep 27 13:24:11 2022 +0200) on "macos_arm64"
@InAnadea InAnadea added the bug Something isn't working label Dec 7, 2022
@techouse
Copy link
Collaborator

techouse commented Dec 10, 2022

Confirmed. I was able to replicate this in a test case.

The Authenticator I used is pretty vanilla.

class FakeAuthenticator extends Authenticator {
  @override
  FutureOr<Request?> authenticate(
    Request request,
    Response response, [
    Request? originalRequest,
  ]) async {
    if (response.statusCode == 401) {
      return request.copyWith(
        headers: <String, String>{
          ...request.headers,
          'authorization': 'some_fake_token',
        },
      );
    }

    return null;
  }
}

This assertion here fails after triggering the Authenticator.

Expected: '{"name":"john","surname":"doe"}'
  Actual: '"{\\"name\\":\\"john\\",\\"surname\\":\\"doe\\"}"'
   Which: is different.
          Expected: {"name":"j ...
            Actual: "{\\"name\ ...
                    ^
           Differ at offset 0

If the Authenticator is not triggered it passes.

It also affects PATCH and PUT methods, as they too send a body. GET is unaffected.

@InAnadea Until I hopefully fix this I suggest you pre-authenticate before attempting any POST calls.

@techouse
Copy link
Collaborator

#390 should fix it.

@InAnadea can you please check out the PR or https://github.com/techouse/chopper/tree/fix-authenticator-corrupting-body and confirm that it all works?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
2 participants