{"id":15509739,"url":"https://github.com/willin/authing-nextjs","last_synced_at":"2026-04-16T06:02:57.200Z","repository":{"id":49377645,"uuid":"452681506","full_name":"willin/authing-nextjs","owner":"willin","description":"Simple Authing Authentication for Next.js","archived":false,"fork":false,"pushed_at":"2022-06-17T09:33:45.000Z","size":102,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-10-29T22:37:29.898Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/willin.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-01-27T12:52:17.000Z","updated_at":"2022-07-25T07:54:32.000Z","dependencies_parsed_at":"2022-08-25T08:02:25.282Z","dependency_job_id":null,"html_url":"https://github.com/willin/authing-nextjs","commit_stats":null,"previous_names":["authing/authing-nextjs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willin%2Fauthing-nextjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willin%2Fauthing-nextjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willin%2Fauthing-nextjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/willin%2Fauthing-nextjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/willin","download_url":"https://codeload.github.com/willin/authing-nextjs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243021782,"owners_count":20223068,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T09:43:33.000Z","updated_at":"2025-12-24T07:37:05.826Z","avatar_url":"https://github.com/willin.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @authing/nextjs\n\n[![npm](https://img.shields.io/npm/v/@authing/nextjs.svg)](https://npmjs.org/package/@authing/nextjs) [![npm](https://img.shields.io/npm/dt/@authing/nextjs.svg)](https://npmjs.org/package/@authing/nextjs)\n\n[中文说明](./readme.zh.md)\n\nSimple Authing OIDC Authentication for Next.js\n\n- [@authing/nextjs](#authingnextjs)\n  - [Functions](#functions)\n    - [isAuthenticated](#isauthenticated)\n  - [API Helpers](#api-helpers)\n    - [createCallbackApi](#createcallbackapi)\n    - [createLoginApi](#createloginapi)\n    - [createLogoutApi](#createlogoutapi)\n  - [Quick Start](#quick-start)\n    - [Add dependencies](#add-dependencies)\n    - [Config](#config)\n    - [Create SessionStorage](#create-sessionstorage)\n    - [Create Login, Logout, Callback APIs](#create-login-logout-callback-apis)\n    - [Use in SSR](#use-in-ssr)\n    - [Use in SSG](#use-in-ssg)\n  - [Others](#others)\n  - [LICENSE](#license)\n\n## Functions\n\n### isAuthenticated\n\n```ts\ntype IsAuthenticatedOptions = {\n  throwOnError?: boolean;\n};\n\nfunction isAuthenticated\u003cUser = any\u003e(\n  req: NextApiRequest,\n  options?: IsAuthenticatedOptions\n): User;\n```\n\nParams:\n\n- `throwOnError`: throw error when not authenticated\n\nReturn Type: `User`\n\n## API Helpers\n\n### createCallbackApi\n\n```ts\ntype CallbackApiArgs = {\n  appDomain: string;\n  clientId: string;\n  clientSecret: string;\n  failureRedirect?: string;\n  successRedirect?: string;\n};\n\nfunction createCallbackApi({\n  appDomain,\n  clientId,\n  clientSecret,\n  failureRedirect,\n  successRedirect\n}: CallbackApiArgs): (\n  req: NextApiRequest,\n  res: NextApiResponse\n) =\u003e Promise\u003cvoid\u003e;\n```\n\nParams:\n\n- `appDomain`: App Domain, like: `https://your-app.authing.cn`\n- `clientId`: App ID\n- `clientSecret`: App Secret\n- `failureRedirect`: redirect when failed, such as `/error`\n- `successRedirect`: redirect when success, such as `/dashboard`\n\n### createLoginApi\n\n```ts\ntype LoginApiArgs = {\n  appDomain: string;\n  ssoDomain?: string;\n  clientId: string;\n  redirectUri: string;\n  scope: string;\n};\n\nfunction createLoginApi({\n  appDomain,\n  ssoDomain,\n  clientId,\n  redirectUri,\n  scope\n}: LoginApiArgs): (req: NextApiRequest, res: NextApiResponse) =\u003e void;\n```\n\nParams:\n\n- `appDomain`: App Domain, like: `https://your-app.authing.cn`\n- `ssoDomain`: SSO Domain, like: `https://your-sso.authing.cn`, when set, `appDomain` will be ignored.\n- `clientId`: App ID\n- `redirectUri`: Callback Redirect URI (same with Authing console configuration)\n- `sope`: OAuth Scope, like: `openid profile email`\n  - 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)\n\n### createLogoutApi\n\n```ts\ntype LogoutApiArgs = {\n  redirectUri: string;\n  appDomain: string;\n};\n\nfunction createLogoutApi({\n  appDomain,\n  redirectUri\n}: LogoutApiArgs): (req: NextApiRequest, res: NextApiResponse) =\u003e void;\n```\n\nParams:\n\n- `appDomain`: App Domain, like: `https://your-app.authing.cn`\n- `redirectUri`: Logout Callback Redirect URI (same in authing console)\n\n## Quick Start\n\nExample project at `examples/basic`.\n\n### Add dependencies\n\n```bash\nnpm install --save @authing/nextjs iron-session swr\n# or\nyarn add @authing/nextjs iron-session swr\n```\n\n### Config\n\nPlaced in `config/index.ts` or somewhere else.\n\n```ts\nexport const clientId =\n  process.env.AUTHING_CLIENT_ID || '61e4da899687d7055442f6b7';\nexport const clientSecret = process.env.AUTHING_CLIENT_SECRET || '';\nexport const appDomain =\n  process.env.AUTHING_CLIENT_DOMAIN || 'https://remix.authing.cn';\nexport const redirectUri =\n  process.env.AUTHING_REDIRECT_URI || 'http://localhost:3000/authing/callback';\nexport const logoutRedirectUri =\n  process.env.AUTHING_LOGOUT_REDIRECT_URI || 'http://localhost:3000/';\n```\n\n### Create SessionStorage\n\nCreate `lib/session.ts`. In this example we use `iron-session` to store session.\n\n### Create Login, Logout, Callback APIs\n\nNotice that login url is `/api/login`, and logout is `/api/logout`\n\nCreate `pages/api/login.ts`:\n\n```ts\nimport { createLoginApi } from '@authing/nextjs';\nimport { appDomain, clientId, redirectUri } from '../../config';\n\nexport default createLoginApi({\n  appDomain,\n  clientId,\n  redirectUri,\n  scope: 'openid roles username phone profile'\n});\n```\n\nCreate `pages/api/logout.ts`:\n\n```ts\nimport { withIronSessionApiRoute } from 'iron-session/next';\nimport { createLogoutApi } from '@authing/nextjs';\nimport { appDomain, logoutRedirectUri } from '../../config';\nimport { sessionOptions } from '../../lib/session';\n\nexport default withIronSessionApiRoute(\n  createLogoutApi({\n    appDomain,\n    redirectUri: logoutRedirectUri\n  }),\n  sessionOptions\n);\n```\n\nCreate `pages/api/callback.ts`:\n\n```ts\nimport { createCallbackApi } from '@authing/nextjs';\nimport { appDomain, clientId, clientSecret } from '../../config';\nimport { withIronSessionApiRoute } from 'iron-session/next';\nimport { sessionOptions } from '../../lib/session';\n\nexport default withIronSessionApiRoute(\n  createCallbackApi({\n    appDomain,\n    clientId,\n    clientSecret,\n    // 登录失败返回登录页\n    failureRedirect: '/error',\n    successRedirect: '/ssr'\n  }),\n  sessionOptions\n);\n```\n\n### Use in SSR\n\n```ts\nimport { withIronSessionSsr } from 'iron-session/next';\nimport { sessionOptions } from '../lib/session';\n\nexport const getServerSideProps = withIronSessionSsr(async function ({\n  req,\n  res\n}) {\n  const user = req.session.user;\n\n  if (user === undefined) {\n    res.setHeader('location', '/api/login');\n    res.statusCode = 302;\n    res.end();\n    return {\n      props: {\n        user: { isLoggedIn: false }\n      }\n    };\n  }\n\n  return {\n    props: { user: req.session.user }\n  };\n},\nsessionOptions);\n```\n\n### Use in SSG\n\nCreate API: `pages/api/me.ts`:\n\n```ts\nimport { withIronSessionApiRoute } from 'iron-session/next';\nimport { sessionOptions } from '../../lib/session';\nimport { NextApiRequest, NextApiResponse } from 'next';\n\nexport type User = {\n  isLoggedIn: boolean;\n  username: string;\n};\n\nexport default withIronSessionApiRoute(userRoute, sessionOptions);\n\nasync function userRoute(req: NextApiRequest, res: NextApiResponse\u003cUser\u003e) {\n  if (req.session.user) {\n    // in a real world application you might read the user id from the session and then do a database request\n    // to get more information on the user if needed\n    res.json({\n      ...req.session.user,\n      isLoggedIn: true\n    });\n  } else {\n    res.json({\n      isLoggedIn: false,\n      username: ''\n    });\n  }\n}\n```\n\nCreate React hook `hooks/use-user.ts`:\n\n```ts\nimport { useEffect } from 'react';\nimport Router from 'next/router';\nimport useSWR from 'swr';\nimport { User } from '../pages/api/me';\n\nexport default function useUser({\n  redirectTo = '',\n  redirectIfFound = false\n} = {}) {\n  const { data: user, error } = useSWR\u003cUser\u003e('/api/me');\n\n  useEffect(() =\u003e {\n    // if no redirect needed, just return (example: already on /dashboard)\n    // if user data not yet there (fetch in progress, logged in or not) then don't do anything yet\n    if (!redirectTo || !user) return;\n\n    if (\n      // If redirectTo is set, redirect if the user was not found.\n      (redirectTo \u0026\u0026 !redirectIfFound \u0026\u0026 !user?.isLoggedIn) ||\n      // If redirectIfFound is also set, redirect if the user was found\n      (redirectIfFound \u0026\u0026 user?.isLoggedIn)\n    ) {\n      Router.push(redirectTo);\n    }\n  }, [user, redirectIfFound, redirectTo]);\n\n  return { user, error };\n}\n```\n\nCreate page `pages/sg.tsx`:\n\n```ts\nimport useUser from '../hooks/use-user';\nimport Link from 'next/link';\n\n// Make sure to check https://nextjs.org/docs/basic-features/layouts for more info on how to use layouts\nexport default function SgProfile() {\n  const { user } = useUser({\n    redirectTo: '/api/login'\n  });\n\n  return (\n    \u003c\u003e\n      \u003cnav\u003e\n        \u003cLink href='/ssr'\u003eSSR\u003c/Link\u003e | \u003cLink href='/api/logout'\u003eLogout\u003c/Link\u003e\n      \u003c/nav\u003e\n      {user \u0026\u0026 (\n        \u003c\u003e\n          \u003cpre\u003e{JSON.stringify(user, null, 2)}\u003c/pre\u003e\n        \u003c/\u003e\n      )}\n    \u003c/\u003e\n  );\n}\n```\n\n## Others\n\n- [@authing/remix](https://github.com/Authing/authing-remix)\n\n## LICENSE\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwillin%2Fauthing-nextjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwillin%2Fauthing-nextjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwillin%2Fauthing-nextjs/lists"}