Skip to content

Commit

Permalink
chore: drop t.middleware() (t3-oss#1708)
Browse files Browse the repository at this point in the history
Co-authored-by: Julius Marminge <[email protected]>
  • Loading branch information
KATT and juliusmarminge committed Dec 28, 2023
1 parent 2413e72 commit 8f379b4
Show file tree
Hide file tree
Showing 16 changed files with 75 additions and 97 deletions.
5 changes: 5 additions & 0 deletions .changeset/tidy-panthers-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"create-t3-app": patch
---

chore: drop `t.middleware()`
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
"source.fixAll.eslint": "explicit"
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
Expand Down
21 changes: 9 additions & 12 deletions cli/template/extras/src/server/api/trpc-app/with-auth-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,15 @@ export const createTRPCRouter = t.router;
*/
export const publicProcedure = t.procedure;

/** Reusable middleware that enforces users are logged in before running the procedure. */
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -92,13 +99,3 @@ const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
},
});
});

/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
21 changes: 9 additions & 12 deletions cli/template/extras/src/server/api/trpc-app/with-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,15 @@ export const createTRPCRouter = t.router;
*/
export const publicProcedure = t.procedure;

/** Reusable middleware that enforces users are logged in before running the procedure. */
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -89,13 +96,3 @@ const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
},
});
});

/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
23 changes: 10 additions & 13 deletions cli/template/extras/src/server/api/trpc-pages/with-auth-db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,16 @@ export const createTRPCRouter = t.router;
*/
export const publicProcedure = t.procedure;

/** Reusable middleware that enforces users are logged in before running the procedure. */
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.session?.user) {
/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
Expand All @@ -119,13 +126,3 @@ const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
},
});
});

/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
23 changes: 10 additions & 13 deletions cli/template/extras/src/server/api/trpc-pages/with-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,16 @@ export const createTRPCRouter = t.router;
*/
export const publicProcedure = t.procedure;

/** Reusable middleware that enforces users are logged in before running the procedure. */
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.session?.user) {
/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
Expand All @@ -117,13 +124,3 @@ const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
},
});
});

/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the session is valid and guarantees `ctx.session.user` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
4 changes: 1 addition & 3 deletions www/src/pages/ar/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. أنشئ tRPC Middleware وتأكد ما اذا كان هذا المستخدم يملك الصلاحيات اللازمة أم لا.

```ts:server/trpc/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -110,8 +110,6 @@ const isAuthed = t.middleware(({ ctx, next }) => {
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
```

الـ Session Object صغير ويحتوي علي عدد قليل من الخانات، وعند استخدامك لـ `protectedProcedures`يمكنك الوصول الى هذة البيانات منها الـ UserId وعندها يمكنك عمل fetch لبيانات اخرى من قاعدة البيانات.
Expand Down
12 changes: 6 additions & 6 deletions www/src/pages/en/usage/next-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Create a tRPC middleware that checks if the user is authenticated. We then use the middleware in a `protectedProcedure`. Any caller to these procedures must be authenticated, or else an error will be thrown which can be appropriately handled by the client.

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -135,9 +135,7 @@ const isAuthed = t.middleware(({ ctx, next }) => {
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
})
```

The session object is a light, minimal representation of the user and only contains a few fields. When using the `protectedProcedures`, you have access to the user's id which can be used to fetch more data from the database.
Expand Down Expand Up @@ -179,10 +177,12 @@ If for example, you'd like to add a `role` to the `User` model, you would need t

## Usage with Next.js middleware

Usage of NextAuth.js with Next.js middleware [requires the use of the JWT session strategy](https://next-auth.js.org/configuration/nextjs#caveats) for authentication. This is because the middleware is only able to access the session cookie if it is a JWT. By default, Create T3 App is configured to use the **default** database strategy, in combination with Prisma as the database adapter.
Usage of NextAuth.js with Next.js middleware [requires the use of the JWT session strategy](https://next-auth.js.org/configuration/nextjs#caveats) for authentication. This is because the middleware is only able to access the session cookie if it is a JWT. By default, Create T3 App is configured to use the **default** database strategy, in combination with Prisma as the database adapter.

<Callout type="warning">
Using database sessions is the recommended approach and you should read up on JWTs before switching to the JWT session strategy to avoid any security issues.
Using database sessions is the recommended approach and you should read up on
JWTs before switching to the JWT session strategy to avoid any security
issues.
</Callout>

After switching to the JWT session strategy. Make sure to update the `session` callback in `src/server/auth.ts`.
Expand Down
6 changes: 2 additions & 4 deletions www/src/pages/es/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Crea un middleware tRPC que verifique si el usuario está autenticado. Luego usamos el middleware en una `protectedProcedure`. Cualquier persona que llama a estos procedimientos debe de estar autenticada, o de lo contrario se lanzará un error que el cliente puede manejar adecuadamente.

```ts:server/trpc/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -109,9 +109,7 @@ const isAuthed = t.middleware(({ ctx, next }) => {
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
})
```

El objeto de sesión es una representación ligera y mínima del usuario y solo contiene algunos campos. Cuando uses `protectedProcedures`, tienes acceso al ID del usuario que puede usarse para obtener más datos de la base de datos.
Expand Down
10 changes: 5 additions & 5 deletions www/src/pages/fr/usage/next-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Créez un middleware tRPC qui vérifie si l'utilisateur est authentifié. Nous utilisons ensuite le middleware dans une `protectedProcedure`. Tout appelant à ces procédures doit être authentifié, sinon une erreur sera générée qui pourra être gérée de manière appropriée par le client.

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -135,9 +135,7 @@ const isAuthed = t.middleware(({ ctx, next }) => {
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
})
```

