# Authentication
# Usage
Ts.ED uses middlewares to protect your route with your own strategy. To handle correctly a request and protect your endpoints, we have to use the UseAuth decorator.
import {Controller} from "@tsed/di";
import {Get} from "@tsed/schema";
import {UseAuth} from "@tsed/platform-middlewares";
import {CustomAuthMiddleware} from "../guards/CustomAuthMiddleware";
@Controller("/dashboard")
@UseAuth(CustomAuthMiddleware, {role: "admin"}) // on class level for all endpoints
class DashboardCtrl {
@Get("/")
@UseAuth(CustomAuthMiddleware, {role: "admin"}) // or for specific endpoints
public getResource() {}
}
2
3
4
5
6
7
8
9
10
11
12
TIP
If you planed to use Passport.js
, it's recommended to follow the Passport.js guide here.
Any middleware can be used as an authentication strategy. Just keep in mind, to work properly, the middleware must use Context decorator to retrieve the endpoint context execution.
Here is an example of the CustomAuth middleware using the Passport.js method to check authentication:
import {Req} from "@tsed/common";
import {Context} from "@tsed/platform-params";
import {Middleware, MiddlewareMethods} from "@tsed/platform-middlewares";
import {Forbidden, Unauthorized} from "@tsed/exceptions";
@Middleware()
export class CustomAuthMiddleware implements MiddlewareMethods {
public use(@Req() request: Req, @Context() ctx: Context) {
// retrieve options given to the @UseAuth decorator
const options = ctx.endpoint.get(CustomAuthMiddleware) || {};
if (!request.isAuthenticated()) {
// passport.js method to check auth
throw new Unauthorized("Unauthorized");
}
if (request.user?.role !== options.role) {
throw new Forbidden("Forbidden");
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Create your Auth decorator
It could be practical to create you own Authentication decorator to reduce the amount of code. For example, if we use swagger, we have to configure some extra security and responses information and it can quickly become heavy.
Example:
import {Controller} from "@tsed/di";
import {Get, Returns, Security} from "@tsed/schema";
import {UseAuth} from "@tsed/platform-middlewares";
import {Forbidden, Unauthorized} from "@tsed/exceptions";
import {CustomAuthMiddleware} from "../guards/CustomAuthMiddleware";
@Controller("/dashboard")
@UseAuth(CustomAuthMiddleware, {role: "admin"}) // on class level for all endpoints
@Security("oauth2", "email", "firstname")
class DashboardCtrl {
@Get("/")
@UseAuth(CustomAuthMiddleware, {role: "admin"}) // or for specific endpoints
@Security("oauth2", "email", "firstname")
@Returns(401, Unauthorized).Description("Unauthorized")
@Returns(403, Forbidden).Description("Forbidden")
public getResource() {}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
To avoid that, we can create a decorator which apply all of these instructions automatically, like this:
import {UseAuth} from "@tsed/platform-middlewares";
import {useDecorators} from "@tsed/core";
import {Security, Returns} from "@tsed/schema";
import {CustomAuthMiddleware} from "../guards/CustomAuthMiddleware";
export interface AuthOpts extends Record<string, unknown> {
role?: string;
scopes?: string[];
}
export function CustomAuth(options: AuthOpts = {}): Function {
return useDecorators(UseAuth(CustomAuthMiddleware, options), Security("oauth", ...(options.scopes || [])), Returns(401), Returns(403));
}
2
3
4
5
6
7
8
9
10
11
12
13
TIP
Additionally, you can use the Operation decorator to add automatically the Authorization
header field in the swagger spec:
import {In, Returns, Security} from "@tsed/schema";
import {UseAuth} from "@tsed/platform-middlewares";
import {useDecorators} from "@tsed/core";
import {CustomAuthMiddleware} from "../guards/CustomAuthMiddleware";
export interface CustomAuthOptions extends Record<string, unknown> {
role?: string;
scopes?: string[];
}
export function CustomAuth(options: CustomAuthOptions = {}): Function {
return useDecorators(
UseAuth(CustomAuthMiddleware, options),
Security("oauth", ...(options.scopes || [])),
In("header").Name("Authorization").Type(String).Required(true),
Returns(401),
Returns(403)
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
And use it on our controller and endpoints:
import {Get} from "@tsed/schema";
import {Controller} from "@tsed/di";
import {CustomAuth} from "../decorators/CustomAuth";
@Controller("/dashboard")
@CustomAuth({role: "admin", scopes: ["email", "firstname"]})
class DashboardCtrl {
@Get("/")
@CustomAuth({role: "admin", scopes: ["email", "firstname"]})
public getResource() {}
}
2
3
4
5
6
7
8
9
10
11
# With Passport.js
Another solution is to use Passport.js to protect your API. Ts.ED provide a @tsed/passport plugin in order to facilitate the use of this library within the framework.
The following codesandbox example show you how you can use this plugin combined with Swagger to describe your API:
Last Updated: 2/5/2023, 1:16:22 PM
Other topics
- Session & cookies
- Passport.js
- Keycloak
- Prisma
- TypeORM
- MikroORM
- Mongoose
- GraphQL
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Serverless HTTP
- Seq
- OIDC
- Stripe
- Agenda
- Terminus
- Serverless
- IORedis
- Controllers
- Providers
- Model
- JsonMapper
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Exceptions
- Throw HTTP Exceptions
- Cache
- Command
- Response Filter
- Injection scopes
- Custom providers
- Lazy-loading provider
- Custom endpoint decorator
- Testing
- Customize 404