@auth/express
@auth/express
目前處於實驗階段。API 未來將會變更。
Express Auth 是 Auth.js 的官方 Express 整合。它提供了一種簡單的方法,只需幾行程式碼即可將驗證新增至您的 Express 應用程式。
安裝
npm install @auth/express
使用方式
import { ExpressAuth } from "@auth/express"
import GitHub from "@auth/express/providers/github"
import express from "express"
const app = express()
// If app is served through a proxy, trust the proxy to allow HTTPS protocol to be detected
// https://express.dev.org.tw/en/guide/behind-proxies.html
app.set('trust proxy', true)
app.use("/auth/*", ExpressAuth({ providers: [ GitHub ] }))
別忘了設定 AUTH_SECRET
環境變數。這應該是一個至少 32 個字元的隨機字串。在 UNIX 系統上,您可以使用 openssl rand -hex 32
或查看 https://generate-secret.vercel.app/32
。
您還需要將環境變數載入您的執行環境。例如,在 Node.js 中,使用像 dotenv
或在 Deno 中使用 Deno.env
等套件。
提供者設定
提供者使用的回呼 URL 必須設定為以下值,除非您在不同的路徑上掛載 ExpressAuth
處理程式
[origin]/auth/callback/[provider]
登入和登出
一旦您的應用程式掛載完成,您可以從用戶端程式碼向以下 REST API 端點發出請求來登入或登出。注意:請務必在所有登入和登出請求的請求主體中包含 csrfToken
。
管理工作階段
如果您使用具有範本引擎(例如 EJS、Pug)的 Express,您可以透過中介軟體,讓所有路由都能使用工作階段資料,如下所示
import { getSession } from "@auth/express"
export function authSession(req: Request, res: Response, next: NextFunction) {
res.locals.session = await getSession(req)
next()
}
app.use(authSession)
// Now in your route
app.get("/", (req, res) => {
const { session } = res.locals
res.render("index", { user: session?.user })
})
授權
您可以透過檢查是否存在工作階段來保護路由,如果不存在工作階段,則重新導向至登入頁面。這可以針對每個路由執行,也可以使用以下中介軟體針對一組路由執行
export async function authenticatedUser(
req: Request,
res: Response,
next: NextFunction
) {
const session = res.locals.session ?? (await getSession(req, authConfig))
if (!session?.user) {
res.redirect("/login")
} else {
next()
}
}
每個路由
若要保護單一路由,只需將中介軟體新增至路由,如下所示
// This route is protected
app.get("/profile", authenticatedUser, (req, res) => {
const { session } = res.locals
res.render("profile", { user: session?.user })
})
// This route is not protected
app.get("/", (req, res) => {
res.render("index")
})
app.use("/", root)
每組路由
若要保護一組路由,請定義一個路由器,並將中介軟體新增至路由器,如下所示
import { Router } from "express"
const router = Router()
router.use(authenticatedUser) // All routes defined after this will be protected
router.get("/", (req, res) => {
res.render("protected")
})
export default router
然後,我們掛載路由器,如下所示
import protected from "./routes/protected.route"
app.use("/protected", protected)
關於 ESM 的注意事項
@auth/express 僅限 ESM。這表示您的 package.json 必須包含 "type": "module"
,而 tsconfig.json 應包含 "module": "NodeNext"
或 ESNext
。檔案匯入必須使用 .js
副檔名,例如 import { MyRouter } from "./my-router.js"
。
您的開發伺服器應使用 tsx 搭配 tsx index.ts
(快速啟動,沒有類型檢查)或 ts-node 搭配「node --loader ts-node/esm index.ts」(啟動較慢,但有類型檢查)來執行。
雖然不建議這麼做,但如果您希望在 CommonJS 專案中使用 @auth/express 而不遷移和進行上述變更,則可以使用 tsx 執行開發伺服器,並且可以使用 pkgroll 進行編譯。將 ‘“name”: ”./dist/index.js”’ 或 ‘“name”: ”./dist/index.mjs”’ 新增至您的 package.json,並執行 ‘pkgroll’ 以使用 ESM 和 CommonJS 支援進行編譯。對於新專案,建議直接使用 ESM。
AuthError
所有 Auth.js 錯誤的基本錯誤類別。它經過最佳化,可透過 logger.error
選項,以格式良好的方式印在伺服器記錄中。
擴展
建構子
new AuthError(message, errorOptions)
new AuthError(message?, errorOptions?): AuthError
參數
參數 | 類型 |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
回傳
覆寫
Error.constructor
屬性
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
類型宣告
err?
optional err: Error;
覆寫
Error.cause
message
message: string;
繼承自
Error.message
name
name: string;
繼承自
Error.name
stack?
optional stack: string;
繼承自
Error.stack
type
type: ErrorType;
錯誤類型。用於在日誌中識別錯誤。
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
用於格式化堆疊追蹤的可選覆寫
請參閱
https://v8.dev.org.tw/docs/stack-trace-api#customizing-stack-traces
參數
參數 | 類型 |
---|---|
err | 錯誤 |
stackTraces | CallSite [] |
回傳
any
繼承自
Error.prepareStackTrace
stackTraceLimit
static stackTraceLimit: number;
繼承自
Error.stackTraceLimit
方法
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
在目標物件上建立 .stack 屬性
參數
參數 | 類型 |
---|---|
targetObject | object |
constructorOpt ? | Function |
回傳
void
繼承自
Error.captureStackTrace
CredentialsSignin
可以從 Credentials 提供者的 authorize
回呼中拋出。當 authorize
回呼期間發生錯誤時,可能會發生兩種情況
- 使用者會被重新導向到登入頁面,網址中帶有
error=CredentialsSignin&code=credentials
。code
是可設定的。 - 如果您在處理表單動作的伺服器端框架中拋出此錯誤,則會拋出此錯誤,而不是重新導向使用者,因此您需要處理。
繼承自
建構子
new CredentialsSignin(message, errorOptions)
new CredentialsSignin(message?, errorOptions?): CredentialsSignin
參數
參數 | 類型 |
---|---|
message ? | string | ErrorOptions |
errorOptions ? | ErrorOptions |
回傳
繼承自
屬性
cause?
optional cause: Record<string, unknown> & {
err: Error;
};
類型宣告
err?
optional err: Error;
繼承自
code
code: string;
在重新導向網址的 code
查詢參數中設定的錯誤代碼。
⚠ 注意:此屬性將會包含在網址中,因此請確保它不會暗示敏感錯誤。
如果需要除錯,完整的錯誤始終記錄在伺服器上。
一般而言,我們不建議明確提示使用者是否有錯誤的使用者名稱或密碼,請嘗試使用「無效的憑證」之類的提示。
message
message: string;
繼承自
name
name: string;
繼承自
stack?
optional stack: string;
繼承自
type
type: ErrorType;
錯誤類型。用於在日誌中識別錯誤。
繼承自
kind
static kind: string;
繼承自
prepareStackTrace()?
static optional prepareStackTrace: (err, stackTraces) => any;
用於格式化堆疊追蹤的可選覆寫
請參閱
https://v8.dev.org.tw/docs/stack-trace-api#customizing-stack-traces
參數
參數 | 類型 |
---|---|
err | 錯誤 |
stackTraces | CallSite [] |
回傳
any
繼承自
stackTraceLimit
static stackTraceLimit: number;
繼承自
type
static type: string;
方法
captureStackTrace()
static captureStackTrace(targetObject, constructorOpt?): void
在目標物件上建立 .stack 屬性
參數
參數 | 類型 |
---|---|
targetObject | object |
constructorOpt ? | Function |
回傳
void
繼承自
帳號
通常包含有關正在使用的提供者的資訊,並且還擴展了 TokenSet
,這是 OAuth 提供者返回的不同權杖。
繼承自
Partial
<TokenEndpointResponse
>
屬性
access_token?
optional readonly access_token: string;
繼承自
Partial.access_token
authorization_details?
optional readonly authorization_details: AuthorizationDetails[];
繼承自
Partial.authorization_details
expires_at?
optional expires_at: number;
基於 TokenEndpointResponse.expires_in 計算的值。
它是 TokenEndpointResponse.access_token 過期的絕對時間戳記(以秒為單位)。
此值可用於實作權杖輪換以及 TokenEndpointResponse.refresh_token。
請參閱
- https://authjs.dev.org.tw/guides/refresh-token-rotation#database-strategy
- https://www.rfc-editor.org/rfc/rfc6749#section-5.1
expires_in?
optional readonly expires_in: number;
繼承自
Partial.expires_in
id_token?
optional readonly id_token: string;
繼承自
Partial.id_token
provider
provider: string;
此帳號的提供者 ID。例如:「google」。請參閱 https://authjs.dev.org.tw/reference/core/providers 的完整清單
providerAccountId
providerAccountId: string;
此值取決於用於建立帳號的提供者類型。
- oauth/oidc:OAuth 帳號的 ID,從
profile()
回呼中傳回。 - email:使用者的電子郵件地址。
- 憑證:從
authorize()
回呼函式返回的id
refresh_token?
optional readonly refresh_token: string;
繼承自
Partial.refresh_token
scope?
optional readonly scope: string;
繼承自
Partial.scope
token_type?
optional readonly token_type: Lowercase<string>;
注意:由於此值不區分大小寫,因此一律以小寫形式返回。
繼承自
Partial.token_type
type
type: ProviderType;
此帳戶的供應商類型
userId?
optional userId: string;
此帳戶所屬使用者的 ID
請參閱
https://authjs.dev.org.tw/reference/core/adapters#adapteruser
DefaultSession
擴展自
屬性
expires
expires: string;
user?
optional user: User;
Profile
從您的 OAuth 供應商返回的使用者資訊。
請參閱
https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims
可索引
[claim
: string
]: unknown
屬性
address?
optional address: null | {
country: null | string;
formatted: null | string;
locality: null | string;
postal_code: null | string;
region: null | string;
street_address: null | string;
};
birthdate?
optional birthdate: null | string;
email?
optional email: null | string;
email_verified?
optional email_verified: null | boolean;
family_name?
optional family_name: null | string;
gender?
optional gender: null | string;
given_name?
optional given_name: null | string;
id?
optional id: null | string;
locale?
optional locale: null | string;
middle_name?
optional middle_name: null | string;
name?
optional name: null | string;
nickname?
optional nickname: null | string;
phone_number?
optional phone_number: null | string;
picture?
optional picture: any;
preferred_username?
optional preferred_username: null | string;
profile?
optional profile: null | string;
sub?
optional sub: null | string;
updated_at?
optional updated_at: null | string | number | Date;
website?
optional website: null | string;
zoneinfo?
optional zoneinfo: null | string;
Session
已登入使用者的活動工作階段。
擴展自
屬性
expires
expires: string;
繼承自
user?
optional user: User;
繼承自
User
OAuth 供應商的 profile
回呼函式中傳回的物件形狀,可在 jwt
和 session
回呼函式中使用,或在使用資料庫時,可在 session
回呼函式的第二個參數中使用。
擴展自
屬性
email?
optional email: null | string;
id?
optional id: string;
image?
optional image: null | string;
name?
optional name: null | string;
ExpressAuthConfig
type ExpressAuthConfig: Omit<AuthConfig, "raw">;
GetSessionResult
type GetSessionResult: Promise<Session | null>;
customFetch
const customFetch: unique symbol;
此選項可讓您覆寫供應商用來直接向供應商的 OAuth 端點發出請求的預設 fetch
函式。不正確的使用可能會產生安全性隱憂。
它可用於支援企業 Proxy、自訂 fetch 程式庫、快取探索端點、為測試新增模擬、記錄、為不符合規格的供應商設定自訂標頭/參數等。
範例
import { Auth, customFetch } from "@auth/core"
import GitHub from "@auth/core/providers/github"
const dispatcher = new ProxyAgent("my.proxy.server")
function proxy(...args: Parameters<typeof fetch>): ReturnType<typeof fetch> {
return undici(args[0], { ...(args[1] ?? {}), dispatcher })
}
const response = await Auth(request, {
providers: [GitHub({ [customFetch]: proxy })]
})
請參閱
- https://undici.nodejs.org/#/docs/api/ProxyAgent?id=example-basic-proxy-request-with-local-agent-dispatcher
- https://authjs.dev.org.tw/guides/corporate-proxy
ExpressAuth()
ExpressAuth(config): (req, res, next) => Promise<void>
參數
參數 | 類型 |
---|---|
config | ExpressAuthConfig |
返回
Function
參數
參數 類型 req
Request
<ParamsDictionary
,any
,any
,ParsedQs
,Record
<string
,any
>>res
Response
<any
,Record
<string
,any
>>next
NextFunction
返回
Promise
<void
>
getSession()
getSession(req, config): GetSessionResult
參數
參數 | 類型 |
---|---|
req | Request <ParamsDictionary , any , any , ParsedQs , Record <string , any >> |
config | ExpressAuthConfig |