A Flutter plugin for integrating Snapchat login kit into your Flutter applications, allowing users to log in with their Snapchat accounts.
- Snapchat login: Enable users to log in to your app using their Snapchat credentials.
- Subscribe / Unsubscribe to Login State Updates: Subscribe or Unsubscribe to updates about the success of the login process.
- Send Requests to Get User Data: After Successful login, Get the user information such as displayName, AvatarUrl, AvatarId, externalId, tokenId and profileLink.
- Query Login State: Check if the user is already logged in to Snapchat.
- Fetch Access Token: Retrieve the access token after a successful login, which can be used to make API calls to Snapchat on behalf of the user.
- Access To Scope: Check if the user has granted access to a specific scope (permission) in their Snapchat account.
- Login With Firebase: Integrate Firebase authentication with Snapchat login, allowing users to log in to your app using Firebase authentication after logging in with Snapchat.
First thing first, you must login to your developer account on Snapchat Developers portal and get your Client ID for the app. For more information you can read the docs Login Kit.
The Client ID is different for Production and Staging environment. So be careful to use the correct values. Note: To use Production Client ID, your snapchat app should be approved and live on snapchat developer portal. Read more about submitting app for review.
It is necessary to perform platform-specific configuration setups first.
Snapchat Scopes let your application declare which Login Kit features it wants access to. If a scope is toggleable, the user can deny access to one scope while agreeing to grant access to others.
In :android module, define snap_connect_scopes
as an Android resource array in values/arrays.xml
.
Define the following values in local.properties
file under :android module.
#sdk.dir=PATH_TO_ANDROID_SDK
# staging env for snapkit
# Your app’s client id
com.snap.kit.clientId=YOUR_APP_CLIENT_ID
# The url that will handle login completion
com.snap.kit.redirectUrl=REDIRECT_URL
# Enter the parts of your redirect url below
# e.g., if your redirect url is myapp://snap-kit/oauth2
# android:scheme="myapp"
# android:host="snap-kit"
# android:path="oauth2"
com.snap.kit.scheme=SCHEME
com.snap.kit.host=HOST
com.snap.kit.path=PATH
# Set the firebase custom token url
com.snap.kit.firebaseExtCustomTokenUrl=FIREBASE_CUSTOM_TOKEN_URL
Inside the app's build.gradle
use manifestPlaceholders attribute to pass these values to login kit. Read more about configuring build types in android.
- Depending on your requirements, you can either setup only one configuration for all
productFlavors
android {
defaultConfig {
manifestPlaceholders = [
SNAP_CLIENT_ID : localProperties.getProperty("com.snap.kit.clientId"),
SNAP_REDIRECT_URL : localProperties.getProperty("com.snap.kit.redirectUrl"),
SNAP_SCOPES_ARRAY : "@array/snap_connect_scopes",
SNAP_REDIRECT_HOST : localProperties.getProperty("com.snap.kit.host"),
SNAP_REDIRECT_PATH : localProperties.getProperty("com.snap.kit.path"),
SNAP_REDIRECT_SCHEME : localProperties.getProperty("com.snap.kit.scheme"),
FIREBASE_CUSTOM_TOKEN_URL: localProperties.getProperty("com.snap.kit.firebaseExtCustomTokenUrl")
]
}
//...
}
- OR better way, setup different configurations for different
productFlavors
android {
//...
flavorDimensions "environment"
productFlavors {
staging {
manifestPlaceholders = [
SNAP_CLIENT_ID : localProperties.getProperty("com.snap.kit.clientId"),
SNAP_REDIRECT_URL : localProperties.getProperty("com.snap.kit.redirectUrl"),
SNAP_SCOPES_ARRAY : "@array/snap_connect_scopes",
SNAP_REDIRECT_HOST : localProperties.getProperty("com.snap.kit.host"),
SNAP_REDIRECT_PATH : localProperties.getProperty("com.snap.kit.path"),
SNAP_REDIRECT_SCHEME : localProperties.getProperty("com.snap.kit.scheme"),
FIREBASE_CUSTOM_TOKEN_URL: localProperties.getProperty("com.snap.kit.firebaseExtCustomTokenUrl")
]
}
production {
manifestPlaceholders = [
SNAP_CLIENT_ID : localProperties.getProperty("com.snap.kit.clientId"),
SNAP_REDIRECT_URL : localProperties.getProperty("com.snap.kit.redirectUrl"),
SNAP_SCOPES_ARRAY : "@array/snap_connect_scopes",
SNAP_REDIRECT_HOST : localProperties.getProperty("com.snap.kit.host"),
SNAP_REDIRECT_PATH : localProperties.getProperty("com.snap.kit.path"),
SNAP_REDIRECT_SCHEME : localProperties.getProperty("com.snap.kit.scheme"),
FIREBASE_CUSTOM_TOKEN_URL: localProperties.getProperty("com.snap.kit.firebaseExtCustomTokenUrl")
]
}
}
//...
}
NOTE: The same properties name should be used as defined in the local.properties
file.
Add the following fields in your application’s Info.plist
file:
<key>SCSDKClientId</key>
<string>$(SNAP_CLIENT_ID)</string>
<key>SCSDKRedirectUrl</key>
<string>$(SNAP_REDIRECT_URL)</string>
<key>SCSDKScopes</key>
<array>
<string>https://auth.snapchat.com/oauth2/api/user.display_name</string>
<string>https://auth.snapchat.com/oauth2/api/user.external_id</string>
<string>https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar</string>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>snapchat</string>
</array>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(SNAP_REDIRECT_SCHEME)</string>
</array>x
</dict>
</array>
Read Snapchat iOS Documentation for more information.
Adding a Build Configuration file to your project for storing your client id and confidential keys. Let's add SNAP_CLIENT_ID
, SNAP_REDIRECT_URL
and SNAP_REDIRECT_SCHEME
properties in configuration file.
/// Configuration settings file format documentation can be found at:
/// https://help.apple.com/xcode/#/dev745c5c974
/// Snapchat Settings
/// your app’s client id
SNAP_CLIENT_ID = YOUR_CLIENT_ID
/// the url that will handle login completion
SNAP_REDIRECT_URL = YOUR_REDIRECT_URL
/// This should contain your redirect URL’s scheme
SNAP_REDIRECT_SCHEME = YOUR_REDIRECT_SCHEME
- OR better way, setup different configurations file for different
productFlavors
NOTE: Now, whenever we push code to our repo, we can make sure that config file does not reach the server by adding it in .gitignore
In AppDelegate
, use the SCSDKLoginClient
interface to receive the deeplink:
import SCSDKLoginKit
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
...
if SCSDKLoginClient.application(app, open: url, options: options) {
return true
}
...
}
After the perform platform-specific configuration setups, add snapchat_loginkit:
as a dependency in your pubspec.yaml file.
Then run flutter pub get
to install the package.
Now in your Dart code, you can use:
import 'package:snapchat_loginkit/snapchat_loginkit.dart';
class _MyAppState extends State<MyApp>{
/// Declaring a SnapchatLoginkit variable
late final SnapchatLoginkit _snapchatLoginkitPlugin;
@override
void initState() {
super.initState();
/// Initializing the _snapchatLoginkitPlugin variable
_snapchatLoginkitPlugin = SnapchatLoginkit(loginStateCallback: this);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Snapchat loginkit example'),
),
body: Container(),
),
);
}
}
To login, use login()
.
LoginStateCallback Provides methods to handle Snapchat login callbacks.
Use [LoginStateCallback] methods to listen to login events such as success, failure, start, and logout.
class _MyAppState extends State<MyApp> implements LoginStateCallback {
/// Declaring a SnapchatLoginkit variable
late final SnapchatLoginkit _snapchatLoginkitPlugin;
@override
void initState() {
super.initState();
/// Initializing the _snapchatLoginkitPlugin variable
_snapchatLoginkitPlugin = SnapchatLoginkit(loginStateCallback: this);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Snapchat loginkit example'),
),
body: Center(child: ElevatedButton(
onPressed: () {
/// call login event
/// LoginStateCallback Provides methods to handle Snapchat login callbacks.
_snapchatLoginkitPlugin.login();
},
child: const Text('Login with Snapchat'),
),
),
),
);
}
/// Callback method invoked when the login process fails.
@override
void onFailure(String message) {}
/// Callback method invoked when the user logs out.
@override
void onLogout() {}
/// Callback method invoked when the login process starts.
@override
void onStart() {}
/// Callback method invoked when the login process is successful.
@override
void onSuccess(String accessToken) async {}
}
To subscribe to updates about the success of the login process, use addLoginStateCallback()
.
To unsubscribe from login updates, use removeLoginStateCallback()
.
class _MyAppState extends State<MyApp> implements LoginStateCallback {
/// Declaring a SnapchatLoginkit variable
late final SnapchatLoginkit _snapchatLoginkitPlugin;
@override
void initState() {
super.initState();
/// Initializing the _snapchatLoginkitPlugin variable
_snapchatLoginkitPlugin = SnapchatLoginkit(loginStateCallback: this);
/// Subscribe for login updates
_snapchatLoginkitPlugin.addLoginStateCallback();
}
@override
void dispose() {
/// Unsubscribe from login updates
_snapchatLoginkitPlugin.removeLoginStateCallback();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Snapchat loginkit example'),
),
body: Container(),
),
);
}
/// Callback method invoked when the login process fails.
@override
void onFailure(String message) {}
/// Callback method invoked when the user logs out.
@override
void onLogout() {}
/// Callback method invoked when the login process starts.
@override
void onStart() {}
/// Callback method invoked when the login process is successful.
@override
void onSuccess(String accessToken) async {}
}
Once a user logs into your app with Snapchat, you can make requests for their displayName
, AvatarUrl
, AvatarId
, externalId
, tokenId
and profileLink
.
Construct the user data query
UserDataQuery query = UserDataQueryBuilder()
/// optional: for 'displayName' resource
.withDisplayName()
/// optional: for ‘bitmoji’ resource
.withBitmojiAvatarId()
.withBitmojiAvatarUrl()
/// optional: for 'externalID' resource
.withExternalId()
/// optional: for Snap OIDC (OpenID Connect) token
/// Snap OIDC (OpenID Connect) provides a generic authentication and identity solution
/// that allows otherwise different systems to interoperate and share authentication state
/// and user profile information.
/// Typically, this allows 3rd party backend services to accept and authenticate requests
/// from Snap clients.
.withIdToken()
/// optional: for 'profileLink' resource
.withProfileLink()
.build();
Call the fetch API
UserResponse userResponse = await _snapchatLoginkitPlugin.fetchUserData(query);
/// handle the response code
debugPrint("User Code: ${userResponse.code}");
/// handle the response message
debugPrint("User Message: ${userResponse.message}");
/// handle the response user
debugPrint("User: ${userResponse.user}");
/// get user display name
final displayName = userResponse.user.displayName;
/// get user avatar url
final avatarUrl = userResponse.user.avatarUrl;
/// get user avatar id
final avatarId = userResponse.user.avatarId;
/// get user external id
final externalId = userResponse.user.externalId;
/// get user token id
final tokenId = userResponse.user.tokenId;
/// get user profile link
final profileLink = userResponse.user.profileLink;
To check whether a user is currently logged in, use isUserLoggedIn()
/// Query user’s logged-in state
bool isUserLoggedIn = await _snapchatLoginkitPlugin.isUserLoggedIn();
Retrieve the access token after a successful login, use fetchAccessToken()
final response = await _snapchatLoginkitPlugin.fetchAccessToken();
/// handle response code
debugPrint("Token Code: ${response.code}");
/// handle response meesage
debugPrint("Token Message: ${response.message}");
/// get access token
debugPrint("Token Token: ${response.token}");
Check if the user has granted access to a specific scope (permission) in their Snapchat account. use hasAccessToScope('scope')
/// Login Kit offers the following scopes:
/// https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar
/// https://auth.snapchat.com/oauth2/api/user.display_name
final bool hasAccess = await _snapchatLoginkitPlugin.hasAccessToScope('https://auth.snapchat.com/oauth2/api/user.display_name');
Users to authenticate with Firebase using their Snapchat accounts. Define the com.snap.kit.firebaseExtCustomTokenUrl=firebaseExtCustomTokenUrl
value in local.properties
file under :android module.
Before call this method loginWithFirebase()
you should need to provide Firebase extension token url. for more help, how to generate firebase extension token url visit
Firebase Extension Token Url Android , Firebase Extension Token Url iOS
A user can choose to end the current OAuth2 Snapchat session and stop sharing their Display Name and Bitmoji avatar with your app.
The logout()
method can be used to clear the access.
/// Clear the access and refresh token locally
_snapchatLoginkitPlugin.logout();
Have a bug or a feature request? Please first search for existing and closed issues. If your problem or idea is not addressed yet, please open a new issue.
Contributions, issues, and feature requests are welcome!
Give a star if this project helped you.