Home > Web Front-end > JS Tutorial > Social Login for Your SPA: Authenticate Your Users via Google and Facebook

Social Login for Your SPA: Authenticate Your Users via Google and Facebook

Joseph Gordon-Levitt
Release: 2025-02-16 10:14:10
Original
578 people have browsed it

Social Login for Your SPA: Authenticate Your Users via Google and Facebook

Social Login for Your SPA: Authenticate Your Users via Google and Facebook

The number of web applications with a single page application architecture is increasing. This type of application loads the entire application into the browser as JavaScript. All interactions with the server are performed through an HTTP-based API that returns JSON documents. These applications often require some degree of user-restricted interaction, such as storing user profile details. Implementing this functionality in traditional HTML-based applications is relatively simple, but it is even more tricky in single-page applications that require authentication for each API request.

This article will demonstrate a technique that uses the Passport.js library to implement social logins for multiple providers and thus implement token-based authentication of subsequent API calls.

All source codes for this article are available for download from our GitHub repository.

Key Points

  • Use the Passport.js library to implement social login for Google and Facebook, and enhance user authentication for single-page applications.
  • Select JSON Web Tokens (JWT) for secure token-based API authentication, avoiding session and cookie-based restrictions.
  • Use social login features: simplified UI, no need to store user credentials, and cross-site password reset.
  • Configure Passport with specific modules such as passport-google-oauth, passport-facebook, and passport-jwt to manage authentication and token generation.
  • Use the passport-jwt module to implement token-based authentication, protecting API endpoints by verifying the JWT in the Authorization header.
  • Simplify user experience with redirect mode and client scripts.

Why use social login in your SPA?

Many issues need to be considered when implementing the login mechanism in your web application.

  • How should your UI handle authentication itself?
  • How should you store user information?
  • How should you best protect user credentials?

These and more questions need to be considered before starting to write a login portal. But, there is a better way.

Many websites, mainly social networks, allow you to use their platform to verify your own apps. This is implemented through many different APIs - OAuth 1.0, OAuth 2.0, OpenID, OpenID Connect, etc.

There are many advantages to implementing your login process using these social login technologies.

  • You are no longer responsible for presenting the UI that users use to authenticate.
  • You are no longer responsible for storing and protecting sensitive user details.
  • Users are able to access multiple sites using a single login.
  • If users feel their password has been leaked, they can reset their password once and benefit from many sites.
  • Usually, services that provide authentication capabilities will provide additional details. For example, this can be used to automatically register users who have never used your website, or to allow you to post updates to their profiles on their behalf.

Why use token-based authentication for your API?

Whenever a client needs to access your API, you need some way to determine who they are and whether or not to allow access. There are many ways to achieve this, but the main options are:

  • Session-based authentication
  • Cookie-based authentication
  • Token-based authentication

Session-based authentication requires your API service to associate the session with the client. This is usually very easy to set up, but if you deploy your API on multiple servers, you may have problems. You are also limited by the mechanisms used by the server for session management and expiration, which may not be under your control.

The cookie-based approach is that you simply store some identifiers in the cookie, which will be used to automatically identify the API request. This means that you need some sort of mechanism to set cookies first, and you may leak it in subsequent requests, as the cookies are automatically included in all (appropriate) requests to the same host.

The token-based approach is a variant of cookie-based authentication, but it gives you more control. Essentially, you generate the token in the same way as a cookie-based authentication system, but you include yourself in the request - usually in the "Authorization" header or directly in the URL. This means you have full control over the storage token, which requests will include it, and more.

Note: Even if the HTTP header is called "Authorization", we are actually using it for authentication. This is because we are using it to determine who the client is, not what the client is allowed to do.

The strategy used to generate tokens is also important. These tokens can be reference tokens, meaning they are nothing more than identifiers used by the server to find the real details. Or a complete token, which means that the token already contains all the necessary information.

