Login Kit

Login Kit lets your users authenticate with Snapchat and bring their existing identity into your app. It uses OAuth, with Snapchat as the identity provider.

Understanding Scopes

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.

Login Kit offers the following scopes:

  • https://auth.snapchat.com/oauth2/api/user.display_name: Grants access to the user's Snapchat display name
  • https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar: Grants access to the user's Bitmoji avatar; toggleable by user

When you specify which scopes you'd like, use the full URL, like this:

  <key>SCSDKScopes</key>
  <array>
    <string>https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar</string>
    <!-- other scopes you might have... -->
  </array>

iOS

Login Kit iOS gives you access to two Snapchat features, login and identity. Logging in via Snapchat removes the obstacles of signup and login for new users. The display name and Bitmoji avatar give users a familiar identity within your app.

Requirements

  • Client ID from the developer portal
  • iOS version 10.0+

Getting started

Get comfortable with the Snap Kit developer portal. This is where you'll actually create and submit your Snap Kit application. Our docs expect you to make changes in the dev portal as well as in your project files.

In your app project in Xcode, add SCSDKCoreKit.framework and SCSDKLoginKit.framework into General > Embedded Binaries.

Add the following fields in your application’s Info.plist file:

  • SCSDKClientId (string): This is your application’s client ID, used for OAuth. Copy it from the developer portal, under App Info > OAuth2 Client ID.
  • SCSDKRedirectUrl (string): This URL will handle and complete login requests. Use any naming convention that works for you, with the URL syntax foo://bar. If you need ideas, you could try myapp://snap-kit/oauth2.
  • SCSDKScopes (string-array): Your application will request scopes of access from the user. For help defining scopes, see the Understanding Scopes section above.
  • LSApplicationQueriesSchemes (string-array): This should contain snapchat, bitmoji-sdk, and itms-apps.
  • CFBundleURLSchemes (string-array): This should contain your redirect URL’s scheme. If your redirect URL is myapp://snap-kit/oauth2, this field would be myapp.

Note: In the Snap Kit developer portal, add the same URL you put in Info.plist to your app's Redirect URLs. Without this, you'll get an error when your app tries to open Snapchat for OAuth.


Initiating login with Snapchat

First, import the login button. When a user taps the Log In with Snapchat button in your app, it directs them to Snapchat if they have it installed. If not, it prompts them to log in with Snapchat through an in-app web view. Pass in a completion handler to let your app know what to do once users successfully log into Snapchat.

// swift

import SCSDKLoginKit

let loginButton = SCSDKLoginButton() { (success : Bool, error : Error?) in
    // do something
}
// objc

#import <SCSDKLoginKit/SCSDKLoginKit.h>

SCSDKLoginButton *loginButton =  [[SCSDKLoginButton alloc] initWithCompletion:^(BOOL success, NSError * _Nullable error) {
                                  // do something
                               }];

Using a custom UI for login? The SCSDKLoginClient supports that. Pass in a completion handler to let your app know what to do once users successfully log into Snapchat.

// swift

import SCSDKLoginKit

SCSDKLoginClient.login(from: viewController) { (success : Bool, error : Error?) in
    // do something
}
// objc

#import <SCSDKLoginKit/SCSDKLoginKit.h>

[SCSDKLoginClient loginFromViewController:viewController
                               completion:^(BOOL success, NSError * _Nullable error) {
                                  // do something
                               }];

Finishing login with Snapchat

Once your user successfully authorizes your app to log in with Snapchat, you need to handle the deeplink that comes from Snapchat to get the access token.

In AppDelegate.m, use the SCSDKLoginClient interface to receive the deeplink:

// swift

import SCSDKLoginKit

func application(
  _ app: UIApplication,
  open url: URL,
  options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
  ...
    if SCSDKLoginClient.application(app, open: url, options: options) {
      return true
    }
  ...
}
// objc

#import <SCSDKLoginKit/SCSDKLoginKit.h>

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
...
              if ([SCSDKLoginClient application:application openUrl:url options:options]) {
                return YES;
              }
...
}

Note: Access to user data expires after 90 days of inactivity on your app.


Sending requests to get user data

Currently, we support two requests for user data:

  • Get display name
  • Get Bitmoji avatar

Use the SCSDKLoginClient to fetch the Bitmoji avatar URL and Snapchat display name:

// swift

let graphQLQuery = "{me{displayName, bitmoji{avatar}}}"

let variables = ["page": "bitmoji"]

