npm package: @quadrel-enterprise-ui/auth
Description: OIDC authentication and role-based authorization for Angular. Wraps `angular-auth-oidc-client` and extends it with a second authentication source: an external session status fed in via `pamsStatus$`. `isAuthenticated$` is only `true` when both OIDC and th
Latest version: 20.1.2

# @quadrel-enterprise-ui/auth

OIDC authentication and role-based authorization for Angular. Wraps `angular-auth-oidc-client` and extends it with a second authentication source: an external session status fed in via `pamsStatus$`. `isAuthenticated$` is only `true` when both OIDC and the external session confirm an active session. Also adds a token interceptor and a role-filter system.

## Setup

```typescript
// environment.ts
export const appSetup: QdAppSetup = {
  production: false,
  serviceEndpoint: 'http://localhost:8080/my-app/'
};

export const authConfig: QdAuthConfigServerSide = {
  configPathSegment: 'ui-api/configuration/auth',
  clientId: 'my-app',
  systemName: 'my-system',
  logLevel: QdLogLevel.Warn,
  silentRenew: true,
  silentRenewUrl: `${window.location.origin}/my-app/assets/auth/silent-renew.html`
};
```

```typescript
// AppModule
@NgModule({
  imports: [QdAuthModule.forRoot(appSetup, authConfig)],
  providers: [provideHttpClient(withInterceptorsFromDi())]
})
```

## Config modes

All `angular-auth-oidc-client` configuration options are accepted and passed through directly. The options below are Quadrel-specific additions on top. See the [angular-auth-oidc-client configuration reference](https://angular-auth-oidc-client.com/docs/documentation/configuration) for the full base config.

**`QdAuthConfigServerSide`** — OIDC config is fetched from the backend at startup via `configPathSegment`. Additional OIDC options (e.g. `clientId`, `silentRenew`) are merged with the server response.

**`QdAuthConfigClientSide`** — Full static OIDC config in the frontend. Requires `applicationUrl` and `pamsEnvironment` instead of `configPathSegment`.

### Common options

| Option | Default | Description |
|---|---|---|
| `tokenAwarePatterns` | — | Token added to matching requests if present |
| `tokenEnforcedPatterns` | — | Request waits for token (up to timeout) |
| `tokenEnforcedTimeout` | `15000` | ms to wait before sending without token |
| `logLevel` | — | `Debug`, `Warn`, `Error`, or `None` |
| `systemName` | — | System name for role filters |
| `useAutoLogin` | — | Redirect to login from anywhere in the app |

## Authorization

### Guard

```typescript
{
  path: 'beer',
  canActivate: [QdAuthorizationGuard],
  data: {
    roleFilter: [
      { system: 'input', resource: 'beer', operation: 'read' }   // AND
      [{ system: 'input', resource: 'beer', operation: 'update' }, // OR within array
       { system: 'input', resource: 'beer', operation: 'delete' }]
    ]
  }
}
```

Unauthorized users are redirected to `/Forbidden`.

### Directive

```html
<button *qdIsAuthorized="{ system: 'input', resource: 'beer', operation: 'delete' }">Delete</button>

<!-- specific partner -->
<div *qdIsAuthorized="{ system: 'input', resource: 'beer', operation: 'read', match: 'one', bpId: '1234567890' }">…</div>
```

| `match` | Description |
|---|---|
| `some` (default) | Any partner or userroles |
| `all` | Userroles only — implies BAZG employee |
| `one` | Specific `bpId` or userroles |
| `one_explicitly` | Specific `bpId` only (not via userroles) |

### Service

```typescript
authorizationService.hasRole({ system: 'input', resource: 'beer', operation: 'read' });
authorizationService.hasRoleForAllPartners({ system: 'input', resource: 'beer', operation: 'read' });
authorizationService.hasRoleForPartner({ system: 'input', resource: 'beer', operation: 'read', bpId: '123' });
authorizationService.getPartnersMatchingRole({ system: 'input', resource: 'beer', operation: 'read' });
```

All methods return `Observable<boolean>` (except `getPartnersMatchingRole` → `Observable<string[]>`).

## Jest setup

This package ships ESM output. Add the included preset to avoid `SyntaxError: Unexpected token 'export'` in Jest:

```js
// jest.config.ts / jest.config.js
module.exports = {
  ...require('@quadrel-enterprise-ui/auth/jest-preset'),
  // ... rest of your config
};
```

If you already use `@quadrel-enterprise-ui/framework/jest-preset`, merge the `transformIgnorePatterns` so both are covered:

```js
module.exports = {
  ...require('@quadrel-enterprise-ui/framework/jest-preset'),
  transformIgnorePatterns: ['node_modules/(?!(@quadrel-enterprise-ui/auth|.*\\.mjs$))'],
  // ... rest of your config
};
```