download
raw
4.59 kB
/**
* Use this to connect authentication providers that support OIDC.
*
* ```ts {5-8}
* import { OidcProvider } from "@openauthjs/openauth/provider/oidc"
*
* export default issuer({
* providers: {
* oauth2: OidcProvider({
* clientId: "1234567890",
* issuer: "https://auth.myserver.com"
* })
* }
* })
* ```
*
*
* @packageDocumentation
*/
import { createLocalJWKSet, JSONWebKeySet, jwtVerify } from "jose"
import { WellKnown } from "../client.js"
import { OauthError } from "../error.js"
import { Provider } from "./provider.js"
import { JWTPayload } from "hono/utils/jwt/types"
import { getRelativeUrl, lazy } from "../util.js"
export interface OidcConfig {
/**
* @internal
*/
type?: string
/**
* The client ID.
*
* This is just a string to identify your app.
*
* @example
* ```ts
* {
* clientID: "my-client"
* }
* ```
*/
clientID: string
/**
* The URL of your authorization server.
*
* @example
* ```ts
* {
* issuer: "https://auth.myserver.com"
* }
* ```
*/
issuer: string
/**
* A list of OIDC scopes that you want to request.
*
* @example
* ```ts
* {
* scopes: ["openid", "profile", "email"]
* }
* ```
*/
scopes?: string[]
/**
* Any additional parameters that you want to pass to the authorization endpoint.
* @example
* ```ts
* {
* query: {
* prompt: "consent"
* }
* }
* ```
*/
query?: Record<string, string>
}
/**
* @internal
*/
export type OidcWrappedConfig = Omit<OidcConfig, "issuer" | "name">
interface ProviderState {
state: string
nonce: string
redirect: string
}
/**
* @internal
*/
export interface IdTokenResponse {
idToken: string
claims: Record<string, any>
raw: Record<string, any>
}
export function OidcProvider(
config: OidcConfig,
): Provider<{ id: JWTPayload; clientID: string }> {
const query = config.query || {}
const scopes = config.scopes || []
const wk = lazy(() =>
fetch(config.issuer + "/.well-known/openid-configuration").then(
async (r) => {
if (!r.ok) throw new Error(await r.text())
return r.json() as Promise<WellKnown>
},
),
)
const jwks = lazy(() =>
wk()
.then((r) => r.jwks_uri)
.then(async (uri) => {
const r = await fetch(uri)
if (!r.ok) throw new Error(await r.text())
return createLocalJWKSet((await r.json()) as JSONWebKeySet)
}),
)
return {
type: config.type || "oidc",
init(routes, ctx) {
routes.get("/authorize", async (c) => {
const provider: ProviderState = {
state: crypto.randomUUID(),
nonce: crypto.randomUUID(),
redirect: getRelativeUrl(c, "./callback"),
}
await ctx.set(c, "provider", 60 * 10, provider)
const authorization = new URL(
await wk().then((r) => r.authorization_endpoint),
)
authorization.searchParams.set("client_id", config.clientID)
authorization.searchParams.set("response_type", "id_token")
authorization.searchParams.set("response_mode", "form_post")
authorization.searchParams.set("state", provider.state)
authorization.searchParams.set("nonce", provider.nonce)
authorization.searchParams.set("redirect_uri", provider.redirect)
authorization.searchParams.set("scope", ["openid", ...scopes].join(" "))
for (const [key, value] of Object.entries(query)) {
authorization.searchParams.set(key, value)
}
return c.redirect(authorization.toString())
})
routes.post("/callback", async (c) => {
const provider = await ctx.get<ProviderState>(c, "provider")
if (!provider) return c.redirect(getRelativeUrl(c, "./authorize"))
const body = await c.req.formData()
const error = body.get("error")
if (error)
throw new OauthError(
error.toString() as any,
body.get("error_description")?.toString() || "",
)
const idToken = body.get("id_token")
if (!idToken)
throw new OauthError("invalid_request", "Missing id_token")
const result = await jwtVerify(idToken.toString(), await jwks(), {
audience: config.clientID,
})
if (result.payload.nonce !== provider.nonce) {
throw new OauthError("invalid_request", "Invalid nonce")
}
return ctx.success(c, {
id: result.payload,
clientID: config.clientID,
})
})
},
}
}

Xet Storage Details

Size:
4.59 kB
·
Xet hash:
82adfadf8e4c8b0859c758e055d09214e47b110717f118334c2819e5dd945f28

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.