Referring tokens has a significant security advantage because user credentials are never leaked to the client. However, since you need to parse the token into actual credentials in each request made, there is a performance penalty.

The complete token is the opposite. They expose user credentials to anyone who understands the token, but since the token is complete, there is no performance loss when looking for it.

Usually, full tokens will be implemented using the JSON Web Tokens standard, as this standard allows for improved security of tokens. Specifically, JWT allows encryption tokens, which means you can guarantee that the token has not been tampered with. It is also stipulated that they can be encrypted, meaning that the token cannot even be decoded without an encryption key.

If you want to review using JWT in Node, check out our tutorial: Using JSON Web Tokens with Node.js.

Another disadvantage of using a full token is the size. For example, a reference token can be implemented using a UUID, which is 36 characters in length. Instead, JWT can easily be as long as hundreds of characters.

In this article, we will use JWT tokens to demonstrate how they work. However, when you implement this function yourself, you need to decide whether you want to use a reference token or a full token and what mechanism will be used for this.

What is Passport?

Passport is a set of modules in Node.js for authentication in your web application. It can plug in many Node-based web servers very easily and use a modular structure to implement the login mechanism you need without excessive bloating.

Passport is a powerful module suite that covers a large number of authentication needs. Using these modules, we can create a pluggable setup that allows different authentication requirements for different endpoints. The authentication system used can be as simple as simply checking for special values ​​in the URL, or as complex as relying on a third-party provider to do all the work.

In this article, we will use the passport-google-oauth, passport-facebook, and passport-jwt modules to enable social login and JWT token-based authentication for API endpoints.

passport-jwt module will be used to require that some endpoints—the API endpoints we actually need authentication to access—a valid JWT must exist in the request. The passport-google-oauth and passport-facebook modules will be used to provide endpoints that authenticate against Google and Facebook respectively, and then generate JWTs that can be used to access other endpoints in the app.

Enable social login for your single page application

From here we will walk through how to get a simple single page app and implement social login for it. This application is written in Express, a simple API provides a secure endpoint and an unsafe endpoint. If you want to continue, you can check out the source code of this app from https://github.com/sitepoint-editors/social-logins-spa. This application can be built by executing npm install in the downloaded source code - downloading all dependencies - and then running by executing node src/index.js.

To successfully use the app, you need to register social login credentials with Google and Facebook and provide the credentials to the app. The complete instructions can be found in the README file of the demo application. These credentials are accessed as environment variables. Therefore, the application can be run as follows:

# Linux / OS X
$ export GOOGLE_CLIENTID=myGoogleClientId
$ export GOOGLE_CLIENTSECRET=myGoogleClientSecret
$ export FACEBOOK_CLIENTID=myFacebookClientId
$ export FACEBOOK_CLIENTSECRET=myFacebookClientSecret
$ node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login
# Windows
> set GOOGLE_CLIENTID=myGoogleClientId
> set GOOGLE_CLIENTSECRET=myGoogleClientSecret
> set FACEBOOK_CLIENTID=myFacebookClientId
> set FACEBOOK_CLIENTSECRET=myFacebookClientSecret
> node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

The end result of this process is to add token authentication support (using JSON Web Tokens) to our secure endpoint and then add social login support (using Google and Facebook) to get the rest of the token provisioning use. This means you need to authenticate once using a social provider and then use the generated JWT to make all future API calls in the app.

JWT is a particularly good choice for our scenarios because they are completely self-contained while still being safe. JWT consists of JSON payload and encrypted signature. The payload contains the details of the authenticated user, the authentication system and the validity period of the token. The signature then ensures that a malicious third party cannot forge it—only the person who has the signature key can generate the token.

