Skip to content

Commit 53d09aa

Browse files
committed
feat: first commit
0 parents  commit 53d09aa

29 files changed

+6168
-0
lines changed

.gitignore

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
.pnpm-debug.log*
9+
10+
# Diagnostic reports (https://nodejs.org/api/report.html)
11+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12+
13+
# Runtime data
14+
pids
15+
*.pid
16+
*.seed
17+
*.pid.lock
18+
19+
# Directory for instrumented libs generated by jscoverage/JSCover
20+
lib-cov
21+
22+
# Coverage directory used by tools like istanbul
23+
coverage
24+
*.lcov
25+
26+
# nyc test coverage
27+
.nyc_output
28+
29+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30+
.grunt
31+
32+
# Bower dependency directory (https://bower.io/)
33+
bower_components
34+
35+
# node-waf configuration
36+
.lock-wscript
37+
38+
# Compiled binary addons (https://nodejs.org/api/addons.html)
39+
build/Release
40+
41+
# Dependency directories
42+
node_modules/
43+
jspm_packages/
44+
45+
# Snowpack dependency directory (https://snowpack.dev/)
46+
web_modules/
47+
48+
# TypeScript cache
49+
*.tsbuildinfo
50+
51+
# Optional npm cache directory
52+
.npm
53+
54+
# Optional eslint cache
55+
.eslintcache
56+
57+
# Optional stylelint cache
58+
.stylelintcache
59+
60+
# Microbundle cache
61+
.rpt2_cache/
62+
.rts2_cache_cjs/
63+
.rts2_cache_es/
64+
.rts2_cache_umd/
65+
66+
# Optional REPL history
67+
.node_repl_history
68+
69+
# Output of 'npm pack'
70+
*.tgz
71+
72+
# Yarn Integrity file
73+
.yarn-integrity
74+
75+
# dotenv environment variable files
76+
.env
77+
.env.development.local
78+
.env.test.local
79+
.env.production.local
80+
.env.local
81+
82+
# parcel-bundler cache (https://parceljs.org/)
83+
.cache
84+
.parcel-cache
85+
86+
# Next.js build output
87+
.next
88+
out
89+
90+
# Nuxt.js build / generate output
91+
.nuxt
92+
dist
93+
94+
# Gatsby files
95+
.cache/
96+
# Comment in the public line in if your project uses Gatsby and not Next.js
97+
# https://nextjs.org/blog/next-9-1#public-directory-support
98+
# public
99+
100+
# vuepress build output
101+
.vuepress/dist
102+
103+
# vuepress v2.x temp and cache directory
104+
.temp
105+
.cache
106+
107+
# Docusaurus cache and generated files
108+
.docusaurus
109+
110+
# Serverless directories
111+
.serverless/
112+
113+
# FuseBox cache
114+
.fusebox/
115+
116+
# DynamoDB Local files
117+
.dynamodb/
118+
119+
# TernJS port file
120+
.tern-port
121+
122+
# Stores VSCode versions used for testing VSCode extensions
123+
.vscode-test
124+
125+
# yarn v2
126+
.yarn/cache
127+
.yarn/unplugged
128+
.yarn/build-state.yml
129+
.yarn/install-state.gz
130+
.pnp.*

.husky/commit-msg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
npx --no -- commitlint --edit ${1}

.husky/pre-commit

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env sh
2+
. "$(dirname -- "$0")/_/husky.sh"
3+
4+
npx lint-staged

