Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

example project using opa-typescript with a simple nestjs REST service

Notifications You must be signed in to change notification settings

StyraInc/opa-typescript-example-nestjs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

a243292 · Sep 9, 2024
Jun 19, 2024
Jul 3, 2024
Jul 3, 2024
Mar 13, 2024
Sep 4, 2024
Jun 19, 2024
Mar 13, 2024
Mar 13, 2024
Mar 13, 2024
Jun 19, 2024
Sep 9, 2024
Sep 4, 2024
Mar 14, 2024
Mar 13, 2024
Sep 4, 2024
Sep 4, 2024
Mar 13, 2024
Mar 13, 2024

Repository files navigation

opa-typescript NestJS example

Important

This code has been moved to StyraInc/opa-sdk-demos.

Description

Based on the Nest framework TypeScript starter repository.

Input Payloads from Authz Decorators

Static key/val pairs

Use the Authz decorator to add static information to the request payload sent to OPA:

@Authz(() => ({ resource: 'cat' }))

on either the class or the handler method will add

{ "resource": "cat" }

to each request payload.

There's a AuthzStatic() variant that lets you condense this to

@Authz({ resource: 'cat' })

Feel free to

import { AuthzStatic as Authz } from '../authz/decorators/action';

if the dynamic functionality isn't required.

Forward request body

POST /cats
{"name": "garfield", "age": 5, "breed": "unknown"}

The entire request body can be forwarded:

@Authz(({ body }) => body)
{
  "name": "garfield",
  "age": 5,
  "breed": "unknown"
}

Note that we can also add a static part to this:

@Authz(({ body }) => ({ ...body, action: 'create' }))
{
  "name": "garfield",
  "age": 5,
  "breed": "unknown",
  "action": "create"
}

It's also possible to select just parts of the body:

@Authz(({ body: { name } }) => ({ name, action: 'create' }))
{
  "name": "garfield",
  "action": "create"
}

If you want to put the body into some key on the payload, use

@Authz(({ body }) => ({ payload: body }))
{
  "payload": {
    "name": "garfield",
    "age": 5,
    "breed": "unknown"
  }
}

Route parameters can also be injected:

@Get(':name')
@Authz(({ params }) => ({ ...params, action: 'get' }))
async findByName(@Param('name') name: string): Promise<Cat> {
  return this.catsService.findByName(name);
}
{
  "name": "garfield",
  "action": "get"
}

More Request Details

Under the hood, the @Authz decorator registers functions that (optionally) take a Request parameter. See the NestJS docs for all the fields that you can use.

Pass along the client IP via

@Authz(({ ip }) => ({ ip }))

Or one specific header,

@Authz(({ headers: { 'x-user': u } }) => ({
  ['x-user']: u,
}))

Response payload mapping

Use the @Decision and @DecisionStatic decorators to instruct the AuthzGuard on how to get a boolean decision from the OPA response:

@DecisionStatic('allowed')

will use the allow field of an object response. So if POST /v1/data/cats/result returns

{
  "allowed": true,
  "details": []
}

the AuthzGuard will use the allowed field to make the decision.

The same be achieved using a non-static @Decision decorator:

@Decision((r) => r['allowed'])

Note that you can also pass a function, like

function pluckAllow(r: any): boolean {
  return r['allow'];
}

via

@Decision(pluckAllow)

You can use all of the result for the decision, for example

@Decision((r) => r.violations.length == 0)

Installation

$ npm install

Running the app

# default env variables, corresponding to http://127.0.0.1:8181/v1/data/cats/allow
cp example.env .env

# development
$ npm run start

# watch mode
$ npm run start:dev

# production mode
$ npm run start:prod

Start OPA with the example policies

opa run --server policies

Run some HTTP calls

hurl basic.hurl

(hurl is https://hurl.dev)

About

example project using opa-typescript with a simple nestjs REST service

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published