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 [
TranslateApi.cloudTranslationScope,
];
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');
print(response.translations!.first.translatedText);
return unescape.convert(response.translations!.first.translatedText!);
} catch (e) {
print(e);
return "?";
}
}
From there on, here's the relevant documentation I've dug up:
- https://pub.dev/packages/googleapis_auth#using-this-package
- https://developers.google.com/identity/protocols/oauth2/scopes#translate
- https://cloud.google.com/translate/docs/setup#roles
Then the exception I get is this:
AccessDeniedException (Access was denied (www-authenticate header was: Bearer realm="https://accounts.google.com/", error="insufficient_scope", scope="https://www.googleapis.com/auth/cloud-platform").)
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 https://console.cloud.google.com/iam-admin/serviceaccounts/details/....
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.