SCSDKLoginClient.fetchUserData(withQuery: graphQLQuery, variables: variables, success: { (resources: [AnyHashable: Any]?) in
  guard let resources = resources,
    let data = resources["data"] as? [String: Any],
    let me = data["me"] as? [String: Any] else { return }

  let displayName = me["displayName"] as? String
  var bitmojiAvatarUrl: String?
  if let bitmoji = me["bitmoji"] as? [String: Any] {
    bitmojiAvatarUrl = bitmoji["avatar"] as? String
  }
}, failure: { (error: Error?, isUserLoggedOut: Bool) in
	// handle error
})
// objc

NSString *graphQLQuery = @"{me{displayName, bitmoji{avatar}}}";

NSDictionary *variables = @{@"page": @"bitmoji"};

[SCSDKLoginClient fetchUserDataWithQuery:graphQLQuery
                               variables:variables
                                 success:^(NSDictionary *resources) {
                                   NSDictionary *data = resources[@"data"];
                                   NSDictionary *me = data[@"me"];
                                   NSString *displayName = me[@"displayName"];
                                   NSDictionary *bitmoji = me[@"bitmoji"];
                                   NSString *bitmojiAvatarUrl = bitmoji[@"avatar"];
                               } failure:^(NSError * error, BOOL isUserLoggedOut) {
                                   // handle error as appropriate
                               }];

Sending requests to get the external ID

Once a user logs into your app with Snapchat, you can make requests for their external ID. This is a unique identifier for this user on your app. The following example requests this identifier for the user that is currently logged in:

// swift

let graphQLQuery = "{me{externalId}}"

SCSDKLoginClient.fetchUserData(withQuery: graphQLQuery, variables: nil, success: { (resources: [AnyHashable: Any]?) in
  guard let resources = resources,
    let data = resources["data"] as? [String: Any],
    let me = data["me"] as? [String: Any] else { return }

  let externalId = me["externalId"] as? String
}, failure: { (error: Error?, isUserLoggedOut: Bool) in
	// handle error
})
// objc

NSString *graphQLQuery = @"{me{externalId}}";

[SCSDKLoginClient fetchUserDataWithQuery:graphQLQuery
                               variables:nil
                  success:^(NSDictionary *resources) {
                    NSDictionary *data = resources[@"data"];
                    NSDictionary *me = data[@"me"];
                    NSString *externalId = me[@"externalId"];
} failure:^(NSError * error, BOOL isUserLoggedOut) {
  // handle error as appropriate
}];

Unlinking

Unlinking current session

A user might want to unlink their current OAuth2 session, which means they’ll lose access to their Bitmoji avatar and display name in your app in this specific session. To enable unlinking, add an unlink authorization option and revoke the previous access token.

// swift

import SCSDKLoginKit

SCSDKLoginClient.unlinkCurrentSessionWithCompletion { (success: Bool) in
  // do something
}
// objc

#import <SCSDKLoginKit/SCSDKLoginKit.h>

[SCSDKLoginClient unlinkCurrentSessionWithCompletion:^(BOOL success) {
  // do something
}];

Once you add and execute this line, your requests from this session to Snapchat will get permission errors. For a good user experience, make sure you stop making those requests after the user unlinks their account with this session.


Unlinking all sessions

A user might want to unlink all existing OAuth2 sessions, which means they’ll lose access to their Bitmoji avatar and display name in your app for all sessions. The app will also be removed from the Connected Apps page in Snapchat. To enable unlinking, add an unlink authorization option and revoke the previous access token.

// swift

import SCSDKLoginKit

SCSDKLoginClient.unlinkAllSessionsWithCompletion { (success: Bool) in
  // do something
}
// objc

#import <SCSDKLoginKit/SCSDKLoginKit.h>

[SCSDKLoginClient unlinkAllSessionsWithCompletion:^(BOOL success) {
  // do something
}];

Once you add and execute this line, your requests to Snapchat will get permission errors. For a good user experience, make sure you stop making those requests after the user unlinks their account with all sessions.


What’s next


Android

Login Kit Android gives you access to two Snapchat features, login and identity. Logging in via Snapchat removes the obstacles of signup and login for new users. The display name and Bitmoji avatar give users a familiar identity within your app.

Requirements

  • Client ID from the developer portal
  • Android Studio 3.0+
  • Gradle 3.0+
  • Android API Level 19+

To connect your app to Snapchat, your app must also have the following targets:

  • Android support library version 22+
  • Snapchat 10.34.0.0+

Getting started

We share the Login Kit and Core Kit AARs from our Maven repository. To access them, add the following code block to your root project's build.gradle file:

repositories {
   maven {
       url "https://storage.googleapis.com/snap-kit-build/maven"
   }
}

