githubProvider function
GitHub OAuth provider.
Based on GitHub's OAuth documentation and NextAuth's default provider
configuration. Retrieves the authenticated user from GET /user and
falls back to GET /user/emails if the email is missing.
Resources
- https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app
- https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps
- https://docs.github.com/en/rest/users/users#get-the-authenticated-user
- https://docs.github.com/en/rest/users/emails#list-public-email-addresses-for-the-authenticated-user
Example
final provider = githubProvider(
GitHubProviderOptions(
clientId: 'client-id',
clientSecret: 'client-secret',
redirectUri: 'https://example.com/auth/callback/github',
),
);
Implementation
OAuthProvider<GitHubProfile> githubProvider(GitHubProviderOptions options) {
final baseUrl = options.enterpriseBaseUrl ?? 'https://github.com';
final apiBaseUrl = options.enterpriseBaseUrl != null
? '${options.enterpriseBaseUrl}/api/v3'
: 'https://api.github.com';
return OAuthProvider<GitHubProfile>(
id: 'github',
name: 'GitHub',
clientId: options.clientId,
clientSecret: options.clientSecret,
authorizationEndpoint: Uri.parse('$baseUrl/login/oauth/authorize'),
tokenEndpoint: Uri.parse('$baseUrl/login/oauth/access_token'),
userInfoEndpoint: Uri.parse('$apiBaseUrl/user'),
redirectUri: options.redirectUri,
scopes: options.scopes,
profileParser: GitHubProfile.fromJson,
profileSerializer: (profile) => profile.toJson(),
profile: (profile) {
return AuthUser(
id: profile.id.toString(),
name: profile.name ?? profile.login,
email: profile.email,
image: profile.avatarUrl,
attributes: profile.toJson(),
);
},
profileRequest: (_, _, token, httpClient, profile) async {
if (profile.email != null && profile.email!.isNotEmpty) {
return profile;
}
final emails = await _loadGitHubEmails(token, httpClient, apiBaseUrl);
if (emails.isEmpty) return profile;
final primary = emails.firstWhere(
(entry) => entry.primary && entry.verified,
orElse: () => emails.first,
);
return profile.copyWith(email: primary.email);
},
);
}