[gis_web] Improves renderButton API exports. (#3432)

[gis_web] Improves renderButton API exports.
diff --git a/packages/google_identity_services_web/CHANGELOG.md b/packages/google_identity_services_web/CHANGELOG.md
index d84b822..966e812 100644
--- a/packages/google_identity_services_web/CHANGELOG.md
+++ b/packages/google_identity_services_web/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.2.1
+
+* Relaxes the `renderButton` API so any JS-Interop Object can be its `target`.
+* Exposes the `Button*` configuration enums, so the rendered button can be configured.
+
 ## 0.2.0
 
 * Adds `renderButton` API to `id.dart`.
diff --git a/packages/google_identity_services_web/example/integration_test/js_interop_id_test.dart b/packages/google_identity_services_web/example/integration_test/js_interop_id_test.dart
index 17ac748..78a4694 100644
--- a/packages/google_identity_services_web/example/integration_test/js_interop_id_test.dart
+++ b/packages/google_identity_services_web/example/integration_test/js_interop_id_test.dart
@@ -9,6 +9,7 @@
 import 'package:integration_test/integration_test.dart';
 import 'package:js/js.dart';
 
+import 'src/dom.dart';
 import 'utils.dart' as utils;
 
 void main() async {
@@ -19,6 +20,17 @@
     await utils.installGisMock();
   });
 