Note: If you have trouble accessing Google (used in the link above), you can use our GitHub Maven repository with the following code block:

repositories {
   maven {
       url "https://raw.githubusercontent.com/Snap-Kit/release-maven/repo"
   }
}

Next, add the following implementation to the dependencies section of your application’s build.gradle file, not the root project’s build.gradle:

dependencies {
   ...
   implementation([
           'com.snapchat.kit.sdk:login:1.1.4',
           'com.snapchat.kit.sdk:core:1.1.4'
   ])
}

Finally, add your application’s client ID, redirect URL, and scopes to the appropriate meta-data tags in your application’s AndroidManifest.xml. The SDK automatically fetches these values to enable deeplinking from your app to Snapchat. For a list of available scopes, please see the Understanding Scopes section of this document

<uses-permission android:name="android.permission.INTERNET" />

<application ...>
   <meta-data android:name="com.snapchat.kit.sdk.clientId" android:value="your app’s client id" />
   <meta-data android:name="com.snapchat.kit.sdk.redirectUrl" android:value="the url that will handle login completion" />
   <meta-data android:name="com.snapchat.kit.sdk.scopes" android:resource="@array/snap_connect_scopes" /> <!-- This should be a string array of scopes !-->

   ...

   <activity
       android:name="com.snapchat.kit.sdk.SnapKitActivity"
       android:launchMode="singleTask"
       >
       <intent-filter>
           <action android:name="android.intent.action.VIEW" />
           <category android:name="android.intent.category.DEFAULT" />
           <category android:name="android.intent.category.BROWSABLE" />
           <!--
               Enter the parts of your redirect url below
               e.g., if your redirect url is myapp://snap-kit/oauth2
                   android:scheme="myapp"
                   android:host="abc"
                   android:path="/xy/z"
           !-->
           <data
               android:scheme="the scheme of your redirect url"
               android:host="the host of your redirect url"
               android:path="the path of your redirect url"
               />
       </intent-filter>

   </activity>

   ...
</application>

In the example above, you'll have to define snap_connect_scopes as an Android resource array in values/arrays.xml. Example:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="snap_connect_scopes">
        <item>https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar</item>
    </string-array>
</resources>

Initiating login with Snapchat

The SDK provides a button that initiates the Snapchat login process. A tap on this button in your app redirects users to Snapchat if they have it installed. If not, it prompts them to log in with Snapchat through an in-app web view.

To add the login button to your app, add the import and view below. This adds the button to your desired root view with the default styling.

import com.snapchat.kit.sdk.SnapLogin;

View mLoginButton = SnapLogin.getButton(getContext(), (ViewGroup)mViewRoot);

To add the login flow using a custom button, it’s a little different:

View yourView = findViewById(...);
yourView.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick() {
        SnapLogin.getAuthTokenManager(this).startTokenGrant();
   }
});

Now when a user taps the button, your app will start auth with Snapchat!


Subscribing to login state updates

For updates on the success of this login process, define an onLoginStateChangedListener:

// Import needed for LoginStateController
import com.snapchat.kit.sdk.core.controller.LoginStateController;

final LoginStateController.OnLoginStateChangedListener mLoginStateChangedListener =
    new LoginStateController.OnLoginStateChangedListener() {
        @Override
        public void onLoginSucceeded() {
            // Here you could update UI to show login success
        }

        @Override
        public void onLoginFailed() {
            // Here you could update UI to show login failure
        }

        @Override
        public void onLogout() {
            // Here you could update UI to reflect logged out state
        }
    };

// Add the LoginStateChangedListener you’ve defined to receive LoginInState updates
SnapLogin.getLoginStateController(getContext()).addOnLoginStateListener(mLoginStateChangedListener);

```java

To unsubscribe your `LoginStateChangedListener` from updates, use the following line:

```java
SnapLogin.getLoginStateController(this).removeOnLoginStateChangedListener(mLoginStateChangedListener);

Querying login state

To check whether the user is currently logged in, use SnapLogin.isUserLoggedIn:

boolean isUserLoggedIn = SnapLogin.isUserLoggedIn(getContext());

Sending requests to get user data

Once a user logs into your app with Snapchat, you can make requests for their display name or Bitmoji avatar. The following example makes a request for both. Upon success, this example callback loads the display name into a TextView mDisplayNameTextView and loads the Bitmoji into an ImageView mBitmojiImageView:

