@authing/nextjs
v0.1.2
Published
Authing OIDC Authentication for Next.js
Downloads
18
Readme
@authing/nextjs
Simple Authing OIDC Authentication for Next.js
Functions
isAuthenticated
type IsAuthenticatedOptions = {
throwOnError?: boolean;
};
function isAuthenticated<User = any>(
req: NextApiRequest,
options?: IsAuthenticatedOptions
): User;
Params:
throwOnError
: throw error when not authenticated
Return Type: User
API Helpers
createCallbackApi
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<void>;
Params:
appDomain
: App Domain, like:https://your-app.authing.cn
clientId
: App IDclientSecret
: App SecretfailureRedirect
: redirect when failed, such as/error
successRedirect
: redirect when success, such as/dashboard
createLoginApi
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 IDredirectUri
: Callback Redirect URI (same with Authing console configuration)sope
: OAuth Scope, like:openid profile email
- Ref: Documentation
createLogoutApi
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
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.
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
:
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
:
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
:
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
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
:
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<User>) {
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
:
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<User>('/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
:
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 (
<>
<nav>
<Link href='/ssr'>SSR</Link> | <Link href='/api/logout'>Logout</Link>
</nav>
{user && (
<>
<pre>{JSON.stringify(user, null, 2)}</pre>
</>
)}
</>
);
}
Others
LICENSE
MIT