Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ end_of_line = lf
indent_style = space
indent_size = 2
tab_width = 2
max_line_length = 140
max_line_length = 100
trim_trailing_whitespace = true
7 changes: 0 additions & 7 deletions .eslintignore

This file was deleted.

34 changes: 0 additions & 34 deletions .eslintrc.js

This file was deleted.

8 changes: 4 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:

permissions:
contents: read
packages: write
id-token: write

jobs:
ci:
Expand All @@ -17,6 +17,6 @@ jobs:

publish:
needs: ci
uses: makerxstudio/shared-config/.github/workflows/node-publish-public.yml@main
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
uses: makerxstudio/shared-config/.github/workflows/node-trusted-publish.yml@main
with:
access: public
24 changes: 23 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Dependency directories
Expand All @@ -21,8 +22,18 @@ node_modules/
# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# Editor/OS directories and files
.DS_Store
*.suo

# Jetbrains
.idea
.idea/shelf/
.idea/workspace.xml
# Editor-based HTTP Client requests
.idea/httpRequests/
# Datasource local storage ignored files
.idea/dataSources/
.idea/dataSources.local.xml

# yarn v2
.yarn/cache
Expand All @@ -33,10 +44,21 @@ node_modules/

# Compiled code
dist/
build/

# Coverage report
coverage

# Test results
test-results.xml

# Website & Code docs generation
code-docs/
out/

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
3 changes: 3 additions & 0 deletions .nsprc
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
{
"GHSA-w5hq-g745-h8pq": {
"notes": "The advisory is about missing buffer bounds checks in uuid.v3(), uuid.v5(), and uuid.v6() when you pass your own buf argument. @azure/msal-node uses uuid only for correlation IDs and similar identifiers — i.e. uuid.v4() with no buffer arg. That code path is not affected."
}
}
7 changes: 0 additions & 7 deletions .prettierrc

This file was deleted.

3 changes: 3 additions & 0 deletions .prettierrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
...require('@makerx/prettier-config'),
}
11 changes: 11 additions & 0 deletions .tstoolkitrc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { TsToolkitConfig } from '@makerx/ts-toolkit'

