Spotify OAuth2 Authentication in a NestJS Application
Tags: nestjs, spotify, typescript, node
Published: 2022-03-20 15:46:25

## Integrate an OAuth2 authorization code flow strategy for the Spotify Web API in a NodeJS with TypeScript and NestJS back end application

When building an API, one of the most important parts of the application is the security and authentication of its users. Most frameworks provide some guidelines on how to implement different authentication strategies. NestJS, for instance, presents, in its [official documentation](https://docs.nestjs.com/security/authentication), the JWT strategy.

However, one widely spread authentication strategy is the OAuth2 approach, usually used with 3rd party services such as Facebook, Google and Spotify accounts which provides a way to use an existing account in these services to authenticate the user and even interact with these services on behalf of the authenticated user.

As there is no official documentation for integrating this type of authentication with NestJS and development articles usually focus on Google and Facebook integration, this article presents an alternative to integrate the [Spotify Authorization Code Flow](https://developer.spotify.com/documentation/general/guides/authorization/code-flow/) with [NestJS](https://nestjs.com/) using the [Passport](https://github.com/jaredhanson/passport) authentication middleware along with the [passport-spotify](https://github.com/JMPerez/passport-spotify) strategy.

## Requirements

This article focuses on the process of using the OAuth2 strategy for Spotify integrated with a NestJS application, therefore, the following requirements are considered to be fulfilled before the process described in this article:

- A NestJS application bootsraped with its basic structure. For this part, it is sufficient to follow the quick setup guide in the [NestJS documentation](https://docs.nestjs.com/first-steps#setup);
- A Spotify account with access to the Spotify Developer Dashboard and an app registered with its CLIENT ID and CLIENT SECRET credentials. Following the step-by-step [official documentation](https://developer.spotify.com/documentation/web-api/quick-start/) on how to use the Spotify API is sufficient for this article.

If you are not familiar with the OAuth2 Authorization Code Flow, please check the guide provided by the [Spotify Web API documentation](https://developer.spotify.com/documentation/general/guides/authorization/code-flow/).

## The auth folder

With a NestJS application ready, an `auth` resource must be created using the following command - considering that the [Nest CLI](https://docs.nestjs.com/cli/overview) is installed in the machine:

```
nest g mo auth
nest g s auth --no-spec
nest g co auth --no-spec
```

Those commands create an auth folder with basic module, service, and controller files without any .spec files. With all in place, the folder structure should look like this:


![Beginning folder tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tl4xo9yk199imyxckcg.png)

Now, the following dependencies must be installed:

```
npm install @nestjs/passport @nestjs/jwt passport passport-jwt passport-spotify
npm install -D @types/passport-jwt @types/passport-spotify
```

From now on, there are 3 functionalities that must be available in the application in terms of authentication:

1. Login of users using the Spotify OAuth2 authorization code flow;
2. Retrieving the user's info from Spotify and generate a JWT;
3. Using the JWT strategy so that there is no need for connecting with the Spotify OAuth2 server every time there's a need for user authentication in during a session.

## The routes

For the first and second functionalities described earlier, there needs to be a controller with the routes '/login' and '/redirect':

{% gist https://gist.github.com/marcus-castanho/d57e9582913f5949ee170d6804034365 %}

The above code comprehends the following:

- Both routes, '/login' and '/redirect' are guarded with the `SpotifyOauthGuard` [custom guard](https://docs.nestjs.com/guards) which implements the `passport-spotify` strategy that will be described later;
- The `login` method/route is the endpoint that users will access to initiate the authentication;
- The `spotifyAuthRedirect` method ('/redirect' route) is the URL to which the Spotify OAuth2 service will be redirected once the user successfully logs in;
- The `spotifyAuthRedirect` method: retrieves the user's information coming from Spotify located the `req.user` property - if there is no info, meaning the authentication wasn't performed or failed, the method redirects the request to the login route again - sets the `user` req property to undefined (as it is will be defined as the JWT payload further), generates a JWT with it, and returns the user's info and Spotify tokens that can be used by the application to access routes in the Spotify Web API using the user's info depending on the [scopes defined](https://developer.spotify.com/documentation/general/guides/authorization/scopes/).

## The Spotify OAuth2 strategy

When using a built-in passport strategy, a custom guard mustbe created and also its corresponding strategy. The `SpotifyOauthGuard` is simply a class that extends the `AuthGuard` class, so, after creating a /guards folder, inside it, the `SpotifyOauthGuard` should look like this:

{% gist https://gist.github.com/marcus-castanho/6d5d5ec088f89f47ec1174232b79eb71 %}

Also, the named `spotify` strategy must be created inside a /strategies folder:

{% gist https://gist.github.com/marcus-castanho/ced42d59babcbf7b6b02d98c2d232326 %}

The above code is responsible for connecting with the Spotify OAuth2 service and managing the redirection to the application. The process is:

- The `SpotifyOauthStrategy` class extends the `PassportStrategy` using the strategy provided by the [passport-spotify](https://github.com/JMPerez/passport-spotify) lib and name it 'spotify' so the `SpotifyOauthGuard` can identify it;
- The `constructor` method calls the [passport-spotify](https://github.com/JMPerez/passport-spotify) `Strategy` constructor method using the `super` method, passing the Spotify app credentials `CLIENT_ID` and `CLIENT_SECRET`(saved in .env vars as they must not be exposed publicly), better described [here](https://developer.spotify.com/documentation/web-api/quick-start/), a callback URL which is the same route defined in the auth.controller.ts, '/redirect', and the scopes that the app needs for interacting with the user's information;
- The `super` method also has a callback function, that will be called as soon as the user's login process succeeds and before it is redirected to the application. This function adds to the request that will be made to the '/redirect' route the following properties: user (containing the user's profile info) and authInfo (containing the `refreshToken`, `accessToken` and `expires_in ` info).

## The redirection and JWT generation

Once the strategy is implemented, the user will be redirected to the /redirect URL, and, in `auth.controller.ts` (presented earlier), the `spotifyAuthRedirect` method will intercept the `req` object and extract the `user` and `authInfo` properties and pass the user to the authService. With the user's info, the `login` method in the `AuthService` class is responsible for generating the JWT. The auth.service.ts should look like:

{% gist https://gist.github.com/marcus-castanho/134d3662172bf21183a5e11fd26892a7 %}

Finally, in `auth.service.ts`, the '/redirect' route returns an object containing the authInfo and `user` properties as well as a header Authentication set to 'Bearer ' concatenated with the JWT.

## The JWT strategy

This part of the authentication is basically as described in the [official NestJS documentation](https://docs.nestjs.com/security/authentication#jwt-functionality). For this part, there needs to be defined in your `.env` vars a `JWT_SECRET`, which is a string that is used to generate and encrypt/decrypt the JWT's that the application generates and must not be exposed publicly. Similar to the Spotify strategy, it's necessary to create a `JwtAuthGuard` class that extends the built-in passport AuthGuard along with a corresponding, named 'jwt'. Inside the /guards folder, create the jwt-auth.guard.ts file as the following:

{% gist https://gist.github.com/marcus-castanho/44cdee2149e3350b9b33e2da6dd7fcda %}

And the corresponding strategy, inside the /strategies folder, should look like:

{% gist https://gist.github.com/marcus-castanho/a3d12f7bc60791faf79f8cc38707117a %}

The above code is executed when a route is decorated with the `JwtAuthGuard`. The `super` method extracts the JWT provided by the request to a guarded route, decrypts it with the `JWT_SECRET` provided and inserts a `user` property into the `req` object containing the info that was previously inserted into the payload of the JWT.

It's important to highlight that the inserted `user` property is not the same that the `spotify-strategy` inserts to the `req` object, and this is the reason why in the `spotifyAuthRedirect` method, the `req.user` property is set to undefined before the sign in with the jwt strategy.

Now any authenticate route can be decorated with the `JwtAuthGuard` as the following:

{% gist https://gist.github.com/marcus-castanho/6494e3d4a597dc061900b8fafc8c4cd8 %}

## The AuthModule and AppModule Configs

With everything in place, it's time to configure the instantiation of all the modules. The `AuthModule` class should look like this:

{% gist https://gist.github.com/marcus-castanho/51a85194aeca24f272bbde7de5952df7 %}

The `auth.module.ts` file defines all the providers of the auth resource and registers the `JWT_SECRET` during the instantiation of the `JwtModule` as well as the expiration time for it, here defined as 3600s (1 hour).

Also, the AppModule should look like:

{% gist https://gist.github.com/marcus-castanho/8829bf237a1c455bae5c434d3503a822 %}

The `app.module.ts` instantiates all the modules of the application including the `ConfigModule`, which is necessary for using all the env vars described in the process.

The final state of the folders and files of the application should look like this:


![Final folder tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8pzbhjhojoy5gjaqlk5m.png)

## Conclusion

The OAuth2 is an interesting way of integrating an application with external apps such as widespread social media services, taking advantage of an easy way to log users as well as providing functionalities to the users related to these apps.

Even though NestJS does not provide an official way of making this kind of integration, there are many open source projects that aims to make it easier this authentication method such as the ones described and used in this article.

## Credits
- Cover image by [Alexander Shatov on Unsplash](https://unsplash.com/@alexbemore?utm_source=medium&utm_medium=referral)