String query = "{me{bitmoji{avatar},displayName}}";
String variables = null;
SnapLogin.fetchUserData(this, query, variables, new FetchUserDataCallback() {
    @Override
    public void onSuccess(@Nullable UserDataResponse userDataResponse) {
        if (userDataResponse == null || userDataResponse.getData() == null) {
            return;
        }

        MeData meData = userDataResponse.getData().getMe();
        if (meData == null) {
            return;
        }

        mNameTextView.setText(userDataResponse.getData().getMe().getDisplayName());

        if (meData.getBitmojiData() != null) {
            Glide.with(getContext())
                    .load(meData.getBitmojiData().getAvatar())
                    .into(mBitmojiImageView);
        }
    }

    @Override
    public void onFailure(boolean isNetworkError, int statusCode) {

    }
});

Sending requests to get the external ID

Once a user logs into your app with Snapchat, you can make requests for their external ID. This is a unique identifier for this user on your app. The following example requests this identifier for the user that is currently logged in and saves it for use in other Snap Kit features:

String query = "{me{externalId}}";
SnapLogin.fetchUserData(this, query, null, new FetchUserDataCallback() {
    @Override
    public void onSuccess(@Nullable UserDataResponse userDataResponse) {
        if (userDataResponse == null || userDataResponse.getData() == null) {
            return;
        }

        MeData meData = userDataResponse.getData().getMe();
        if (meData == null) {
            return;
        }

        mBackend.save(userDataResponse.getData().getMe().getExternalId());
    }

    @Override
    public void onFailure(boolean isNetworkError, int statusCode) {

    }
});

Unlinking

A user can choose to end the current OAuth2 Snapchat session and no longer share their display name and Bitmoji avatar with your app. The app will also be removed from the Connected Apps page in Snapchat. However, if the user has multiple ongoing sessions, another session may still work. To kill the current OAuth2 session, use:

SnapLogin.getAuthTokenManager(this).revokeToken();

Note: Once the revokeToken() command is executed, fetchUserData() requests will result in permission errors.

What’s next

Web

Login Kit Web gives you access to two Snapchat features, login and identity. Logging in via Snapchat removes the obstacles of signup and login for new users. The display name and Bitmoji avatar give users a familiar identity within your app.

Requirements

Getting started

The only requirement for using Login Kit on web is that your network is able to access the JavaScript bundle login.js.

Adding the login button

The login button prompts users to log in with Snapchat and sends back basic information about the logged in user to your app.

Client-side-only web application integration

Quickly integrate a login button into your web app with this temporary access flow.

The OAuth2.0 implicit grant flow used in this integration provides a one-time access token. This means that when users click Continue with Snapchat and authorize your app, you will be provided a token to fetch information about that user — but only for one hour.

If you only need to get user data once (or very infrequently), for example to bootstrap a user account in your own application's database, then the implicit grant flow may be sufficient.

If you need continual access to the Snapchat user data, however, then we recommend you set up a server and following the server-side integration steps.

Adding Login Kit icon HTML example

First, add an HTML div to the page in your application where you want to add the login button UI. Give your div element a unique class name like the one below. This div element will be the target for the Login Kit SDK UI. More specifically, this is where the login button UI button will be mounted.

/********************** HTML EXAMPLE **********************/
<html lang="en">
  <body>
    <div id="my-login-button-target" />
  </body>
</html>

Next, add a script tag into the the above HTML example to load the SDK asynchronously.

/********************** HTML EXAMPLE **********************/
<html lang="en">
  <body>
    <div id="my-login-button-target" />
    <script>
      // Load the SDK asynchronously
      (function (d, s, id) {
        var js, sjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "https://sdk.snapkit.com/js/v1/login.js";
        sjs.parentNode.insertBefore(js, sjs);
      }(document, 'script', 'loginkit-sdk'));
    </script>
  </body>
</html>

To get notified when the SDK is loaded, define a callback with the following signature:

window.snapKitInit = function () { /* Add your code here */ }

Next, add the arguments required by mountButton (in the API) to mount the login button in the SDK callback. Refer to Login Kit Parameter Definitions for an explanation of each parameter in the API.

Finally, call the API to mount the login button.

Adding Login Kit button example full code
/********************** HTML EXAMPLE **********************/
<html lang="en">
  <body>
    <div id="my-login-button-target" />
    <script>
       window.snapKitInit = function () {
        var loginButtonIconId = 'my-login-button-target';
        // Mount Login Button
        snap.loginkit.mountButton(loginButtonIconId, {
          clientId: 'your-clientId',
          redirectURI: 'your-redirectURI',
          scopeList: [
            'user.display_name',
            'user.bitmoji.avatar',
          ],
          handleResponseCallback: function() {
            snap.loginkit.fetchUserInfo()
              .then(data => console.log('User info:', data));
          },
        });
      };

      // Load the SDK asynchronously
      (function (d, s, id) {
        var js, sjs = d.getElementsByTagName(s)[0];
        if (d.getElementById(id)) return;
        js = d.createElement(s); js.id = id;
        js.src = "https://sdk.snapkit.com/js/v1/login.js";
        sjs.parentNode.insertBefore(js, sjs);
      }(document, 'script', 'loginkit-sdk'));
    </script>
  </body>
