https://github.com/willin/authing-nextjs
Simple Authing Authentication for Next.js
https://github.com/willin/authing-nextjs
Last synced: about 2 months ago
JSON representation
Simple Authing Authentication for Next.js
- Host: GitHub
- URL: https://github.com/willin/authing-nextjs
- Owner: willin
- License: mit
- Created: 2022-01-27T12:52:17.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2022-06-17T09:33:45.000Z (almost 4 years ago)
- Last Synced: 2024-10-29T22:37:29.898Z (over 1 year ago)
- Language: TypeScript
- Homepage:
- Size: 99.6 KB
- Stars: 1
- Watchers: 7
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
README
# @authing/nextjs
[](https://npmjs.org/package/@authing/nextjs) [](https://npmjs.org/package/@authing/nextjs)
[中文说明](./readme.zh.md)
Simple Authing OIDC Authentication for Next.js
- [@authing/nextjs](#authingnextjs)
- [Functions](#functions)
- [isAuthenticated](#isauthenticated)
- [API Helpers](#api-helpers)
- [createCallbackApi](#createcallbackapi)
- [createLoginApi](#createloginapi)
- [createLogoutApi](#createlogoutapi)
- [Quick Start](#quick-start)
- [Add dependencies](#add-dependencies)
- [Config](#config)
- [Create SessionStorage](#create-sessionstorage)
- [Create Login, Logout, Callback APIs](#create-login-logout-callback-apis)
- [Use in SSR](#use-in-ssr)
- [Use in SSG](#use-in-ssg)
- [Others](#others)
- [LICENSE](#license)
## Functions
### isAuthenticated
```ts
type IsAuthenticatedOptions = {
throwOnError?: boolean;
};
function isAuthenticated(
req: NextApiRequest,
options?: IsAuthenticatedOptions
): User;
```
Params:
- `throwOnError`: throw error when not authenticated
Return Type: `User`
## API Helpers
### createCallbackApi
```ts
type CallbackApiArgs = {
appDomain: string;
clientId: string;
clientSecret: string;
failureRedirect?: string;
successRedirect?: string;
};
function createCallbackApi({
appDomain,
clientId,
clientSecret,
failureRedirect,
successRedirect
}: CallbackApiArgs): (
req: NextApiRequest,
res: NextApiResponse
) => Promise;
```
Params:
- `appDomain`: App Domain, like: `https://your-app.authing.cn`
- `clientId`: App ID
- `clientSecret`: App Secret
- `failureRedirect`: redirect when failed, such as `/error`
- `successRedirect`: redirect when success, such as `/dashboard`
### createLoginApi
```ts
type LoginApiArgs = {
appDomain: string;
ssoDomain?: string;
clientId: string;
redirectUri: string;
scope: string;
};
function createLoginApi({
appDomain,
ssoDomain,
clientId,
redirectUri,
scope
}: LoginApiArgs): (req: NextApiRequest, res: NextApiResponse) => void;
```
Params:
- `appDomain`: App Domain, like: `https://your-app.authing.cn`
- `ssoDomain`: SSO Domain, like: `https://your-sso.authing.cn`, when set, `appDomain` will be ignored.
- `clientId`: App ID
- `redirectUri`: Callback Redirect URI (same with Authing console configuration)
- `sope`: OAuth Scope, like: `openid profile email`
- Ref: [Documentation](https://docs.authing.cn/v2/concepts/oidc-common-questions.html#scope-%E5%8F%82%E6%95%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF)
### createLogoutApi
```ts
type LogoutApiArgs = {
redirectUri: string;
appDomain: string;
};
function createLogoutApi({
appDomain,
redirectUri
}: LogoutApiArgs): (req: NextApiRequest, res: NextApiResponse) => void;
```
Params:
- `appDomain`: App Domain, like: `https://your-app.authing.cn`
- `redirectUri`: Logout Callback Redirect URI (same in authing console)
## Quick Start
Example project at `examples/basic`.
### Add dependencies
```bash
npm install --save @authing/nextjs iron-session swr
# or
yarn add @authing/nextjs iron-session swr
```
### Config
Placed in `config/index.ts` or somewhere else.
```ts
export const clientId =
process.env.AUTHING_CLIENT_ID || '61e4da899687d7055442f6b7';
export const clientSecret = process.env.AUTHING_CLIENT_SECRET || '';
export const appDomain =
process.env.AUTHING_CLIENT_DOMAIN || 'https://remix.authing.cn';
export const redirectUri =
process.env.AUTHING_REDIRECT_URI || 'http://localhost:3000/authing/callback';
export const logoutRedirectUri =
process.env.AUTHING_LOGOUT_REDIRECT_URI || 'http://localhost:3000/';
```
### Create SessionStorage
Create `lib/session.ts`. In this example we use `iron-session` to store session.
### Create Login, Logout, Callback APIs
Notice that login url is `/api/login`, and logout is `/api/logout`
Create `pages/api/login.ts`:
```ts
import { createLoginApi } from '@authing/nextjs';
import { appDomain, clientId, redirectUri } from '../../config';
export default createLoginApi({
appDomain,
clientId,
redirectUri,
scope: 'openid roles username phone profile'
});
```
Create `pages/api/logout.ts`:
```ts
import { withIronSessionApiRoute } from 'iron-session/next';
import { createLogoutApi } from '@authing/nextjs';
import { appDomain, logoutRedirectUri } from '../../config';
import { sessionOptions } from '../../lib/session';
export default withIronSessionApiRoute(
createLogoutApi({
appDomain,
redirectUri: logoutRedirectUri
}),
sessionOptions
);
```
Create `pages/api/callback.ts`:
```ts
import { createCallbackApi } from '@authing/nextjs';
import { appDomain, clientId, clientSecret } from '../../config';
import { withIronSessionApiRoute } from 'iron-session/next';
import { sessionOptions } from '../../lib/session';
export default withIronSessionApiRoute(
createCallbackApi({
appDomain,
clientId,
clientSecret,
// 登录失败返回登录页
failureRedirect: '/error',
successRedirect: '/ssr'
}),
sessionOptions
);
```
### Use in SSR
```ts
import { withIronSessionSsr } from 'iron-session/next';
import { sessionOptions } from '../lib/session';
export const getServerSideProps = withIronSessionSsr(async function ({
req,
res
}) {
const user = req.session.user;
if (user === undefined) {
res.setHeader('location', '/api/login');
res.statusCode = 302;
res.end();
return {
props: {
user: { isLoggedIn: false }
}
};
}
return {
props: { user: req.session.user }
};
},
sessionOptions);
```
### Use in SSG
Create API: `pages/api/me.ts`:
```ts
import { withIronSessionApiRoute } from 'iron-session/next';
import { sessionOptions } from '../../lib/session';
import { NextApiRequest, NextApiResponse } from 'next';
export type User = {
isLoggedIn: boolean;
username: string;
};
export default withIronSessionApiRoute(userRoute, sessionOptions);
async function userRoute(req: NextApiRequest, res: NextApiResponse) {
if (req.session.user) {
// in a real world application you might read the user id from the session and then do a database request
// to get more information on the user if needed
res.json({
...req.session.user,
isLoggedIn: true
});
} else {
res.json({
isLoggedIn: false,
username: ''
});
}
}
```
Create React hook `hooks/use-user.ts`:
```ts
import { useEffect } from 'react';
import Router from 'next/router';
import useSWR from 'swr';
import { User } from '../pages/api/me';
export default function useUser({
redirectTo = '',
redirectIfFound = false
} = {}) {
const { data: user, error } = useSWR('/api/me');
useEffect(() => {
// if no redirect needed, just return (example: already on /dashboard)
// if user data not yet there (fetch in progress, logged in or not) then don't do anything yet
if (!redirectTo || !user) return;
if (
// If redirectTo is set, redirect if the user was not found.
(redirectTo && !redirectIfFound && !user?.isLoggedIn) ||
// If redirectIfFound is also set, redirect if the user was found
(redirectIfFound && user?.isLoggedIn)
) {
Router.push(redirectTo);
}
}, [user, redirectIfFound, redirectTo]);
return { user, error };
}
```
Create page `pages/sg.tsx`:
```ts
import useUser from '../hooks/use-user';
import Link from 'next/link';
// Make sure to check https://nextjs.org/docs/basic-features/layouts for more info on how to use layouts
export default function SgProfile() {
const { user } = useUser({
redirectTo: '/api/login'
});
return (
<>
SSR | Logout
{user && (
<>
{JSON.stringify(user, null, 2)}
>
)}
>
);
}
```
## Others
- [@authing/remix](https://github.com/Authing/authing-remix)
## LICENSE
MIT