Anto Subash.

abp
nextjs
react
identity-server
openid
ABP Framework - Getting started -Part : 2

SPA Authentication using Next.js, ABP and IdentityServer4. Part 2

Table of contents

Intro

In this post we will see how to create a Identity server Client and configure it to implement authenticate for the Next.js Application.

1. Adding a new client to the IdentityServer

first step is to create a new client for the nextjs application. list of client is available in the appsettings.json file at DbMigrator project.

1.1 Add the new json entry

"Todos_Spa_1": {
    "ClientId": "Todos_Spa_1",
    "ClientSecret": "1q2w3e*",
    "RootUrl": "http://localhost:3000"
},

1.2 Update the CreateClientsAsync method

In the Domain project there is a IdentityServerDataSeedContributor class which has the CreateClientsAsync method. This method creates the Identity server clients during the migrations. so we will update this method to include the new json entry.

// React Client
var reactClient = configurationSection["Todos_Spa_1:ClientId"];
if (!reactClient.IsNullOrWhiteSpace())
{
    var webClientRootUrl = configurationSection["Todos_Spa_1:RootUrl"]?.TrimEnd('/');

    await CreateClientAsync(
        name: reactClient,
        scopes: commonScopes,
        grantTypes: new[] { "client_credentials", "authorization_code" },
        secret: (configurationSection["Todos_Spa_1:ClientSecret"] ?? "1q2w3e*").Sha256(),
        requireClientSecret: false,
        redirectUri: $"{webClientRootUrl}/authentication/login-callback/identity-server4",
        postLogoutRedirectUri: $"{webClientRootUrl}",
        corsOrigins: new[] { webClientRootUrl.RemovePostFix("/") }
    );
}

1.3 Run the migration

Now run the migration to add the client to the DB.

2. Create Next.js App

yarn create next-app

3. Add next-auth package

yarn add next-auth

4. Add .env file

NEXTAUTH_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=https://localhost:44391
IdentityServer4_Domain=localhost:44354
IdentityServer4_CLIENT_ID=Todos_Spa_1
IdentityServer4_CLIENT_SECRET="1q2w3e*"
NODE_TLS_REJECT_UNAUTHORIZED=0

NEXT_PUBLIC_API_URL is the ABP application url.

NEXTAUTH_URL is the nextjs app url.

NODE_TLS_REJECT_UNAUTHORIZED is set to 0 to work with ssl in localhost.

5. Setup next-auth

create a /pages/api/auth/[...nextauth].js and add the following

import NextAuth from "next-auth";
import Providers from "next-auth/providers";

export default NextAuth({
  // Configure one or more authentication providers
  providers: [
    Providers.IdentityServer4({
      id: "identity-server4",
      name: "IdentityServer4",
      scope: "openid profile email Todos offline_access", // Allowed Scopes
      domain: process.env.IdentityServer4_Domain,
      clientId: process.env.IdentityServer4_CLIENT_ID,
      clientSecret: process.env.IdentityServer4_CLIENT_SECRET,
    }),
  ],
  callbacks: {
    /**
     * @param  {object} session      Session object
     * @param  {object} token        User object    (if using database sessions)
     *                               JSON Web Token (if not using database sessions)
     * @return {object}              Session that will be returned to the client
     */
    async session(session, token) {
      // Add property to session, like an access_token from a provider.
      session.accessToken = token.accessToken;
      return session;
    },

    async jwt(token, user, account, profile, isNewUser) {
      // Add access_token to the token right after signin
      if (account?.accessToken) {
        token.accessToken = account.accessToken;
      }
      return token;
    },
  },
});

6. Create login Component

import React from "react";
import { signIn, signOut, useSession } from "next-auth/client";
function Login() {
  const [session, loading] = useSession();

  return (
    <>
      {!session && (
        <>
          Not signed in <br />
          <button onClick={() => signIn("identity-server4")}>Sign in</button>
        </>
      )}
      {session && (
        <>
          Signed in as {session.user.email} <br />
          <button onClick={() => signOut()}>Sign out</button>
        </>
      )}
    </>
  );
}

export default Login;

7. Render the login component

Now you can render the login component in any page to trigger the auth.

<Login></Login>

Buy Me a Coffee at ko-fi.com