README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# RBAC NextAuth.js firewall
2+
3+
This package is a plugin for [NextAuth](https://next-auth.js.org/) version 5 that adds a
4+
Role-Based Access Control (RBAC) authorization layer to your authentication setup.
5+
The RBAC implementation is inspired by [Symfony](https://symfony.com).
6+
7+
## Installation
8+
9+
To install the `@aulasoftwarelibre/next-auth-firewall` package, run:
10+
11+
```bash yarn2npm
12+
npm install @aulasoftwarelibre/next-auth-firewall
13+
```
14+
15+
## Setup
16+
17+
### Change auth.ts
18+
19+
Replace the content of your auth.ts file with the following code:
20+
21+
```typescript
22+
import NextAuthFirewall from '@aulasoftwarelibre/next-auth-firewall'
23+
import authConfig from '@/lib/auth/auth.config'
24+
25+
export const {
26+
auth,
27+
firewallHandler,
28+
handlers: { GET, POST },
29+
signIn,
30+
signOut,
31+
update,
32+
} = NextAuthFirewall(authConfig)
33+
```
34+
35+
### Change middleware.ts
36+
37+
Update your middleware.ts file with the following code:
38+
39+
```typescript
40+
import NextAuthFirewall from '@aulasoftwarelibre/next-auth-firewall'
41+
import authConfig from '@/lib/auth/auth.config'
42+
43+
export default NextAuthFirewall(authConfig).auth
44+
45+
export const config = {
46+
matcher: [
47+
'/((?!api|_next/static|_next/image|favicon.ico).*)',
48+
],
49+
}
50+
```
51+
52+
### Add Firewall Router
53+
54+
Create a new file src/app/api/auth/firewall/route.ts and add the following code:
55+
56+
```typescript
57+
import { firewallHandler } from '@/lib/auth/auth'
58+
59+
const { POST } = firewallHandler
60+
61+
export { POST }
62+
```
63+
64+
### Update auth.config.ts
65+
66+
Modify your auth.config.ts file to replace the authorize callback with access control rules. Here's an example:
67+
68+
```typescript
69+
import type { NextAuthFirewallConfig } from '@aulasoftwarelibre/next-auth-firewall'
70+
71+
const authConfig = {
72+
accessControl: [
73+
{
74+
path: '^/(signout|settings)',
75+
roles: 'IS_AUTHENTICATED',
76+
},
77+
{
78+
path: '^/',
79+
roles: 'PUBLIC_ACCESS',
80+
},
81+
],
82+
// ...
83+
} as NextAuthFirewallConfig
84+
85+
export default authConfig
86+
```
87+
88+
Make sure to configure the adapter as per your requirements.
89+

next-env.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/// <reference types="next" />
2+
3+
// NOTE: This file should not be edited
4+
// see https://nextjs.org/docs/basic-features/typescript for more information.

package.json

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
{
2+
"name": "@aulasoftwarelibre/next-auth-firewall",
3+
"version": "0.1.0",
4+
"description": "Firewall for NextAuth",
5+
"type": "module",
6+
"repository": "https://github.com/aulasoftwarelibre/next-auth-firewall",
7+
"author": "Sergio Gómez <sergio@uco.es>",
8+
"license": "EUPL-1.2",
9+
"main": "dist/index.js",
10+
"types": "dist/index.d.ts",
11+
"files": [
12+
"/dist"
13+
],
14+
"scripts": {
15+
"prebuild": "rimraf dist/",
16+
"build": "tsc",
17+
"build:watch": "tsc --watch",
18+
"lint": "eslint --fix src/ tests/",
19+
"prepare": "husky install",
20+
"test": "jest --watchAll",
21+
"test:ci": "jest"
22+
},
23+
"dependencies": {
24+
"@auth/core": "experimental",
25+
"next": "^14.0.0",
26+
"next-auth": "^5.0.0-beta.3"
27+
},
28+
"devDependencies": {
29+
"@commitlint/cli": "^18.4.2",
30+
"@commitlint/config-conventional": "^18.4.2",
31+
"@types/jest": "^29.5.8",
32+
"@typescript-eslint/eslint-plugin": "^6.11.0",
33+
"@typescript-eslint/parser": "^6.11.0",
34+
"eslint": "^8.54.0",
35+
"eslint-config-prettier": "^9.0.0",
36+
"eslint-plugin-import": "^2.29.0",
37+
"eslint-plugin-jest": "^27.6.0",
38+
"eslint-plugin-prettier": "^5.0.1",
39+
"eslint-plugin-simple-import-sort": "^10.0.0",
40+
"eslint-plugin-sort": "^2.11.0",
41+
"eslint-plugin-unused-imports": "^3.0.0",
42+
"husky": "^8.0.3",
43+
"jest": "^29.7.0",
44+
"lint-staged": "^15.1.0",
45+
"prettier": "^3.1.0",
46+
"rimraf": "^5.0.5",
47+
"ts-jest": "^29.1.1",
48+
"typescript": "^5.2.2"
49+
},
50+
"eslintConfig": {
51+
"env": {
52+
"node": true,
53+
"jest": true
54+
},
55+
"extends": [
56+
"plugin:@typescript-eslint/recommended",
57+
"plugin:prettier/recommended",
58+
"plugin:jest/recommended"
59+
],
60+
"parser": "@typescript-eslint/parser",
61+
"plugins": [
62+
"@typescript-eslint",
63+
"import",
64+
"simple-import-sort",
65+
"sort",
66+
"unused-imports",
67+
"prettier"
68+
],
69+
"root": true,
70+
"rules": {
71+
"@typescript-eslint/no-shadow": "error",
72+
"@typescript-eslint/no-unused-vars": [
73+
"error",
74+
{
75+
"ignoreRestSiblings": true
76+
}
77+
],
78+
"camelcase": "error",
79+
"default-case-last": "error",
80+
"default-param-last": "error",
81+
"dot-notation": "error",
82+
"eqeqeq": "error",
83+
"import/first": "error",
84+
"import/newline-after-import": "error",
85+
"import/no-duplicates": "error",
86+
"no-shadow": "off",
87+
"simple-import-sort/exports": "error",
88+
"simple-import-sort/imports": "error",
89+
"sort/destructuring-properties": "error",
90+
"sort/object-properties": "error",
91+
"sort/type-properties": "error",
92+
"unused-imports/no-unused-imports": "error",
93+
"prettier/prettier": "error"
94+
}
95+
},
96+
"prettier": {
97+
"semi": false,
98+
"singleQuote": true,
99+
"trailingComma": "all"
100+
},
101+
"lint-staged": {
102+
"*.{js,jsx,ts,tsx}": "eslint --fix"
103+
},
104+
"commitlint": {
105+
"extends": [
106+
"@commitlint/config-conventional"
107+
]
108+
},
109+
"jest": {
110+
"preset": "ts-jest"
111+
}
112+
}

src/auth/access-map.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { NextRequest } from 'next/server'
2+
3+
import RequestMatcherInterface from '../request/request-matcher/request-matcher-interface'
4+
import { AccessControlRole, InternalRole } from '../types'
5+
6+
interface AccessMapEntry {
7+
matcher: RequestMatcherInterface
8+
roles: string[]
9+
}
10+
11+
interface AccessMapPattern {
12+
roles: string[] | InternalRole[] | null
13+
}
14+
15+
export default class AccessMap {
16+
private readonly map: AccessMapEntry[]
17+
18+
constructor() {
19+
this.map = []
20+
}
21+
22+
add(matcher: RequestMatcherInterface, roles: AccessControlRole) {
23+
this.map.push({ matcher, roles: Array.isArray(roles) ? roles : [roles] })
24+
}
25+
26+
pattern(request: Request | NextRequest): AccessMapPattern {
27+
for (const accessMap of this.map) {
28+
if (accessMap.matcher === null || accessMap.matcher.matches(request)) {
29+
const { roles } = accessMap
30+
31+
return { roles }
32+
}
33+
}
34+
35+
return { roles: null }
36+
}
37+
}

0 commit comments

Comments
 (0)