@urbaninfrastructure/api-auth-sdk
> TODO: description
External request ACL validation
Import from /nestjs submodule in nestjs project, and from /express in others.
In frontend/web projects pure functions and interfaces can be imported from root module.
NestJS
Split ACL
import { AuthorizedResource, AuthorizedAction } from '@urbaninfrastructure/api-auth-sdk/nestjs'
@AuthorizedResource('fleet', 'vehicle')
@Controller()
class Controller {
@Get('/edit')
@AuthorizedAction('update')
async editResource() { ... }
@Get('/other/edit')
@AuthorizedAction('other', 'update')
async editOtherResource() { ... }
}
Object ACL
import { Authorized } from '@urbaninfrastructure/api-auth-sdk/nestjs'
@Controller()
class Controller {
@Get('/edit')
@Authorized({ product: 'fleet', resource: 'vehicle', action: 'update' })
async editResource() { ... }
}
Object ACL, combinatorics
Arbitrary combinations using AclCombination
interface can be supplied
in order to validate complex acl definitions
@Authorized({
and: [
{ is: { product: 'fleet', resource: 'vehicle', action: 'update' } },
{ is: { product: 'fleet', resource: 'trip', action: 'any' } },
{
not: [
{ is: toAcl('fleet', 'user', 'create') }
]
}
]
})
See the @Authorized
decorator function docs too.
Get authenticated administrator and their permissions
import {
AclCandidate, Admin, Authorized, Permissions
} from '@urbaninfrastructure/api-auth-sdk/nestjs'
@Controller()
class Controller {
@Get('/path')
@Authorized({ product: 'fleet', resource: 'vehicle', action: 'any' })
async pathHandler(
@Admin() admin: AdministratorEntity,
@Permissions() permissions: AclCandidate[],
) {
console.log(admin)
console.log(permissions)
}
}
AclOwner decorator
If the Owner (system id) isn't in a well-known location in the request (systemId or metaSystemId),
use @AuthorizedOwner()
to help locate it. Can also be used to specify "any" owner.
import {
AuthorizedOwner, AuthorizedAction, AuthorizedResource
} from '@urbaninfrastructure/api-auth-sdk/nestjs'
@AuthorizedResource('vehicle')
@Controller
class Controller {
@Get('/path')
@AuthorizedOwner((req) => req.params.ownerId)
@AuthorizedAction('read')
async readVehicle() { ... }
}
Custom / express/sequelize
Provided middleware
import { reqHasAcl, toAcl, expressAuthorized } from '@urbaninfrastructure/api-auth-sdk/express'
router.use(expressAuthorized)
function hasPermission(req: Request, owner: string, resource: AclResource, action: AclAction): bool {
return reqHasAcl(req, toAcl('fleet', owner, resource, action))
}
function onRequest(req: Request) {
if (!hasPermission(req, req.systemId, 'vehicle', 'read')) {
return null
}
}
Custom
import {
authenticateExternalRequest, authorizeAdministrator, toAcl
} from '@urbaninfrastructure/api-auth-sdk/express'
function onRequest(req: Request) {
const jwtToken = authenticateExternalRequest(req)
const result = authorizeAdministrator(jwtToken.sub, toAcl('fleet', systemId, 'vehicle', 'read'))
const result = authorizeAdministrator(jwtToken.sub, { product: 'fleet', owner: systemId, resource: 'vehicle', action: 'read' })
const result = authorizeAdministrator(jwtToken.sub, { and: [ { is: toAcl(...) }, { is: toAcl(...) } ] })
if (!result.allowed) {
throw new Error('unauthorized', result.missedAcls)
}
}
Internal request usage
import { getRequestToken, ApiJwtAudience } from '@urbaninfrastructure/api-auth-sdk/nestjs'
const token = getRequestToken(ApiJwtAudience.CORE)
doRequest(coreUrl, headers: { Authorization: `Bearer ${token}` })
import { InternalAuth } from '@urbaninfrastructure/api-auth-sdk/nestjs'
@Module({
providers: [
{
provide: APP_GUARD,
useClass: InternalAuth,
},
],
})
export class AppModule {}
import { authenticateInternalRequest } from '@urbaninfrastructure/api-auth-sdk/express'
function onRequest(req: Request) {
const authMetadata = authenticateInternalRequest(req)
console.log(`Requesting: ${authMetadata.requestingClient}`)
console.log(`System id: ${authMetadata.urbanSharingSystemId}`)
}