Skip to content

Commit

Permalink
feat(docs): add authentication page
Browse files Browse the repository at this point in the history
Closes: #19
  • Loading branch information
Romakita committed Apr 17, 2024
1 parent 5e0c23d commit a97e6b8
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 0 deletions.
57 changes: 57 additions & 0 deletions docs/docs/authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

# Authentication

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.

<<< @/docs/snippets/authentication/auth-example.ts

::: tip
If you planed to use `Passport.js`, it's recommended to follow the [Passport.js guide here](/tutorials/passport.md).
:::

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.

## Usage

Here is an example of the CustomAuth middleware using the Passport.js method to check authentication:

<<< @/docs/snippets/authentication/auth-middleware.ts

## 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:

<<< @/docs/snippets/authentication/auth-swagger-example.ts

To avoid that, we can create a decorator which apply all of these instructions automatically, like this:

<<< @/docs/snippets/authentication/auth-decorator-example.ts

::: tip
Additionally, you can use the `In` decorator to add automatically the `Authorization` header field in the swagger spec:

<<< @/docs/snippets/authentication/auth-decorator-example-2.ts

:::

And use it on our controller and endpoints:

<<< @/docs/snippets/authentication/auth-custom-auth-example.ts

## With Passport.js

Another solution is to use [Passport.js](/tutorials/passport.md) to protect your API. Ts.ED provide
a [@tsed/passport](/tutorials/passport.md) 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:

<iframe src="https://codesandbox.io/embed/tsed-swagger-with-authorization-hi5pp?fontsize=14&hidenavigation=1&theme=dark"
style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;"
title="tsed-swagger-with-authorization"
allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"></iframe>
11 changes: 11 additions & 0 deletions docs/docs/snippets/authentication/auth-custom-auth-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
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() {}
}
19 changes: 19 additions & 0 deletions docs/docs/snippets/authentication/auth-decorator-example-2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
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)
);
}
13 changes: 13 additions & 0 deletions docs/docs/snippets/authentication/auth-decorator-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
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));
}
12 changes: 12 additions & 0 deletions docs/docs/snippets/authentication/auth-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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() {}
}
21 changes: 21 additions & 0 deletions docs/docs/snippets/authentication/auth-middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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");
}
}
}
17 changes: 17 additions & 0 deletions docs/docs/snippets/authentication/auth-swagger-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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() {}
}

0 comments on commit a97e6b8

Please sign in to comment.