When reading this article, you will often see references to the config.js module contained as part of your application. This module is used to configure the application and is configured externally using the Node-convict module. The configuration used in this article is as follows:

  • http.port – The port where the application runs. The default is 3000 and is overridden with the "PORT" environment variable.
  • authentication.google.clientId – Google client ID for Google authentication. This is provided to the application through the "GOOGLE_CLIENTID" environment variable.
  • authentication.google.clientSecret – Google client key for Google authentication. This is provided to the application through the "GOOGLE_CLIENTSECRET" environment variable.
  • authentication.facebook.clientId – Facebook client ID for Facebook authentication. This is provided to the application through the "FACEBOOK_CLIENTID" environment variable.
  • authentication.facebook.clientSecret – Facebook client key for Facebook authentication. This is provided to the application through the "FACEBOOK_CLIENTSECRET" environment variable.
  • authentication.token.secret – The key to the JWT that signs our authentication token. The default is "mySuperSecretKey".
  • authentication.token.issuer – The issuer stored in JWT. This indicates which service issues the token, in the case where one authentication service serves many applications.
  • authentication.token.audience – Audience stored in JWT. This represents the target service of the token, in the case where one authentication service serves many applications.

Integrated Passport

A small amount of settings are required before using Passport in your app. This is nothing more than making sure the module is installed and initializing the middleware in your Express application.

The modules required at this stage are the passport modules, and then to set up the middleware, we just need to add it to our Express app.

// src/index.js
const passport = require('passport');
.....
app.use(passport.initialize());
Copy after login
Copy after login
Copy after login

If you follow the instructions on the Passport website, you will be allowed to set up session support - by calling using passport.session(). We do not use any session support in our app, so this is unnecessary. This is because we are implementing a stateless API, so we will provide authentication for each request instead of persisting it into the session.

Implement JWT token authentication for secure endpoints

Setting up JWT token authentication with Passport is relatively simple. We will use the passport-jwt module, which will do all the heavy lifting for us. This module looks for the "Authorization" header with a value beginning with "JWT" ​​and treats the rest of the header as a JWT token for authentication. It then decodes the JWT and provides the values ​​stored there to your own code for operations—for example, performing user lookups. If the JWT is invalid, such as invalid signature, the token has expired... the request will be unauthenticated without additional involvement of your own code.

Then, the method to configure JWT token authentication is as follows:

# Linux / OS X
$ export GOOGLE_CLIENTID=myGoogleClientId
$ export GOOGLE_CLIENTSECRET=myGoogleClientSecret
$ export FACEBOOK_CLIENTID=myFacebookClientId
$ export FACEBOOK_CLIENTSECRET=myFacebookClientSecret
$ node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

Above, we used some internal modules:

  • config.js – Contains configuration properties for our entire application. It can be assumed that these properties have been configured and that the values ​​can be used at any time.
  • users.js – This is the user storage of the application. This allows users to be loaded and created - here we just load users by their internal ID.

Here, we configure the JWT decoder with known keys, publishers, and audiences, and we inform the policy that it should get the JWT from the Authorization header. If either of the publisher or audience does not match what is stored in the JWT, authentication will fail. This gives us another layer of anti-counterfeiting protection, although it is a very simple protection.

Token decoding is entirely processed by the passport-jwt module. We only need to provide the configuration corresponding to the configuration originally used to generate the token. Because JWT is a standard, any module that follows this standard works perfectly.

After successfully decoding the token, it will be passed to our callback as a payload. Here we are just trying to find users identified by the "topic" in the token. In fact, you may do additional checks, such as making sure the token is not revoked.

If the user is found, we provide it to Passport, and Passport then provides it to the rest of the request processing as req.user. If the user is not found, we do not provide any user to Passport and Passport will then consider the authentication failed.

This can now connect to the request handler so that the request requires authentication to succeed:

# Windows
> set GOOGLE_CLIENTID=myGoogleClientId
> set GOOGLE_CLIENTSECRET=myGoogleClientSecret
> set FACEBOOK_CLIENTID=myFacebookClientId
> set FACEBOOK_CLIENTSECRET=myFacebookClientSecret
> node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

