From f773ce00c30916ee09351bfb36a71b89e1966065 Mon Sep 17 00:00:00 2001 From: Wang Sijie Date: Wed, 20 Jul 2022 12:02:08 +0800 Subject: [PATCH] feat(next): sign out (#358) --- packages/next-sample/pages/api/sign-out.ts | 3 +++ packages/next-sample/tsconfig.json | 3 ++- packages/next/src/index.test.ts | 22 ++++++++++++++++++++++ packages/next/src/index.ts | 15 ++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 packages/next-sample/pages/api/sign-out.ts diff --git a/packages/next-sample/pages/api/sign-out.ts b/packages/next-sample/pages/api/sign-out.ts new file mode 100644 index 00000000..f9bd1291 --- /dev/null +++ b/packages/next-sample/pages/api/sign-out.ts @@ -0,0 +1,3 @@ +import { logtoClient } from '../../libraries/logto'; + +export default logtoClient.handleSignOut(); diff --git a/packages/next-sample/tsconfig.json b/packages/next-sample/tsconfig.json index 17c03999..9441f1b5 100644 --- a/packages/next-sample/tsconfig.json +++ b/packages/next-sample/tsconfig.json @@ -2,7 +2,8 @@ "extends": "@silverhand/ts-config-react/tsconfig.base", "compilerOptions": { "jsx": "preserve", - "incremental": true + "incremental": true, + "allowJs": true // added by next cli }, "include": [ "next-env.d.ts", diff --git a/packages/next/src/index.test.ts b/packages/next/src/index.test.ts index c7affb95..3f8abe8d 100644 --- a/packages/next/src/index.test.ts +++ b/packages/next/src/index.test.ts @@ -23,6 +23,7 @@ const handleSignInCallback = jest.fn(); const getIdTokenClaims = jest.fn(() => ({ sub: 'user_id', })); +const signOut = jest.fn(); jest.mock('./storage', () => jest.fn(() => ({ @@ -48,6 +49,10 @@ jest.mock('@logto/node', () => handleSignInCallback, isAuthenticated: true, getIdTokenClaims, + signOut: () => { + navigate(configs.baseUrl); + signOut(); + }, })) ); @@ -109,4 +114,21 @@ describe('Next', () => { expect(getIdTokenClaims).toHaveBeenCalled(); }); }); + + describe('handleSignOut', () => { + it('should redirect to Logto sign out url', async () => { + const client = new LogtoClient(configs); + await testApiHandler({ + handler: client.handleSignOut(), + url: '/api/sign-out', + test: async ({ fetch }) => { + const response = await fetch({ method: 'GET', redirect: 'manual' }); + const headers = response.headers as Map; + expect(headers.get('location')).toEqual(`${configs.baseUrl}/`); + }, + }); + expect(save).toHaveBeenCalled(); + expect(signOut).toHaveBeenCalled(); + }); + }); }); diff --git a/packages/next/src/index.ts b/packages/next/src/index.ts index bd0593e1..5e0a35a2 100644 --- a/packages/next/src/index.ts +++ b/packages/next/src/index.ts @@ -12,7 +12,7 @@ export default class LogtoClient { private storage?: NextStorage; constructor(private readonly config: LogtoNextConfig) {} - handleSignIn = (redirectUri = `${this.config.baseUrl}/api/sign-in`): NextApiHandler => + handleSignIn = (redirectUri = `${this.config.baseUrl}/api/sign-in-callback`): NextApiHandler => this.withIronSession(async (request, response) => { const nodeClient = this.createNodeClient(request); await nodeClient.signIn(redirectUri); @@ -34,6 +34,19 @@ export default class LogtoClient { } }); + handleSignOut = (redirectUri = this.config.baseUrl): NextApiHandler => + this.withIronSession(async (request, response) => { + const nodeClient = this.createNodeClient(request); + await nodeClient.signOut(redirectUri); + + request.session.destroy(); + await this.storage?.save(); + + if (this.navigateUrl) { + response.redirect(this.navigateUrl); + } + }); + handleUser = () => this.withLogtoApiRoute((request, response) => { response.json(request.user);