2.0.22 • Published 1 month ago

@neohelden/commons-nestjs-server-auth v2.0.22

Weekly downloads
-
License
UNLICENSED
Repository
github
Last release
1 month ago

neohelden-commons-nestjs-server-auth

This module provides common mechanisms for NestJS to perform JWT server authentication. Additionally the use of the Open Policy Agent is supported.

Auth Bundle

The decisions are available to the Application using decorators. An example for OPA enabled decision is:

import {
  Get,
  UseGuards,
} from "@nestjs/common";
import {
  OPAGuard,
  OPAPrincipal,
  OpaJwtPrincipal,
} from "@neohelden/commons-nestjs-server-auth";

interface JWTClaims {
  /**
   * tenant id
   */
  tid: string
}

interface OPAConstraints {
  constraint1: boolean
  constraint2: string[]
}

class Controller {
    @UseGuards(OPAGuard)
    @Get("/")
    public getSomethingSecure(@OPAPrincipal() opaPrincipal: OpaJwtPrincipal<JWTClaims, OPAConstraints>) {
        const constraints = opaPrincipal.constraints;
        return constraints
    }
}

Configuration

The configuration of this module is accomplished using NestJS Dynamic modules. Therefore import the AuthModule in your AppModule and provide the configuration.

Example:

AuthModule.forRootAsync({
  isGlobal: true,
  useFactory: async (configService: ConfigService) => {
    console.log("Using factory");
    return {
      opa: {
        disableOpa: configService.get<string>("opa.disable") === "true",
        baseUrl: configService.get<string>("opa.url"),
        policyPackage: configService.get<string>("opa.package"),
        opaClient: {
          timeout: configService.get<number>("opa.opaClient.timeout"),
        },
      },
      auth: {
        disableAuth: configService.getOrThrow<string>("auth.disableAuth") === "true",
        authIssuers: configService
          .get<string>("auth.issuers")
          ?.trim()
          .split(","),
        authKeys: configService.get("auth.keys"),
      },
    } as AuthModuleOptions;
  },
  inject: [ConfigService],
  imports: [ConfigModule],
}),

OPA Evaluation

Inputs are available to the OPA policy file. An example of this file is:

# each policy lies in a package that is referenced in the configuration of the OpaBundle
package example

# decode the JWT as new variable 'token'
token = {"payload": payload} {
    not input.jwt == null
    io.jwt.decode(input.jwt, [_, payload, _])
}

# deny by default
default allow = false

allow {
    # allow if path match '/contracts/:anyid' 
    input.path = ["contracts", _]

    # allow if request method 'GET' is used
    input.httpMethod == "GET"

    # allow if 'claim' exists in the JWT payload
    token.payload.claim

    # allow if a request header 'HttpRequestHeaderName' has a certain value 
    input.headers["httprequestheadername"][_] == "certain-value"
}

# set some example constraints 
constraint1 := true                # always true
constraint2 := [ "v2.1", "v2.2" ]  # always an array of "v2.1" and "v2.2"
constraint3[token.payload.sub].    # always a set that contains the 'sub' claim from the token
                                   # or is empty if no token is present

The results of this policy are then added to the @OPAPrincipal Decorator available for requests.

2.0.22

1 month ago

2.0.21

1 month ago

2.0.20

1 month ago

2.0.19

2 months ago

2.0.18

2 months ago

2.0.17

2 months ago

2.0.16

2 months ago

2.0.15

3 months ago

2.0.14

3 months ago

2.0.13

3 months ago

2.0.12

4 months ago

2.0.11

5 months ago

2.0.10

5 months ago

2.0.9

6 months ago

2.0.8

6 months ago

2.0.7

6 months ago

2.0.6

6 months ago

2.0.5

6 months ago

2.0.4

6 months ago

2.0.3

7 months ago

2.0.2

7 months ago

2.0.1

8 months ago

2.0.0

8 months ago

1.0.2

8 months ago

1.0.1

8 months ago

1.0.0

8 months ago