The above line 3 is the magic to make Passport handle the request. This causes Passport to run the "jwt" policy we just configured on the request we passed in and allow it to continue or fail immediately.

We can see how it works by running the application - by executing node src/index.js - and trying to access this resource:

// src/index.js
const passport = require('passport');
.....
app.use(passport.initialize());
Copy after login
Copy after login
Copy after login

We did not provide any Authorization headers, it does not allow us to continue. However, if you provide a valid Authorization header, you will get a successful response:

// src/authentication/jwt.js
const passport = require('passport');
const passportJwt = require('passport-jwt');
const config = require('../config');
const users = require('../users');

const jwtOptions = {
  // 从 "Authorization" 标头获取 JWT。
  // 默认情况下,这会查找 "JWT " 前缀
  jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeader(),
  // 用于签署 JWT 的密钥
  secretOrKey: config.get('authentication.token.secret'),
  // JWT 中存储的发行者
  issuer: config.get('authentication.token.issuer'),
  // JWT 中存储的受众
  audience: config.get('authentication.token.audience')
};

passport.use(new passportJwt.Strategy(jwtOptions, (payload, done) => {
  const user = users.getUserById(parseInt(payload.sub));
  if (user) {
      return done(null, user, payload);
  }
  return done();
}));
Copy after login
Copy after login

To perform this test, I manually generated a JWT by visiting https://www.jsonwebtoken.io and filling out the form there. "Payload" is what I use:

// src/index.js
app.get('/api/secure',
  // 此请求必须使用 JWT 进行身份验证,否则我们将失败
  passport.authenticate(['jwt'], { session: false }),
  (req, res) => {
    res.send('Secure response from ' + JSON.stringify(req.user));
  }
);
Copy after login
Copy after login

"Signature Key" is "mySuperSecretKey", taken from configuration.

Support token generation

Now we can access resources only with valid tokens, we need a way to actually generate the token. This is done using the jsonwebtoken module, which builds a JWT with the correct details and signed with the same key as above.

# Linux / OS X
$ export GOOGLE_CLIENTID=myGoogleClientId
$ export GOOGLE_CLIENTSECRET=myGoogleClientSecret
$ export FACEBOOK_CLIENTID=myFacebookClientId
$ export FACEBOOK_CLIENTSECRET=myFacebookClientSecret
$ node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

Note that we use the exact same audience, issuer, and key configuration settings when generating JWTs. We also specify that the validity period of JWT is one hour. This can be any time period you think is reasonable for your app, and can even be extracted from the configuration so that it can be easily changed.

In this case, no JWT ID is specified, but this can be used to generate a completely unique ID for the token - for example using a UUID. This then gives you a way to revoke the token and store a collection of revoked IDs in the datastore and check if the JWT ID is not in the list when processing the JWT in the Passport policy.

Social Login Provider

Now that we have the ability to generate tokens, we need a way to get the user to actually log in. This is where social login providers come into play. We will add a feature that allows users to redirect to social login providers and generate a JWT token upon success and provide it to the browser's JavaScript engine for future requests. We already have almost all of this components, we just need to put them together.

The social login provider in Passport is divided into two parts. First, you need to actually configure Passport for your social login provider using the appropriate plugin. Secondly, the Express route that the user is directed to is required to initiate authentication, and the route that the user is redirected to after the authentication is successful.

We will open these URLs in a new subbrowser window, which we can close when we are done and be able to call the JavaScript method inside the window where it is opened. This means that the process is relatively transparent to the user – at most they will see a new window open, asking them to provide credentials, but best they can see nothing but the fact that they are now logged in.

The aspect of this browser needs to be composed of two parts. View of the pop-up window and JavaScript that handles this view in the main window. This can be easily integrated with any framework, but in this example we will use vanilla JavaScript for simplicity.

The main page JavaScript only requires something like this:

