Providers

Google Provider

Prebuilt Google Sign-In using OAuth 2.0 Authorization Code flow with PKCE.

GoogleProvider is a prebuilt OAuth2Provider subclass targeting Google's OAuth 2.0 endpoints. It uses PKCE and requests access_type: offline so a refresh token is always returned, enabling silent session renewal.

Package: authyra_flutter


Constructor

GoogleProvider({
  required String clientId,
  String? clientSecret,
  String? redirectUri,
  List<String> scopes = const ['openid', 'email', 'profile'],
})
ParameterDefaultDescription
clientIdrequiredOAuth 2.0 client ID from Google Cloud Console
clientSecretnullOnly for confidential clients (backend/desktop with stored secret). Omit for mobile PKCE flows.
redirectUricom.googleusercontent.apps.<clientId>:/oauth2redirectOverride if your app uses a different URI scheme
scopes['openid', 'email', 'profile']Additional scopes extend these defaults

The provider ID is 'google'.


Setup

1. Create a Google OAuth 2.0 client

Go to Google Cloud Console → APIs & Services → Credentials and create an OAuth 2.0 Client ID:

  • For Android: choose Android, enter your package name and SHA-1 signing certificate fingerprint.
  • For iOS / macOS: choose iOS, enter your bundle ID.
  • For Web / desktop: choose Web application.

2. Add the provider

lib/main.dart
import 'package:app_links/app_links.dart';
import 'package:authyra_flutter/authyra_flutter.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final googleProvider = GoogleProvider(
    clientId: 'YOUR_GOOGLE_CLIENT_ID',
    // redirectUri defaults to com.googleusercontent.apps.YOUR_CLIENT_ID:/oauth2redirect
  );

  // Register before Authyra.initialize
  OAuth2CallbackHandler.registerProvider(
    'com.googleusercontent.apps.YOUR_CLIENT_ID',
    googleProvider,
  );
  AppLinks().uriLinkStream.listen(OAuth2CallbackHandler.handleCallback);

  await Authyra.initialize(
    client: AuthyraClient(
      providers: [googleProvider],
      storage: SecureAuthStorage(),
      config: const AuthConfig(autoRefresh: true),
    ),
  );

  runApp(const MyApp());
}

Androidandroid/app/src/main/AndroidManifest.xml:

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="com.googleusercontent.apps.YOUR_CLIENT_ID" />
</intent-filter>

iOSios/Runner/Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>com.googleusercontent.apps.YOUR_CLIENT_ID</string>
    </array>
  </dict>
</array>

Sign in

try {
  final user = await Authyra.instance.signIn('google');
  print('Hello, ${user.name}!');
} on AuthenticationCancelledException {
  // User closed the browser — no error to show
} on AuthenticationFailedException catch (e) {
  print('Google sign-in failed: $e');
}

User fields

AuthUser fieldGoogle claimNotes
idsubStable Google User ID
emailemail
namenameFull display name
avatarUrlpictureProfile photo URL
metadata['email_verified']email_verified
metadata['given_name']given_name
metadata['family_name']family_name
metadata['locale']locale
metadata['hd']hdHosted domain — Google Workspace accounts only

Scopes

The default scopes (openid, email, profile) cover the common case. Add scopes at construction for additional access:

GoogleProvider(
  clientId: 'YOUR_CLIENT_ID',
  scopes: [
    'openid',
    'email',
    'profile',
    'https://www.googleapis.com/auth/calendar.readonly',
  ],
)
Request only the scopes your app actually uses. Google will show a consent screen listing every scope — unnecessary scopes reduce user trust and may block app verification.

Token refresh

GoogleProvider sets supportsRefresh: true. The provider requests access_type: offline and prompt: consent on every sign-in, ensuring Google returns a refresh token. When the access token expires, AuthyraClient refreshes it automatically if AuthConfig.autoRefresh is true.

To force a token refresh manually:

await Authyra.instance.refreshSession();

Token revocation (sign-out)

GoogleProvider overrides signOut to call Google's revocation endpoint (https://oauth2.googleapis.com/revoke) with the current access token, revoking the Google session server-side before clearing the local session.

await Authyra.instance.signOut();

Troubleshooting

Callback never arrives

  1. Confirm the scheme in AndroidManifest.xml / Info.plist exactly matches com.googleusercontent.apps.<clientId>.
  2. Confirm OAuth2CallbackHandler.registerProvider is called with the same scheme string.
  3. On Android, verify app_links dependency and that your activity has launchMode="singleTask".

"redirect_uri_mismatch" error from Google

The redirect URI sent to Google does not match what is registered in Cloud Console. The default is com.googleusercontent.apps.<clientId>:/oauth2redirect — if you override redirectUri, register the same URI in the Cloud Console.

No refresh token returned

Google only returns a refresh token when access_type=offline and prompt=consent. Both are set by default. If the user has previously authorized your app and prompt=consent is removed, no refresh token is returned for subsequent logins.


See also

Copyright © 2026