const config: TsToolkitConfig = {
packageConfig: {
srcDir: 'src',
outDir: 'dist',
moduleType: 'commonjs',
Comment thread
cuzzlor marked this conversation as resolved.
main: 'index.ts',
},
}
export default config
26 changes: 26 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "npm",
"script": "check-types",
"problemMatcher": ["$tsc"],
"label": "npm: check-types",
"detail": "tsc -p tsconfig.json"
},
{
"type": "npm",
"script": "lint",
"problemMatcher": ["$eslint-stylish"],
"label": "npm: lint",
"detail": "eslint \"src/**/*.ts\""
},
{
"type": "npm",
"script": "lint:fix",
"problemMatcher": ["$eslint-stylish"],
"label": "npm: lint:fix",
"detail": "eslint \"src/**/*.ts\" --fix"
}
]
}
39 changes: 21 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,29 @@ For Bearer token authentication, see [@makerxstudio/express-bearer](https://gith

## Usage

Requires Node >= 20, and peers `@azure/msal-node` >= 4, `express` >= 4, and `cookie-session` >= 2.

```
npm install @azure/msal-node express cookie-session @makerxstudio/express-msal
npm install @azure/msal-node express cookie-session @makerx/express-msal
```

```ts
import { ConfidentialClientApplication } from '@azure/msal-node'
import { AuthConfig, pkceAuthenticationMiddleware, copySessionJwtToBearerHeader } from '@makerxstudio/express-msal'
import { AuthConfig, pkceAuthenticationMiddleware, copySessionJwtToBearerHeader } from '@makerx/express-msal'
import cookieSession from 'cookie-session'

const app = express()
app.use(cookieSession(cookieSessionOptions))

const msalApp = new ConfidentialClientApplication(msalConfig)
const msalClient = new ConfidentialClientApplication(msalConfig)
const authConfig: AuthConfig = {
app,
msalApp,
msalClient,
scopes: ['profile', 'api://my-api/.default'],
}

// trigger pkce auth on GET requests (iteractive users accessing UIs)
// trigger pkce auth on GET requests (interactive users accessing UIs)
// Note: on Express 5, use a regex or '/*splat' instead of '*'.
app.get('*', pkceAuthenticationMiddleware(authConfig))
// set a Bearer {token} auth header on POST request to '/graphql'
app.post('/graphql', copySessionJwtToBearerHeader)
Expand Down Expand Up @@ -74,7 +77,7 @@ app.use(cookieSession(cookieSessionOptions))
| `app` | The Express JS app on which the auth reply handler is set up (see `authReplyRoute`). |
| `msalClient` | The `@azure/msal-node` `ConfidentialClientApplication` instance. |
| `scopes` | The scopes to use to aquire the accessToken. |
| `authReplyRoute` | The route on which the auth completion handler is be set up, which must be configured in the Azure App Registration, default: `/auth`. |
| `authReplyRoute` | The route on which the auth completion handler is set up, which must be configured in the Azure App Registration, default: `/auth`. |
| `augmentSession` | Optional function to add additional info to the session from the msal `AuthenticationResult`. |
| `logger` | Optional logger implementation to log token validation errors, handler setup info entry etc. |
| `authorizationUrlRequestOverride` | Optional per request override of the authorisation URL request configuration, allows for things like dynamic authority for multi-tenanted apps, etc. |
Expand All @@ -93,29 +96,29 @@ const cookieSessionOptions = {
app.use(cookieSession(cookieSessionOptions))

// set up msal client
const msalApp = new ConfidentialClientApplication({
const msalClient = new ConfidentialClientApplication({
auth: {
clientId: '<client-ID>',
clientSecret: '<client-secret>'
clientSecret: '<client-secret>',
authority: 'https://login.microsoftonline.com/<tenant-ID>',
},
})

// configure all config options
const authConfig: AuthConfig = {
app,
msalApp,
msalClient,
scopes: ['profile', 'api://my-api/.default'],
// specify non-default reply url
replyUrl: '/auth-callback',
// specify non-default reply route
authReplyRoute: '/auth-callback',
// add some additional info to the session from the msal `AuthenticationResult`
augmentSession: (response) => {
return { username: response.account?.username }
},
// specify a logger
logger,
// specify an authority override
authorizationUrlRequestOverride: (req) => ({authority: authorityLookup[req.host]})
authorizationUrlRequestOverride: (req) => ({ authority: authorityLookup[req.host] }),
}

// use pkce auth on everything apart from ./api*
Expand All @@ -127,7 +130,7 @@ app.use('/api*', copySessionJwtToBearerHeader)
// add a logout endpoint for GET requests to /logout
app.get('/logout', logout)

// return the currently logger in user's username from GET requests to /user
// return the currently logged in user's username from GET requests to /user
app.get('/user', (req, res) => {
if (!isAuthenticatedSession(req.session)) return res.status(400).send('Not logged in').end()
res.send(req.session.username).end()
Expand All @@ -154,11 +157,11 @@ The following example uses console logging:

```ts
const logger: Logger = {
error: (message: string, ...params: unknown[]) => console.error
warn: (message: string, ...params: unknown[]) => console.warn
info: (message: string, ...params: unknown[]) => console.info
verbose: (message: string, ...params: unknown[]) => console.trace
debug: (message: string, ...params: unknown[]) => console.debug
error: (message: string, ...params: unknown[]) => console.error(message, ...params),
warn: (message: string, ...params: unknown[]) => console.warn(message, ...params),
info: (message: string, ...params: unknown[]) => console.info(message, ...params),
verbose: (message: string, ...params: unknown[]) => console.trace(message, ...params),
debug: (message: string, ...params: unknown[]) => console.debug(message, ...params),
}

const pkceAuthConfig: AuthConfig = {
Expand Down
37 changes: 37 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import globals from 'globals'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import js from '@eslint/js'
import { FlatCompat } from '@eslint/eslintrc'

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
})

export default [
{
ignores: [
'**/.eslintrc.js',
'**/node_modules',
'**/dist',
'**/build',
'**/coverage',
'**/generated/types.d.ts',
'**/generated/types.ts',
'**/.idea',
'**/.vscode',
],
},
...compat.extends('@makerx/eslint-config'),
{
languageOptions: {
globals: {
...globals.node,
},
},
},
]
14 changes: 0 additions & 14 deletions jest.config.ts

This file was deleted.

Loading