Fixing Google Translate API calls in Flutter

For some reason, my API calls to Google Translate in Flutter have started failing in the past few weeks. However, I do not even remember how I set it all up. Still, let's debug and find our way through this problem.

First here's how the code is roughly set up:

import 'package:googleapis_auth/auth_io.dart';
import 'package:googleapis/translate/v3.dart';


const _SCOPES = const [

Future<TranslateApi> _getTranslateClient() async {
  final credentials = new ServiceAccountCredentials.fromJson(jsonCredentials);

  projectId = jsonDecode(jsonCredentials)['project_id'];
  final httpClient = await clientViaServiceAccount(credentials, _SCOPES);
  client = new TranslateApi(httpClient);
  return client;

Future<String> translate(
    {required String text, Language? from, Language? to}) async {
  final client = await _getTranslateClient();

  var request = TranslateTextRequest();
  request.contents = [text];
  request.sourceLanguageCode = from == null ? null : from.isoCode;
  request.targetLanguageCode = to!.isoCode;
  try {
    final response =
        await client.projects.translateText(request, 'projects/$projectId');
    return unescape.convert(response.translations!.first.translatedText!);
  } catch (e) {
    return "?";

From there on, here's the relevant documentation I've dug up:

Then the exception I get is this:

AccessDeniedException (Access was denied (www-authenticate header was: Bearer realm="", error="insufficient_scope", scope="").)

Looking back at the scope, I do indeed only use Translate. Why should I also need cloud-platform? But indeed, this page lists both tokens:

However, "See, edit, configure, delete Google Cloud data" seems scary. I just need a translation, I do not want to delete any data! Anyway, if that's the scope I need, let's set it up. I add this scope and run the translation again. This time I get this:

DetailedApiRequestError (DetailedApiRequestError(status: 403, message: Cloud IAM permission 'cloudtranslate.generalModels.predict' denied. ))

Ok this seems relevant. Let's take a look at my Credential roles at

In the search box, I do not see any role called "translate" or "generateModels".

But if I click Manage Roles, I get a list of over 1400 roles. And this time the search box works:

I select the role "Cloud Translation API User", and it automatically selects 28 permissions.

How though do I assign this to my credential? Since I couldn't find any way to do it, I tried to create another Credential. This time when creating the Credential, I can search for the Translate role!

Then I create a new Key

I downloaded the JSON and applied it to my project. And lo and behold, it worked! In the end, I never found any official documentation explaining this process in detail, and why the old scope suddenly stopped working.