# Windows
> set GOOGLE_CLIENTID=myGoogleClientId
> set GOOGLE_CLIENTSECRET=myGoogleClientSecret
> set FACEBOOK_CLIENTID=myFacebookClientId
> set FACEBOOK_CLIENTSECRET=myFacebookClientSecret
> node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

This registers a global function object (named authenticateCallback) on the window, which will store the access token, and then opens our route to start authentication, we are accessing /api/authentication/{provider}/start.

This function can then be triggered in any way you wish to initiate authentication. This is usually a login link in the title area, but the details are entirely dependent on your app.

The second part is the view to be presented after successful authentication. In this case we use Mustache for simplicity, but this will use any viewing technique that is most suitable for you.

# Linux / OS X
$ export GOOGLE_CLIENTID=myGoogleClientId
$ export GOOGLE_CLIENTSECRET=myGoogleClientSecret
$ export FACEBOOK_CLIENTID=myFacebookClientId
$ export FACEBOOK_CLIENTSECRET=myFacebookClientSecret
$ node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

Here we have only a simple JavaScript code that calls the authenticateCallback method above on the open program (i.e., the main application window), and then we close ourselves.

At this point, the JWT token will be available in the main application window for any purpose you want.

Implement Google Authentication

Using the passport-google-oauth module will authenticate against Google. This requires three pieces of information:

  • Client ID
  • Client Key
  • Redirect URL

Client ID and key are obtained by registering your app in the Google Developer Console. A redirect URL is the URL that the user will be sent back to your app after logging in with their Google credentials. This will depend on how and where the app is deployed, but now we will hardcode it.

Our Google Authentication Passport configuration will then look like this:

# Windows
> set GOOGLE_CLIENTID=myGoogleClientId
> set GOOGLE_CLIENTSECRET=myGoogleClientSecret
> set FACEBOOK_CLIENTID=myFacebookClientId
> set FACEBOOK_CLIENTSECRET=myFacebookClientSecret
> node src/index.js
Copy after login
Copy after login
Copy after login
Copy after login

When users redirect back to us after successful authentication, we will get their ID and some profile information in the Google system. We first try to see if this user has been logged in before. If so, then we get their user records and we're done. If not, we will register a new account for them and we will use this new account. This provides us with a transparent mechanism where user registration is done on the first login. We can do this in different ways if we need to, but it is not necessary now.

The next is to set up the routing handler to manage this login. These will look like this:

// src/index.js
const passport = require('passport');
.....
app.use(passport.initialize());
Copy after login
Copy after login
Copy after login

Please note the routes of /api/authentication/google/start and /api/authentication/gogle/redirect. As mentioned above, the /start variant is the URL we open, and the /redirect variant is the URL that Google redirects the user on success. This will then render the authenticated view we show above, providing the generated JWT for its use.

Implement Facebook authentication

Now that we have the first social login provider, let's expand and add a second one. This time it will be Facebook, using the passport-facebook module.

This module works almost the same way as Google modules, requiring the same configuration and the same settings. The only real difference is that it is a different module and the URL structure that accesses it is different.

To configure Facebook authentication, you also need the client ID, client key, and redirect URL. Client ID and client key (called App ID and App Key on Facebook) can be obtained by creating Facebook apps in the Facebook Developer Console. You need to make sure that the Facebook Login product is added to your app to get it to work.

Our Facebook Authentication Passport configuration will be:

// src/authentication/jwt.js
const passport = require('passport');
const passportJwt = require('passport-jwt');
const config = require('../config');
const users = require('../users');

const jwtOptions = {
  // 从 "Authorization" 标头获取 JWT。
  // 默认情况下,这会查找 "JWT " 前缀
  jwtFromRequest: passportJwt.ExtractJwt.fromAuthHeader(),
  // 用于签署 JWT 的密钥
  secretOrKey: config.get('authentication.token.secret'),
  // JWT 中存储的发行者
  issuer: config.get('authentication.token.issuer'),
  // JWT 中存储的受众
  audience: config.get('authentication.token.audience')
};

