download
raw
3.54 kB
/**
* Subjects are what the access token generated at the end of the auth flow will map to. Under
* the hood, the access token is a JWT that contains this data.
*
* #### Define subjects
*
* ```ts title="subjects.ts"
* import { object, string } from "valibot"
*
* const subjects = createSubjects({
* user: object({
* userID: string()
* })
* })
* ```
*
* We are using [valibot](https://github.com/fabian-hiller/valibot) here. You can use any
* validation library that's following the
* [standard-schema specification](https://github.com/standard-schema/standard-schema).
*
* :::tip
* You typically want to place subjects in its own file so it can be imported by all of your apps.
* :::
*
* You can start with one subject. Later you can add more for different types of users.
*
* #### Set the subjects
*
* Then you can pass it to the `issuer`.
*
* ```ts title="issuer.ts"
* import { subjects } from "./subjects"
*
* const app = issuer({
* providers: { ... },
* subjects,
* // ...
* })
* ```
*
* #### Add the subject payload
*
* When your user completes the flow, you can add the subject payload in the `success` callback.
*
* ```ts title="issuer.ts"
* const app = issuer({
* providers: { ... },
* subjects,
* async success(ctx, value) {
* let userID
* if (value.provider === "password") {
* console.log(value.email)
* userID = ... // lookup user or create them
* }
* return ctx.subject("user", {
* userID
* })
* },
* // ...
* })
* ```
*
* Here we are looking up the userID from our database and adding it to the subject payload.
*
* :::caution
* You should only store properties that won't change for the lifetime of the user.
* :::
*
* Since these will be stored in the access token, you should avoid storing information
* that'll change often. For example, if you store the user's username, you'll need to
* revoke the access token when the user changes their username.
*
* #### Decode the subject
*
* Now when your user logs in, you can use the OpenAuth client to decode the subject. For
* example, in our SSR app we can do the following.
*
* ```ts title="app/page.tsx"
* import { subjects } from "../subjects"
*
* const verified = await client.verify(subjects, cookies.get("access_token")!)
* console.log(verified.subject.properties.userID)
* ```
*
* All this is typesafe based on the shape of the subjects you defined.
*
* @packageDocumentation
*/
import type { v1 } from "@standard-schema/spec"
import { Prettify } from "./util.js"
/**
* Subject schema is a map of types that are used to define the subjects.
*/
export type SubjectSchema = Record<string, v1.StandardSchema>
/** @internal */
export type SubjectPayload<T extends SubjectSchema> = Prettify<
{
[type in keyof T & string]: {
type: type
properties: v1.InferOutput<T[type]>
}
}[keyof T & string]
>
/**
* Create a subject schema.
*
* @example
* ```ts
* const subjects = createSubjects({
* user: object({
* userID: string()
* }),
* admin: object({
* workspaceID: string()
* })
* })
* ```
*
* This is using [valibot](https://github.com/fabian-hiller/valibot) to define the shape of the
* subjects. You can use any validation library that's following the
* [standard-schema specification](https://github.com/standard-schema/standard-schema).
*/
export function createSubjects<Schema extends SubjectSchema = {}>(
types: Schema,
): Schema {
return { ...types }
}

Xet Storage Details

Size:
3.54 kB
·
Xet hash:
84e191fa2cd8848b96b62b542fc25587d14c7393a746164d0d95b9906d65a18b

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