</html>
Server-side web application integration

The OAuth2.0 authorization grant flow we follow for this integration provides refreshable offline access tokens. These access tokens enable users to access features of the Login Kit SDK and require the user to only authorize your application once. This approach is a bit more involved, with three main steps:

Update the Login Kit integration code to override the login callback. Add backend server code to handle request/response from Snap’s authorization endpoints and manage token flows. Update the Login Kit component on your web client with the access token retrieved from your backend.

To write code for the server, use any language you’re comfortable in. We use JavaScript in our examples.

1. Update the login kit UI code to override login callback

Update the Login Kit integration code to override the login button’s onClick handler. By passing in a callback that calls a backend handler implemented by your application, you kick off the OAuth2.0 Authorization Code grant flow. Specify a callback parameter handleAuthGrantFlowCallback in the loginParamsObj.

Update the previous [simple HTML and ES5 JavaScript example]:

var loginButtonIconId = 'my-login-button-target';
var loginParamsObj = {
  // Override this parameter `handleAuthGrantFlowCallback`
  handleAuthGrantFlowCallback:
    function handleAuthGrantFlowCallback(){
      // TO START THE OAUTH2.0 AUTHORIZATION
      // GRANT FLOW, POINT THIS CALLBACK TO
      // YOUR APPLICATION’S BACKEND HANDLER
    },
  clientId: 'your-clientId',
  redirectURI: 'your-redirectURI', // REMOVE THIS
  scopeList: ['your-scope(s)'], // REMOVE THIS
};
2. Add backend server code to handle request/response

See how your web server application can implement the OAuth2.0 authorization grant flow to access Snap data — for example, obtaining permission from the user to retrieve avatar data.

Adding the OAuth2.0 flow involves several steps.

Applications that implement this authorization type will be responsible for the following:

  • Managing the access token request flow for each user that authorizes your app
  • Managing the refresh flow for expiring access tokens
  • Managing the revocation flow for access tokens
  • Keeping their client secret and refresh tokens secure
2.1 Set up OAuth2.0 parameters

To make the initial redirect request to Snap’s authorization server, you need to generate the parameter: state.

ParameterDefinition
state"state” is a base64 URL encoded string. This value is used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery.

Feel free to use any language to generate the parameters’ values. We use JavaScript.

In JavaScript, the easiest way to generate these values is with the crypto module provided by NodeJS. It lets you make wrapper functions to create RFC-compliant values. See the crypto library helper below. The most important functions here are generateBase64UrlEncodedString(bytesToEncode) and generateRandomBytes(size) which help generate all three parameters.

// ******************** Crypto Library Helper ***************************
var _crypto = require('crypto');

var OAUTH2_STATE_BYTES = 32;
var REGEX_PLUS_SIGN = /\+/g;
var REGEX_FORWARD_SLASH = /\//g;
var REGEX_EQUALS_SIGN = /=/g;

/*
 * This function generates a random amount of bytes using the
 * crypto library
 *
 * @param {int} size - The number of random bytes to generate.
 *
 * @returns {Buffer} The generated number of bytes
 */
var generateRandomBytes = function generateRandomBytes(size) {
  return _crypto.randomBytes(size);
};

/*
 * This function encodes the given byte buffer into a base64 URL
 * safe string.
 *
 * @param {Buffer} bytesToEncode - The bytes to encode
 *
 * @returns {string} The URL safe base64 encoded string
 */
var generateBase64UrlEncodedString = function generateBase64UrlEncodedString(bytesToEncode) {
  return bytesToEncode
    .toString('base64')
    .replace(REGEX_PLUS_SIGN, '-')
    .replace(REGEX_FORWARD_SLASH, '_')
    .replace(REGEX_EQUALS_SIGN, '');
};

/*
 * This function generates the state required for both the
 * OAuth2.0 Authorization and Implicit grant flow
 *
 * @returns {string} The URL safe base64 encoded string
 */
var generateClientState = exports.generateClientState = function generateClientState() {
  return generateBase64UrlEncodedString(
    generateRandomBytes(OAUTH2_STATE_BYTES)
  );
};

You can use the function generateClientState() to help generate the parameter you need.

2.2 Redirect to Snap OAuth2.0 server

To redirect to the Snap authorization server, the OAuth2.0 parameters must be added as well.

