Skip to main content
Module

x/alosaur/src/security/authorization/README.md

Alosaur - Deno web framework with many decorators
Go to Latest
File

Authorization & Authentication

Example app with authorization & authentication

AuthenticationScheme

Need for use security context, authentificate, verify, signin, signout and more methods.

Now available CookiesAuthentication.DefaultScheme and JwtBearerScheme.

export interface AuthenticationScheme {
  /**
   * This function assign to context identity info, uses in Authorization middleware
   */
  authenticate(context: SecurityContext): Promise<void>;

  /**
   * Create sign identity and assign to context identity info
   */
  signInAsync<I, R = any>(
    context: SecurityContext,
    identity: Identity<I>,
  ): Promise<R>;

  /**
   * Clear sign in info and destroy identity context
   */
  signOutAsync<T, R>(context: SecurityContext): Promise<R>;

  /**
   * Uses in Authorize decorators for handle if AuthPayload result failure
   */
  onFailureResult(context: SecurityContext): void;

  /**
   * Uses in Authorize decorators for handle if AuthPayload result success
   */
  onSuccessResult(context: SecurityContext): void;
}

CookiesScheme

Contains types that enable support for Cookies based authentication.

You can use default CookiesAuthentication.DefaultScheme with signIn url. or extends from CookiesScheme for create other cases, for example extend onFailureResult

export namespace CookiesAuthentication {
  export const DefaultScheme = new CookiesScheme(
    "/account/login",
  );
}

For use Alosaur Authorization with CookiesScheme you need create session middleware.

More about Alosaur session middleware

app.ts:

const app = new App({
  providers: [{ // need for create security context
    token: Context,
    useClass: SecurityContext,
  }],
});

// create session store
const sessionStore = new MemoryStore();
await sessionStore.init();

// create middleware with options
const sessionMiddleware = new SessionMiddleware(sessionStore, {
  secret: 123456789n,
  maxAge: DAYS_30,
  path: "/",
});

// create auth middlware with schemes
const authMiddleware = new AuthMiddleware([
  CookiesAuthentication.DefaultScheme,
]);

app.use(new RegExp("/"), sessionMiddleware);
app.use(new RegExp("/"), authMiddleware);

JwtBearerScheme

Contains types that enable support for JWT bearer based authentication.

For signIn, and authentificate you can create instance of scheme.

const key = await crypto.subtle.generateKey(
  { name: "HMAC", hash: "SHA-512" },
  true,
  ["sign", "verify"],
);

export const JWTscheme = new JwtBearerScheme(
  "HS512",
  key,
  30 * 24 * 60 * 60 * 1000,
);
//     private readonly algorithm: Algorithm,
//     private readonly key: CryptoKey,
//     private readonly expires: number = DAYS_30,

// and use JWTscheme in other cases, when need scheme

const app = new App({
  providers: [{ // need for create security context
    token: Context,
    useClass: SecurityContext,
  }],
});

// create auth middlware with schemes
const authMiddleware = new AuthMiddleware([JWTscheme]);

app.use(new RegExp("/"), authMiddleware);

Note: JwtBearerScheme not suported signOut

SecurityContext

This context you can use in various methods and middlewares.

SecurityContext extend Context and has methods: signInAsync, signOutAsync, identity.

For create this context you execute this action in App:

app.ts:

const app = new App({
  providers: [{ // need for create security context
    token: Context,
    useClass: SecurityContext,
  }],
});

Example

account.controller.ts:

@Controller("/account")
export class AccountController {
  name: string | undefined = undefined;

  constructor(private service: AuthService) {}

  @Get("/login")
  getLogin(@Ctx() context: SecurityContext) {
    if (context.security.auth.identity()) {
      return Redirect("/home/protected");
    }

    return `<form method="post">
                login: admin <br>
                password: admin <br>
              <input type="text" name="login" placeholder="login" value="admin"><br>
              <input type="password" name="password" placeholder="password" value="admin"><br>
              <input type="submit">
            </form>`;
  }

  @Post("/login")
  async postLogin(
    @Ctx() context: SecurityContext,
    @Body() account: LoginModel,
  ) {
    const user = this.service.validate(account.login, account.password);

    if (user) {
      await context.security.auth.signInAsync<UserModel>(scheme, user);
      return Redirect("/home/protected");
    }

    return Redirect("/account/login");
  }

  @Get("/logout")
  async logOut(@Ctx() context: SecurityContext) {
    await context.security.auth.signOutAsync(scheme);
    return Redirect("/account/login");
  }
}

// validation user service
export class AuthService {
  validate(login: string, password: string): UserModel | undefined {
    if (login === "admin" && password === "admin") {
      return { id: "1", login: "admin" };
    }
    return undefined;
  }
}

Decorators

@Authorize(scheme, payload) - Hook decorator for guard actions, controllers and areas.

@Authorize(CookiesAuthentication.DefaultScheme)
@Get("/protected")
getProtectedData() {
    return "Hi! this protected info. <br>  <a href='/account/logout'>logout</a>";
  }

Authorize payload can have roles, and policy function to protect the route.

@Authorize(CookieScheme, {roles: ["admin"], policy: (context: SecurityContext) => {
    result = false ;// validate with context
    return result;
}})