L'objet de session est une représentation légère et minimale de l'utilisateur et ne contient que quelques champs. Lorsque vous utilisez les `protectedProcedures`, vous avez accès à l'identifiant de l'utilisateur qui peut être utilisé pour extraire plus de données de la base de données.
Expand Down Expand Up @@ -182,7 +180,9 @@ Si, par exemple, vous souhaitez ajouter un `role` au modèle `User`, vous devrez
Utilisation de NextAuth.js avec le middleware Next.js [nécessite l'utilisation de la stratégie de session JWT](https://next-auth.js.org/configuration/nextjs#caveats) pour l'authentification. En effet, le middleware ne peut accéder au cookie de session que s'il s'agit d'un JWT. Par défaut, Create T3 App est configuré pour utiliser la stratégie de base de données **default**, en combinaison avec Prisma comme adaptateur de base de données.

<Callout type="warning">
L'utilisation de sessions en base de données est l'approche recommandée et vous devriez vous informer sur les JWT (JSON Web Token) avant de passer à la stratégie de session JWT, et ce, afin d'éviter tout problème de sécurité.
L'utilisation de sessions en base de données est l'approche recommandée et
vous devriez vous informer sur les JWT (JSON Web Token) avant de passer à la
stratégie de session JWT, et ce, afin d'éviter tout problème de sécurité.
</Callout>

Après avoir basculé vers la stratégie de session JWT, assurez-vous de mettre à jour le callback `session` dans `src/server/auth.ts`. L'objet `user` sera `undefined`. À la place, récupérez l'identifiant de l'utilisateur à partir de l'objet `token`.
Expand Down
6 changes: 2 additions & 4 deletions www/src/pages/ja/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. ユーザーが認証されているかどうかをチェックする tRPC ミドルウェアを作成します。そして、そのミドルウェアを `protectedProcedure` で使用します。これらのプロシージャの呼び出し元はすべて認証されていなければなりません。そうでなければ、エラーが投げられるので、クライアントで適切にエラー処理を行えます。

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -132,9 +132,7 @@ const isAuthed = t.middleware(({ ctx, next }) => {
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
})
```

セッションオブジェクトは、ユーザーの軽くて最小限の表現であり、いくつかのフィールドしか含んでいません。`protectedProcedures`を使用するとユーザー id にアクセスでき、データベースからさらにデータを取得するのに使用できます。
Expand Down
6 changes: 2 additions & 4 deletions www/src/pages/no/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Lag en tRPC-middleware som sjekker om brukeren er autentisert. Vi bruker deretter middlewaren i en `protectedProcedure`. Hvert kall av disse prosedyrene må autentiseres, ellers kastes en feilmelding, som kan håndteres av klienten.

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -129,9 +129,7 @@ const isAuthed = t.middleware(({ ctx, next }) => {
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
}));
```

`Session`-objektet er en minimal representasjon av brukeren og inneholder bare noen få felt. Hvis du bruker `protectedProcedures`, har du tilgang til brukerens ID, som kan brukes til å hente ut mer data fra databasen.
Expand Down
8 changes: 3 additions & 5 deletions www/src/pages/pl/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,17 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Stwórz middleware tRPC, który sprawdza, czy użytkownik jest autoryzowany. Wykorzystamy następnie stworzony middleware w `protectedProcedure` - specjalnej, zabezpieczonej procedurze. Każda osoba wywołująca ją będzie musiała spełniać warunki autoryzacji - w przeciwnym razie wystąpi błąd, który w odpowiedni sposób będzie mógł zostać obsłużony po stronie klienta.

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// `session` dziedzicząca odpowiedni typ w tym przypadku nie może mieć wartości `null`
// inferer `session` som ikke-nullbar
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
}));
```

Obiekt `session` to minimalna i lekka reprezentacja użytkownika zawierająca jedynie parę pól. Jeśli korzystasz z procedur `protectedProcedure`, masz dostęp do ID użytkownika, które może zostać wykorzystane do pobrania większej ilości danych z bazy.
Expand Down
8 changes: 3 additions & 5 deletions www/src/pages/pt/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,19 +122,17 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Criar um middleware tRPC que verifique se o usuário está autenticado. Em seguida, usamos o middleware em um `protectedProcedure`. Qualquer chamador para esses procedimentos deve ser autenticado, caso contrário, será lançado um erro que pode ser tratado adequadamente pelo cliente.

```ts:server/trpc/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// Infere `session` como não-nulo
// inferer `session` som ikke-nullbar
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
}));
```

O objeto de sessão é uma representação leve e mínima do usuário e contém apenas alguns campos. Ao usar `protectedProcedures`, você tem acesso ao id do usuário que pode ser usado para buscar mais dados do banco de dados.
Expand Down
6 changes: 2 additions & 4 deletions www/src/pages/ru/usage/next-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. Создайте tRPC middleware, которое проверяет, аутентифицирован ли пользователь. Затем мы используем middleware в `protectedProcedure`. Любой вызывающий эти процедуры должен быть аутентифицирован, иначе будет сгенерирована ошибка, которую можно правильно обработать на стороне клиента.

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
Expand All @@ -132,9 +132,7 @@ const isAuthed = t.middleware(({ ctx, next }) => {
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
})
```