Now that you have the query parameters generated, add the additional OAuth2.0 parameters.

ParameterDefinition
client_idThe client ID Snap assigned to your application when you signed up for Snap Kit, the value is a 36 character alphanumeric string.
client_secretThe client secret Snap assigned to your application when you signed up for Snap Kit. The value is a BASE64 URL encoded string.
redirect_uriThe redirect URI that you requested for your application.
scopeA URL safe space-delimited string of OAuth2.0 token scopes. These scope(s) were assigned to your application when you sign up for Snap Kit. These scopes handle what content your application can and cannot access.
As an example, if your application is assigned the OAuth2.0 scopes “ https://auth.snapchat.com/oauth2/api/example.abc” and “ https://auth.snapchat.com/oauth2/api/example.xyz” . Then your scope value would be: “https%3A%2F%2Fauth.snapchat.com%2Foauth2%2Fapi%2Fexample.abc%20https%3A%2F%2Fauth.snapchat.com%2Foauth2%2Fapi%2Fexample.xyz”
response_typeValue MUST be set to “code”.

To authorize your application, build a GET request and redirect the user to it. The table below outlines the redirect endpoint and the query parameters required to access it.

Request URL For User Consent

TypeDescription
GET Requesthttps://accounts.snapchat.com/accounts/oauth2/auth
Queryclient id=<client id>&redirect uri=<redirect uri>&response_type=code&scope= < scope > &state= < state >

Note: The redirect endpoint can only be accessed via HTTPS.

Create a helper function to build out your URL.

// ******************** URL Builder Helper ***********************

var _qs = require('qs'); // Will need to 'npm install qs'

var getAuthCodeRedirectURL = function getAuthCodeRedirectURL(clientId, redirectUri, scopeList, state) {
  var SNAP_ACCOUNTS_LOGIN_URL = 'https://accounts.snapchat.com/accounts/oauth2/auth';
  var scope = scopeList.join(' ');
  var loginQS = {
    client_id: clientId,
    redirect_uri: redirectUri,
    response_type: 'code',
    scope: scope,
    state: state
  };

  var stringifyLoginQS = _qs.stringify(loginQS);
  return SNAP_ACCOUNTS_LOGIN_URL + '?' + stringifyLoginQS;
};

Now, create a quick ExpressJS application. In this example, whenever the user hits the the URL ‘http://localhost:3000/send-oauth-GET-request-step-two’, the server builds the redirect URL and sends the user to it.

// ******************** ExpressJS Server Main Logic ************************

var express = require('express'); // Will need to 'npm install express'
var app = express();

var clientId = 'my-assigned-client-id';
var clientSecret = 'my-assigned-client-secret';
var redirectUri = 'https://my-redirect-uri.com';
var scopeList = ['https://auth.snapchat.com/oauth2/api/example.abc', 'https://auth.snapchat.com/oauth2/api/example.xyz'];

app.get('/send-oauth-GET-request-step-two', function(req, res){
  // Generate query parameters
  var state = generateClientState();

  // Build redirect URL
  var getRedirectURL = getAuthCodeRedirectURL(clientId, redirectUri, scopeList, state);

  // Redirect user to get consent
  res.redirect(getRedirectURL);
});

app.listen(3000);

The redirect URL takes the user to Snapchat login.

After logging in, a page asks the user for consent to allow your application to retrieve the data it requests. In the example below, the application Bitmoji Chrome Extension asks for the user's consent to retrieve their avatar data.

2.4 Handle OAuth2.0 server response

Your application needs to handle two scenarios for this step. The user can either approve or not approve your application’s requested scopes.

If the user approves your application, then an authorization code response will be sent as part of the URL parameter via the given redirect URI you specified in the original request. The response will contain an an authorization code—a series of numbers and letters—and the state that was originally sent. You will need to validate that the state sent is equal to the state received. That response looks like this:

<redirect_uri>?code=123Abx23kdjfhdfjdf2&state=StYxxll233jdfjdlf

If the user does not approve your application, they're redirected to Snapchat login.

2.5 Exchange authorization code for refresh and access token

If the user gives consent to your application, you get an authorization code to retrieve the user’s access token. This authorization code expires after 10 minutes of grant. The required OAuth2.0 parameters for this step are outlined below.

ParameterDefinition
client_idThe client ID Snap assigned to your application when you signed up for Snap Kit. The value is a 36 character alphanumeric string.
client_secretThe client secret Snap assigned to your application when you signed up for Snap Kit. The value is a BASE64 URL encoded string.
redirect_uriThe redirect URI that you requested for your application.
grant_typePossible values include “authorization code” or “refresh token”.
codeThe authorization code received from the authorization server.