passport.use(new passportJwt.Strategy(jwtOptions, (payload, done) => {
  const user = users.getUserById(parseInt(payload.sub));
  if (user) {
      return done(null, user, payload);
  }
  return done();
}));
Copy after login
Copy after login

This is almost the same as Google's configuration, except that "facebook" is used instead of "google". The URL routing is also similar:

// src/index.js
app.get('/api/secure',
  // 此请求必须使用 JWT 进行身份验证,否则我们将失败
  passport.authenticate(['jwt'], { session: false }),
  (req, res) => {
    res.send('Secure response from ' + JSON.stringify(req.user));
  }
);
Copy after login
Copy after login

Here we don't need to specify the range we want to use, because the default set is good enough. Otherwise, the configuration between Google and Facebook is almost the same.

Summary

Use social login providers to add user login and registration to your app quickly and easily. In fact, this uses browser redirection to send users to social login providers and then sends them back to your app, which makes it possible to integrate them into single page apps, even if it's integrated into more traditional apps Relatively easy.

This article shows a way to integrate these social login providers into a single page application that promises to be both easy to use and easy to scale to future providers you may wish to use. Passport has a lot of modules that can work with different providers, and it's just a matter of finding the right module and configuring it like we did above with Google and Facebook.

This article was peer-reviewed by James Kolce. Thanks to all SitePoint peer reviewers for getting SitePoint content to its best

FAQs about social login integration (FAQs)

What are the benefits of integrating social login into my web application?

Integrating social login into your web application can bring several benefits. First, it simplifies the registration process for users because they can register with an existing social media account without remembering another username and password. Second, it can improve conversion rates, as a simplified registration process can encourage more users to sign up. Finally, it gives you access to user data in their social media profiles that can be used to personalize their experience on your website.

How to ensure the security of user data when using social login?

It is crucial to ensure the security of user data when integrating social logins. You can do this by authenticating using secure protocols such as OAuth 2.0, which ensures that the user password is not shared with your app. Additionally, you should only request the minimum amount of user data required by the application and ensure that this data is stored securely.

Can I integrate multiple social logins in my web application?

Yes, you can integrate multiple social logins in your web application. This can provide users with more choices and increase the likelihood of their registration. However, it is important to ensure that the user experience remains seamless regardless of which social login the user chooses to use.

How to deal with users with multiple social media accounts?

Processing users with multiple social media accounts can be challenging. One solution is to allow users to link multiple social media accounts to a single account on your app. This way, they have the option to log in with any linked account.

What happens if a user disables their social media account?

If users disable their social media account, they will no longer be able to use the account to log in to your app. To handle this, you can give users the option to add an email address or phone number to their account, and if they deactivate their social media account, you can log in with this information.

How to customize the appearance of social login buttons?

CSS can be used to customize the appearance of the social login button. However, be sure to follow the brand guidelines provided by social media platforms. For example, Facebook's "f" logo should always be used in its original form and should not be modified in any way.

Can I use social login for mobile apps?

Yes, social login can be used for web and mobile applications. The process of integrating social login in a mobile app is similar to that of a web app, but you may need to use a specific SDK provided by the social media platform.

How to test social login function?

You can test the social login feature by creating test accounts on social media platforms and using these accounts to log into your app. This can help you identify any issues or errors before the app starts.

What should I do if the user forgets to register with which social media account to use?

If users forget which social media account to sign up with, you can provide a recovery option that allows them to enter their email address or phone number to receive a list of social media accounts linked to their account.

Can I integrate social login without coding?

While some tools and plugins can be used to integrate social login without coding, it can be beneficial to know some coding knowledge. This can give you more flexibility and control over the integration process, and can also help you solve any problems that may arise.

The above is the detailed content of Social Login for Your SPA: Authenticate Your Users via Google and Facebook. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template