Обект сессии - это легкое, минимальное представление пользователя и содержит только несколько полей. При использовании `protectedProcedures` у вас есть доступ к идентификатору пользователя, который можно использовать для получения большего количества данных из базы данных.
Expand Down
11 changes: 5 additions & 6 deletions www/src/pages/zh-hans/usage/next-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -125,19 +125,17 @@ export const createContext = async (opts: CreateNextContextOptions) => {
2. 创建一个 tRPC 中间件,来检测用户是否已通过认证。然后我们可以在一个 `protectedProcedure` 里调用该中间件。任何对该路由的调用都会被要求认证,否则会抛出一个错误,由客户端妥善处理。

```ts:server/api/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// 推断出 `session` 为非空类型
// inferer `session` som ikke-nullbar
session: { ...ctx.session, user: ctx.session.user },
},
});
});

export const protectedProcedure = t.procedure.use(isAuthed);
}));
```

这个 session 对象是对用户数据的一个轻量、最小化表示,仅包含了少量字段。当使用 `protectedProcedures` 时,你可以借助访问用户 ID 来从数据库里读取该用户的更多数据。
Expand Down Expand Up @@ -182,7 +180,8 @@ const userRouter = router({
将 NextAuth.js 搭配 Next.js 中间件一同使用[需要采用 JWT session 策略](https://next-auth.js.org/configuration/nextjs#caveats) 来进行认证。这是因为只有当会话 cookie 为 JWT 时,中间件才能够获取到它。默认情况下,Create T3 App 会用 Prisma 作为数据库适配器,并采取**默认**的数据库策略。

<Callout type="warning">
使用数据库会话是推荐的方法,如果要切换到 JWT 会话策略,请先了解 JWT,以避免出现任何安全问题。
使用数据库会话是推荐的方法,如果要切换到 JWT 会话策略,请先了解
JWT,以避免出现任何安全问题。
</Callout>

在切换到 JWT 会话策略后,请确保更新 `src/server/auth.ts` 中的 `session` 回调函数。
Expand Down

0 comments on commit 8f379b4

Please sign in to comment.