Build a POST request with the header and payload (which includes authorization code from the OAuth2.0 response) outlined below.

Requesting an Access Token for A User

TypeDescription
POST Requesthttps://accounts.snapchat.com/accounts/oauth2/token
HeaderAuthorization: Basic BASE16(<client id>:<client secret>)
Payloadgrant type=authorization code&redirect uri=<redirect uri>&code= < code >

If the request is successful, the response returns these values: access_token, refresh_token, and expires_in. Persist these values in your backend; you’ll need this data to access Snapchat features and persist access.

// Success Response Body
{
    access_token: <string>,
    refresh_token: <string>,
    expires_in: <time in seconds>
}

If the request is not successful, the response returns the data error and error_description in the response body.

// Error Response Body
{
    error: <ascii error code>,
    error_description: <human readable error description>
}

Update your previous ExpressJS example to include requesting access token for a user. Use an additional package, called ‘request’, to make HTTP requests. In this example, whenever the user hits the the URL ‘http://localhost:3000/send-access-token-POST-request-step-five’, the server builds the POST request and sends it to Snapchat’s authorization endpoint.

// ******************** ExpressJS Server Main Logic ************************

var express = require('express'); // will need to 'npm install express'
var request = require('request'); // will need to 'npm install request'

var app = express();

var clientId = 'my-assigned-client-id';
var clientSecret = 'my-assigned-client-secret';

var redirectUri = 'https://my-redirect-uri.com';
var scopeList = ['https://auth.snapchat.com/oauth2/api/example.abc', 'https://auth.snapchat.com/oauth2/api/example.xyz'];

app.get('/send-oauth-GET-request-step-two', function(req, res){
   // ..
});

app.get('/send-access-token-POST-request-step-five', function(req, res) {
  var SNAPCHAT_AUTH_ENDPOINT = 'https://accounts.snapchat.com/accounts/oauth2/token';
  var auth_code = 'received-auth-code-xyz';

  var authorizationHeader = clientId + ':' + clientSecret;
  var authorizationHeaderBase64 = Buffer.from(authorizationHeader).toString('base64');

  // Set headers
  var headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + authorizationHeaderBase64
  }

  // Configure access token POST request
  var options = {
    url: SNAPCHAT_AUTH_ENDPOINT,
    method: 'POST',
    headers: headers,
    form:{
      grant_type: 'authorization_code',
      code: auth_code,
      redirect_uri: redirectUri,
      client_id: clientId,
    }
  };

  // Start POST request
  request(options, function (error, response, body) {
      // Handle success and error responses here
      // Make sure to persist access_token, refresh_token, and expires_in
      res.send(response)
  })
});

app.listen(3000);
2.6 (Offline) Refreshing access token

The access_token retrieved expires hourly, but it can be refreshed offline without user consent. Find the expiry data in expires_in and have your application refresh the access_token before that expiry. Use the required OAuth2.0 parameters below for this step.

ParameterDefinition
client_idThe client ID Snap assigned to your application when you signed up for Snap Kit, the value is a 36 character alphanumeric string.
client_secretThe client secret Snap assigned to your application when you signed up for Snap Kit. The value is a BASE64 URL encoded string.
grant_typePossible values include “authorization code” or “refresh token”.
refresh_tokenThe user's refresh token received from the authorization server. Used when refreshing an expiring access_token.

In order to refresh access, build a POST request with the header and payload outlined below.

Refreshing An Access Token For A User

TypeDescription
POST Requesthttps://accounts.snapchat.com/accounts/oauth2/token
HeaderAuthorization: Basic BASE16(<client id>:<client secret>)
Payloadgrant type=refresh token&refresh token=<refresh token>

If the request is successful, the the response body returns a new set of data for access_token, refresh_token, and expires_in. Update these values in your backend.

// Success Response Body
{
    access_token: <string>,
    refresh_token: <string>,
    expires_in: <time in seconds>
}

If the request is not successful, the response returns the data error and error_description in the response body.

// Error Response Body
{
    error: <ascii error code>,
    error_description: <human readable error description>
}

Update your ExpressJS example to include requesting access token for a user. You'll use an additional package called ‘request’ to help make HTTP requests. In this example, whenever the user hits the the URL ‘http://localhost:3000/send-refresh-token-POST-request-step-six’, the server builds the POST request and sends it to Snapchat’s authorization endpoint.

// ******************** ExpressJS Server Main Logic ************************

var express = require('express'); // will need to ‘npm install express`
var request = require('request'); // will need to ‘npm install request`