+  group('renderButton', () {
+    testWidgets('supports a js-interop target from any library', (_) async {
+      final DomElement target = createDomElement('div');
+
+      id.renderButton(target);
+
+      final DomElement? button = target.querySelector('button');
+      expect(button, isNotNull);
+    });
+  });
+
   group('prompt', () {
     testWidgets('supports a moment notification callback', (_) async {
       id.initialize(IdConfiguration(client_id: 'testing_1-2-3'));
diff --git a/packages/google_identity_services_web/example/integration_test/src/dom.dart b/packages/google_identity_services_web/example/integration_test/src/dom.dart
new file mode 100644
index 0000000..fb41b0a
--- /dev/null
+++ b/packages/google_identity_services_web/example/integration_test/src/dom.dart
@@ -0,0 +1,31 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: public_member_api_docs
+
+import 'package:js/js.dart';
+import 'package:js/js_util.dart' as js_util;
+
+@JS()
+@staticInterop
+class DomDocument {}
+
+extension DomDocumentExtension on DomDocument {
+  DomElement createElement(String name, [Object? options]) =>
+      js_util.callMethod(this, 'createElement',
+          <Object>[name, if (options != null) options]) as DomElement;
+}
+
+@JS()
+@staticInterop
+class DomElement {}
+
+extension DomElementExtension on DomElement {
+  external DomElement? querySelector(String selector);
+}
+
+@JS('document')
+external DomDocument get domDocument;
+
+DomElement createDomElement(String tag) => domDocument.createElement(tag);
diff --git a/packages/google_identity_services_web/example/lib/main.dart b/packages/google_identity_services_web/example/lib/main.dart
index 3dc8c0e..1046826 100644
--- a/packages/google_identity_services_web/example/lib/main.dart
+++ b/packages/google_identity_services_web/example/lib/main.dart
@@ -9,7 +9,8 @@
 import 'package:google_identity_services_web/loader.dart' as gis;
 // #enddocregion use-loader
 import 'package:js/js.dart' show allowInterop;
-import 'package:jwt_decoder/jwt_decoder.dart' as jwt;
+
+import 'src/jwt.dart' as jwt;
 
 // #docregion use-loader
 void main() async {
@@ -32,7 +33,7 @@
 /// Handles the ID token returned from the One Tap prompt.
 /// See: https://developers.google.com/identity/gsi/web/reference/js-reference#callback
 void onCredentialResponse(CredentialResponse o) {
-  final Map<String, dynamic>? payload = jwt.JwtDecoder.tryDecode(o.credential!);
+  final Map<String, dynamic>? payload = jwt.decodePayload(o.credential);
   if (payload != null) {
     print('Hello, ${payload["name"]}');
     print(o.select_by);
diff --git a/packages/google_identity_services_web/example/lib/src/jwt.dart b/packages/google_identity_services_web/example/lib/src/jwt.dart
new file mode 100644
index 0000000..bc17f49
--- /dev/null
+++ b/packages/google_identity_services_web/example/lib/src/jwt.dart
@@ -0,0 +1,50 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'dart:convert';
+
+/// A codec that can encode/decode JWT payloads.
+///
+/// See https://www.rfc-editor.org/rfc/rfc7519#section-3
+final Codec<Object?, String> _jwtCodec = json.fuse(utf8).fuse(base64);
+
+/// A RegExp that can match, and extract parts from a JWT Token.
+///
+/// A JWT token consists of 3 base-64 encoded parts of data separated by periods:
+///
+///   header.payload.signature
+///
+/// More info: https://regexr.com/789qc
+final RegExp _jwtTokenRegexp = RegExp(
+    r'^(?<header>[^\.\s]+)\.(?<payload>[^\.\s]+)\.(?<signature>[^\.\s]+)$');
+
+/// Decodes the `claims` of a JWT token and returns them as a Map.
+///
+/// JWT `claims` are stored as a JSON object in the `payload` part of the token.
+///
+/// (This method does not validate the signature of the token.)
+///
+/// See https://www.rfc-editor.org/rfc/rfc7519#section-3
+Map<String, Object?>? decodePayload(String? token) {
+  if (token != null) {
+    final RegExpMatch? match = _jwtTokenRegexp.firstMatch(token);
+    if (match != null) {
+      return _decodeJwtPayload(match.namedGroup('payload'));
+    }
+  }
+
+  return null;
+}
+
+/// Decodes a JWT payload using the [_jwtCodec].
+Map<String, Object?>? _decodeJwtPayload(String? payload) {
+  try {
+    // Payload must be normalized before passing it to the codec
+    return _jwtCodec.decode(base64.normalize(payload!))
+        as Map<String, Object?>?;
+  } catch (_) {
+    // Do nothing, we always return null for any failure.
+  }
+  return null;
+}
diff --git a/packages/google_identity_services_web/example/pubspec.yaml b/packages/google_identity_services_web/example/pubspec.yaml
index 4b87b49..b305694 100644
--- a/packages/google_identity_services_web/example/pubspec.yaml
+++ b/packages/google_identity_services_web/example/pubspec.yaml
@@ -13,7 +13,6 @@
     path: ../
   http: ^0.13.5
   js: ^0.6.4
-  jwt_decoder: 2.0.1
 
 dev_dependencies:
   build_runner: ^2.1.10 # To extract README excerpts only.
diff --git a/packages/google_identity_services_web/example/web/mock-gis.js b/packages/google_identity_services_web/example/web/mock-gis.js
index 2e13460..5921c5e 100644
--- a/packages/google_identity_services_web/example/web/mock-gis.js
+++ b/packages/google_identity_services_web/example/web/mock-gis.js
@@ -33,6 +33,13 @@
   initialize(config) {
     this.config = config;
   }
+  renderButton(target, config) {
+    // Simulate rendering a button.
+    target.replaceChildren();
+    target.dataset.buttonConfig = config;
+    let button = document.createElement('button');
+    target.append(button);
+  }
   prompt(momentListener) {
     callAsync(() => {
       if (this.mockCredentialResponse) {
diff --git a/packages/google_identity_services_web/lib/id.dart b/packages/google_identity_services_web/lib/id.dart
index 3486212..922ef0f 100644
--- a/packages/google_identity_services_web/lib/id.dart
+++ b/packages/google_identity_services_web/lib/id.dart
@@ -5,7 +5,14 @@
 export 'src/js_interop/google_accounts_id.dart';
 export 'src/js_interop/shared.dart'
     show
+        ButtonLogoAlignment,
+        ButtonShape,
+        ButtonSize,
+        ButtonText,
+        ButtonTheme,
+        ButtonType,
         CredentialSelectBy,
+        GoogleIdentityServicesErrorType,
         MomentDismissedReason,
         MomentNotDisplayedReason,
         MomentSkippedReason,
diff --git a/packages/google_identity_services_web/lib/oauth2.dart b/packages/google_identity_services_web/lib/oauth2.dart
index 63db5bc..e0cb236 100644
--- a/packages/google_identity_services_web/lib/oauth2.dart
+++ b/packages/google_identity_services_web/lib/oauth2.dart
@@ -3,4 +3,5 @@
 // found in the LICENSE file.
 
 export 'src/js_interop/google_accounts_oauth2.dart';
-export 'src/js_interop/shared.dart' show UxMode;
+export 'src/js_interop/shared.dart'
+    show GoogleIdentityServicesErrorType, UxMode;
diff --git a/packages/google_identity_services_web/lib/src/js_interop/google_accounts_id.dart b/packages/google_identity_services_web/lib/src/js_interop/google_accounts_id.dart
index a790fae..45a8e51 100644
--- a/packages/google_identity_services_web/lib/src/js_interop/google_accounts_id.dart
+++ b/packages/google_identity_services_web/lib/src/js_interop/google_accounts_id.dart
@@ -14,7 +14,6 @@
 
 import 'package:js/js.dart';
 
-import 'dom.dart';
 import 'shared.dart';
 
 /// Binding to the `google.accounts.id` JS global.
@@ -93,7 +92,7 @@
   /// Method: google.accounts.id.renderButton
   /// https://developers.google.com/identity/gsi/web/reference/js-reference#google.accounts.id.renderButton
   external void renderButton(
-    DomHtmlElement parent, [
+    Object parent, [
     GsiButtonConfiguration options,
   ]);
 
diff --git a/packages/google_identity_services_web/pubspec.yaml b/packages/google_identity_services_web/pubspec.yaml
index e979dfa..8d4b6c5 100644
--- a/packages/google_identity_services_web/pubspec.yaml
+++ b/packages/google_identity_services_web/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Dart JS-interop layer for Google Identity Services. Google's new sign-in SDK for Web that supports multiple types of credentials.
 repository: https://github.com/flutter/packages/tree/main/packages/google_identity_services_web
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+google_identiy_services_web%22
-version: 0.2.0
+version: 0.2.1
 
 environment:
   sdk: ">=2.17.0 <4.0.0"
diff --git a/script/configs/allowed_pinned_deps.yaml b/script/configs/allowed_pinned_deps.yaml
index 67886a9..e1d7f54 100644
--- a/script/configs/allowed_pinned_deps.yaml
+++ b/script/configs/allowed_pinned_deps.yaml
@@ -10,7 +10,6 @@
 # Legacy allowances, for dependencies that predate the tooling.
 # TODO(stuartmorgan): Audit these. See
 # https://github.com/flutter/flutter/issues/122713
-- jwt_decoder
 - lcov_parser
 - adaptive_dialog
 - provider