var app = express();

var clientId = 'my-assigned-client-id';
var clientSecret = 'my-assigned-client-secret';

var redirectUri = 'https://my-redirect-uri.com';
var scopeList = ['https://auth.snapchat.com/oauth2/api/example.abc', 'https://auth.snapchat.com/oauth2/api/example.xyz'];

app.get('/send-oauth-GET-request-step-two', function(req, res){
   // ..
});

app.get('/send-access-token-POST-request-step-five', function(req, res) {
  // ..
});

app.get('/send-refresh-token-POST-request-step-six', function(req, res) {
  var SNAPCHAT_AUTH_ENDPOINT = 'https://accounts.snapchat.com/accounts/oauth2/token';

  var authorizationHeader = clientId + ':' + clientSecret;
  var authorizationHeaderBase64 = Buffer.from(authorizationHeader).toString('base64');

  // Set headers
  var headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + authorizationHeaderBase64
  }

  // Configure refresh token POST request
  var options = {
    url: SNAPCHAT_AUTH_ENDPOINT,
    method: 'POST',
    headers: headers,
    form:{
      grant_type: 'refresh_token',
      refresh_token: refresh_token, // refresh_token is value from step six
    }
  };

  // Start POST request
  request(options, function (error, response, body) {
      // Handle success and error responses here
      // Persist new access_token, refresh_token, and expires_in values
      res.send(response)
  })
});

app.listen(3000);
2.7 (Offline) Revoking access token

Sometimes a user might want to revoke access to your application, which they can do from the Snapchat accounts page. We also recommend providing users the option of revoking access via your UI. Use the required OAuth2.0 parameters below for this step.

ParameterDefinition
client_idThe client ID Snap assigned to your application when you signed up for Snap Kit, the value is a 36 character alphanumeric string.
client_secretThe client secret Snap assigned to your application when you signed up for Snap Kit. The value is a BASE64 URL encoded string.
refresh_tokenThe users refresh token received from the authorization server. Will need to be used when refreshing an expiring access_token.

If the user wants to revoke access, build a POST request with the Header and Payload outlined below.

Revoking an Access Token for a User

TypeDescription
POST Requesthttps://accounts.snapchat.com/accounts/oauth2/revoke
HeaderAuthorization: Basic BASE16(<client id>:<client secret>)
Payloadtoken=<refresh_token>

Whether or not the request succeeds, we return server response 200. Regardless of response status, you must discard the user’s access_token and refresh_token.

Update your ExpressJS example to include revoking an access token for a user. In this example, whenever the user hits the URL ‘http://localhost:3000/send-revoke-token-POST-request-step-seven’, the server makes a POST request to revoke the token and sends it to Snapchat’s authorization endpoint.

// ******************** ExpressJS Server Main Logic ************************

var express = require('express'); // Will need to 'npm install express'
var request = require('request'); // Will need to 'npm install request'

var app = express();

var clientId = 'my-assigned-client-id';
var clientSecret = 'my-assigned-client-secret';

var redirectUri = 'https://my-redirect-uri.com';
var scopeList = ['https://auth.snapchat.com/oauth2/api/example.abc', 'https://auth.snapchat.com/oauth2/api/example.xyz'];

app.get('/send-oauth-GET-request-step-two', function(req, res){
   // ..
});

app.get('/send-access-token-POST-request-step-five', function(req, res) {
  // ..
});

app.get('/send-refresh-token-POST-request-step-six', function(req, res) {
  // ..
});

app.get('/send-revoke-token-POST-request-step-seven', function(req, res) {
  var SNAPCHAT_AUTH_REVOKE_ENDPOINT = 'https://accounts.snapchat.com/accounts/oauth2/revoke';

  var authorizationHeader = clientId + ':' + clientSecret;
  var authorizationHeaderBase64 = Buffer.from(authorizationHeader).toString('base64');

  // Set headers
  var headers = {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Authorization': 'Basic ' + authorizationHeaderBase64,
  }

  // configure refresh token POST request
  var options = {
    url: SNAPCHAT_AUTH_REVOKE_ENDPOINT,
    method: 'POST',
    headers: headers,
    form:{
      token: refresh_token, // refresh_token is value from step six
    }
  };

  // Start POST request
  request(options, function (error, response, body) {
      // Clear access_token, refresh_token, and expires_in values
      res.send(response)
  })
});

app.listen(3000);
3. Update Login Button UI

The last step of this process is to update your client code to set the retrieved access_token or any time a new access_token is retrieved via the refresh flow.

The updated signature for the API is:

snap.loginkit.mountButton(loginButtonDivId, loginParams, accessToken);