adapt-authoring-auth 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
# Calls the org-level reusable workflow to add PRs to the TODO Board
|
|
2
|
+
|
|
3
|
+
name: Add PR to Project
|
|
2
4
|
|
|
3
5
|
on:
|
|
4
|
-
issues:
|
|
5
|
-
types:
|
|
6
|
-
- opened
|
|
7
6
|
pull_request:
|
|
8
7
|
types:
|
|
9
8
|
- opened
|
|
9
|
+
- reopened
|
|
10
10
|
|
|
11
11
|
jobs:
|
|
12
12
|
add-to-project:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- uses: actions/add-to-project@v0.1.0
|
|
17
|
-
with:
|
|
18
|
-
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
19
|
-
github-token: ${{ secrets.PROJECTS_SECRET }}
|
|
13
|
+
uses: adapt-security/.github/.github/workflows/new.yml@main
|
|
14
|
+
secrets:
|
|
15
|
+
PROJECTS_SECRET: ${{ secrets.PROJECTS_SECRET }}
|
package/adapt-authoring.json
CHANGED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Authentication and permissions
|
|
2
|
+
|
|
3
|
+
The Adapt authoring tool uses a token-based authentication system with role-based access control (RBAC) provided through permissions scopes. This guide covers how authentication works, how to configure authorisation, and how to manage permissions.
|
|
4
|
+
|
|
5
|
+
## Authentication
|
|
6
|
+
|
|
7
|
+
Authentication verifies user identity. The system supports multiple authentication methods through plugins (local username/password, OAuth providers like GitHub or Okta, etc.).
|
|
8
|
+
|
|
9
|
+
### How authentication works
|
|
10
|
+
|
|
11
|
+
1. User submits credentials to an auth plugin endpoint (e.g., `POST /api/auth/local`)
|
|
12
|
+
2. The auth plugin validates the credentials
|
|
13
|
+
3. On success, a JWT ([JSON Web Token](https://www.jwt.io/introduction#what-is-json-web-token)) is generated and returned to the client
|
|
14
|
+
4. The client includes the token in subsequent requests via the `Authorization` header
|
|
15
|
+
5. The server validates the token and checks permissions for each request
|
|
16
|
+
|
|
17
|
+
### Request auth data
|
|
18
|
+
|
|
19
|
+
Authenticated requests have auth data attached to `req.auth`:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
async myHandler (req, res, next) {
|
|
23
|
+
const {
|
|
24
|
+
user, // The authenticated user document
|
|
25
|
+
scopes, // Array of permission scopes
|
|
26
|
+
isSuper, // Whether user has super privileges
|
|
27
|
+
token, // The decoded JWT
|
|
28
|
+
userSchemaName // Schema used for the user
|
|
29
|
+
} = req.auth
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Making authenticated requests
|
|
34
|
+
|
|
35
|
+
Include the JWT in the `Authorization` header:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
Authorization: Bearer <token>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Checking authentication status
|
|
42
|
+
|
|
43
|
+
Retrieve the current user's details and permissions if authenticated (error if not):
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
GET /api/auth/check
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Generating tokens
|
|
50
|
+
|
|
51
|
+
For API integrations etc. tokens can be generated manually with custom lifespans:
|
|
52
|
+
|
|
53
|
+
> Requires the `generatetoken:auth` scope
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
POST /api/auth/generatetoken
|
|
57
|
+
Content-Type: application/json
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
"lifespan": "30d"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Revoking tokens
|
|
65
|
+
|
|
66
|
+
To log out or invalidate sessions and revoke the current user's token:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
POST /api/auth/disavow
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Disabling authentication
|
|
73
|
+
|
|
74
|
+
For development only, authentication can be disabled.
|
|
75
|
+
|
|
76
|
+
> **Warning:** Auth cannot be disabled in production environments. The system enforces this automatically.
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
module.exports = {
|
|
80
|
+
'adapt-authoring-auth': {
|
|
81
|
+
isEnabled: false
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Authentication errors
|
|
87
|
+
|
|
88
|
+
| Error | Description |
|
|
89
|
+
| ----- | ----------- |
|
|
90
|
+
| `UNAUTHENTICATED` | No valid authentication provided |
|
|
91
|
+
| `AUTH_TOKEN_EXPIRED` | Token has expired |
|
|
92
|
+
| `AUTH_TOKEN_INVALID` | Token is malformed or tampered |
|
|
93
|
+
| `ACCOUNT_DISABLED` | User account is disabled |
|
|
94
|
+
| `ACCOUNT_LOCKED_TEMP` | Account temporarily locked (too many failed attempts) |
|
|
95
|
+
| `ACCOUNT_LOCKED_PERM` | Account permanently locked |
|
|
96
|
+
| `INVALID_LOGIN_DETAILS` | Wrong username or password |
|
|
97
|
+
|
|
98
|
+
## Authorisation
|
|
99
|
+
|
|
100
|
+
Authorisation determines what authenticated users are allowed to do. The system uses roles to group permissions together.
|
|
101
|
+
|
|
102
|
+
### Roles
|
|
103
|
+
|
|
104
|
+
Roles are collections of scopes (permissions) assigned to users. The system comes with three default roles:
|
|
105
|
+
|
|
106
|
+
**authuser** — Basic authenticated user:
|
|
107
|
+
- `clear:session`
|
|
108
|
+
- `read:config`
|
|
109
|
+
- `read:lang`
|
|
110
|
+
- `read:me`
|
|
111
|
+
- `write:me`
|
|
112
|
+
- `disavow:auth`
|
|
113
|
+
|
|
114
|
+
**contentcreator** _extends authuser_ — Can create and manage content:
|
|
115
|
+
- `export:adapt`
|
|
116
|
+
- `import:adapt`
|
|
117
|
+
- `preview:adapt`
|
|
118
|
+
- `publish:adapt`
|
|
119
|
+
- `read:assets`
|
|
120
|
+
- `write:assets`
|
|
121
|
+
- `read:content`
|
|
122
|
+
- `write:content`
|
|
123
|
+
- `read:contentplugins`
|
|
124
|
+
- `read:roles`
|
|
125
|
+
- `read:schema`
|
|
126
|
+
- `read:tags`
|
|
127
|
+
- `write:tags`
|
|
128
|
+
- `read:users`
|
|
129
|
+
|
|
130
|
+
**superuser** — Full access to everything:
|
|
131
|
+
- `*:*`
|
|
132
|
+
|
|
133
|
+
### Role inheritance
|
|
134
|
+
|
|
135
|
+
Roles can extend other roles using the `extends` property. The child role inherits all scopes from its parent.
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"shortName": "contentcreator",
|
|
140
|
+
"extends": "authuser",
|
|
141
|
+
"scopes": ["read:content", "write:content"]
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
In this example, `contentcreator` has all scopes from `authuser` plus `read:content` and `write:content`.
|
|
146
|
+
|
|
147
|
+
### Defining custom roles
|
|
148
|
+
|
|
149
|
+
Add roles via configuration in your config file:
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
module.exports = {
|
|
153
|
+
'adapt-authoring-roles': {
|
|
154
|
+
roleDefinitions: [
|
|
155
|
+
{
|
|
156
|
+
shortName: 'reviewer',
|
|
157
|
+
displayName: 'Content Reviewer',
|
|
158
|
+
extends: 'authuser',
|
|
159
|
+
scopes: [
|
|
160
|
+
'read:content',
|
|
161
|
+
'read:assets',
|
|
162
|
+
'preview:adapt'
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Default roles for new users
|
|
171
|
+
|
|
172
|
+
Configure which roles are assigned to new users:
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
module.exports = {
|
|
176
|
+
'adapt-authoring-roles': {
|
|
177
|
+
defaultRoles: ['authuser'],
|
|
178
|
+
defaultRolesForAuthTypes: {
|
|
179
|
+
local: ['contentcreator']
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Authorisation errors
|
|
186
|
+
|
|
187
|
+
| Error | Description |
|
|
188
|
+
| ----- | ----------- |
|
|
189
|
+
| `UNAUTHORISED` | User lacks required permissions |
|
|
190
|
+
|
|
191
|
+
## Permissions
|
|
192
|
+
|
|
193
|
+
Once a user has been authorised and authenticated, the final permissions checks are performed. These are to ensure that the user has access to the specific resources they are requesting.
|
|
194
|
+
Permissions control access to specific actions and resources. They are enforced in two ways:
|
|
195
|
+
- Using scopes on routes
|
|
196
|
+
- Specific manual checks on individual resource items
|
|
197
|
+
|
|
198
|
+
### Scopes
|
|
199
|
+
|
|
200
|
+
Scopes are strings in the format `action:resource` that define what a user can do in a plain human-readable way. You will find the most common actions are `read` and `write`, but there are various cases where a more specific and descriptive action is called for.
|
|
201
|
+
|
|
202
|
+
Some examples are: `read:content`, `delete:assets` and `preview:adapt`.
|
|
203
|
+
|
|
204
|
+
### Securing routes
|
|
205
|
+
|
|
206
|
+
**Using AbstractApiModule:**
|
|
207
|
+
|
|
208
|
+
When extending `AbstractApiModule`, define permissions in your route configuration:
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
async setValues () {
|
|
212
|
+
this.root = 'myresource'
|
|
213
|
+
this.schemaName = 'myresource'
|
|
214
|
+
this.collectionName = 'myresources'
|
|
215
|
+
|
|
216
|
+
this.routes = [
|
|
217
|
+
{
|
|
218
|
+
route: '/',
|
|
219
|
+
handlers: {
|
|
220
|
+
get: this.getHandler.bind(this),
|
|
221
|
+
post: this.postHandler.bind(this)
|
|
222
|
+
},
|
|
223
|
+
permissions: {
|
|
224
|
+
get: ['read:myresource'],
|
|
225
|
+
post: ['write:myresource']
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Using secureRoute directly:**
|
|
233
|
+
|
|
234
|
+
For custom routes outside `AbstractApiModule`:
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
async init () {
|
|
238
|
+
const auth = await this.app.waitForModule('auth')
|
|
239
|
+
|
|
240
|
+
auth.secureRoute('/api/custom/action', 'post', ['custom:action'])
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Unsecuring routes:**
|
|
245
|
+
|
|
246
|
+
Some routes need to be publicly accessible (e.g., login endpoints):
|
|
247
|
+
|
|
248
|
+
> **Warning:** Unsecured routes are accessible without authentication. Use sparingly.
|
|
249
|
+
|
|
250
|
+
```javascript
|
|
251
|
+
async init () {
|
|
252
|
+
const auth = await this.app.waitForModule('auth')
|
|
253
|
+
|
|
254
|
+
auth.unsecureRoute('/api/public/data', 'get')
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Access control hooks
|
|
259
|
+
|
|
260
|
+
Although a user may have access to a resource, there may be occasions when more fine-grained control is necessary to filter out specific resources. In this case, you can use hooks to implement custom access control logic.
|
|
261
|
+
|
|
262
|
+
The `AbstractApiModule#accessCheckHook` is called for each document returned by queries, allowing fine-grained access control:
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
async init () {
|
|
266
|
+
await super.init()
|
|
267
|
+
const content = await this.app.waitForModule('content')
|
|
268
|
+
|
|
269
|
+
// Check if user owns the document
|
|
270
|
+
content.accessCheckHook.tap((req, doc) => {
|
|
271
|
+
if (doc.createdBy.toString() !== req.auth.user._id.toString()) {
|
|
272
|
+
throw this.app.errors.UNAUTHORISED
|
|
273
|
+
}
|
|
274
|
+
})
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Further reading
|
|
279
|
+
|
|
280
|
+
- [Creating auth plugins](creating-auth-plugins.md) — How to implement custom authentication methods
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Creating auth plugins
|
|
2
|
+
|
|
3
|
+
> Preliminary reading: [Authentication and permissions](auth-permissions.md) — Overview of the auth system
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Auth plugins allows for implementations of different authentication methods.
|
|
7
|
+
|
|
8
|
+
## Basic structure
|
|
9
|
+
|
|
10
|
+
Extend `AbstractAuthModule` and implement the required methods:
|
|
11
|
+
|
|
12
|
+
```javascript
|
|
13
|
+
import { AbstractAuthModule } from 'adapt-authoring-auth'
|
|
14
|
+
|
|
15
|
+
class MyAuthModule extends AbstractAuthModule {
|
|
16
|
+
async setValues () {
|
|
17
|
+
this.type = 'myauth' // Unique identifier
|
|
18
|
+
this.userSchema = 'myauthuser' // Optional custom user schema
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async authenticate (user, req, res) {
|
|
22
|
+
// Verify credentials - throw on failure
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Reference
|
|
28
|
+
|
|
29
|
+
### Required values
|
|
30
|
+
|
|
31
|
+
| Property | Description |
|
|
32
|
+
| -------- | ----------- |
|
|
33
|
+
| `this.type` | Unique identifier for the auth type (e.g., `'local'`, `'github'`) |
|
|
34
|
+
|
|
35
|
+
### Optional values
|
|
36
|
+
|
|
37
|
+
| Property | Default | Description |
|
|
38
|
+
| -------- | ------- | ----------- |
|
|
39
|
+
| `this.userSchema` | `'user'` | Schema name for validating users of this auth type - allows custom data to be added to users |
|
|
40
|
+
| `this.routes` | `[]` | Additional routes for the auth plugin |
|
|
41
|
+
|
|
42
|
+
### Inherited methods
|
|
43
|
+
|
|
44
|
+
| Method | Description |
|
|
45
|
+
| ------ | ----------- |
|
|
46
|
+
| `register(data)` | Register a new user with this auth type |
|
|
47
|
+
| `setUserEnabled(user, isEnabled)` | Enable or disable a user account |
|
|
48
|
+
| `disavowUser(query)` | Revoke user tokens |
|
|
49
|
+
| `secureRoute(route, method, scopes)` | Secure a route |
|
|
50
|
+
| `unsecureRoute(route, method)` | Remove auth from a route |
|
|
51
|
+
| `comparePassword(plain, hashed)` | Compare a plain password against a hash |
|
|
52
|
+
|
|
53
|
+
### Hooks
|
|
54
|
+
|
|
55
|
+
| Hook | Description |
|
|
56
|
+
| ---- | ----------- |
|
|
57
|
+
| `registerHook` | Invoked when a new user registers (mutable) |
|
|
58
|
+
|
|
59
|
+
## Worked Example: GitHub OAuth
|
|
60
|
+
|
|
61
|
+
We will work through an example authentication plugin using GitHub OAuth.
|
|
62
|
+
|
|
63
|
+
For OAuth providers (GitHub, Okta, Google, etc.), the flow redirects users to the provider rather than validating credentials directly.
|
|
64
|
+
|
|
65
|
+
### Key steps for OAuth plugins
|
|
66
|
+
|
|
67
|
+
1. Extend `AbstractAuthModule` and set `this.type` to a unique identifier
|
|
68
|
+
2. Add config & user schemas (if necessary)
|
|
69
|
+
3. Use Passport.js with the appropriate strategy for your provider
|
|
70
|
+
4. The OAuth callback should generate a token and store it in the session
|
|
71
|
+
5. Mark OAuth routes as unsecured since users aren't authenticated yet
|
|
72
|
+
6. Handle user registration if the OAuth profile doesn't match an existing user
|
|
73
|
+
7. Add UI code for your plugin, and register it with the UI module (see [this page](ui-extensions))
|
|
74
|
+
|
|
75
|
+
**Below code is for illustrative purposes only, and is not guaranteed to work without modifications**
|
|
76
|
+
|
|
77
|
+
### Creating Auth Module
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
import { AbstractAuthModule, AuthToken } from 'adapt-authoring-auth'
|
|
81
|
+
import passport from 'passport'
|
|
82
|
+
import { Strategy as GitHubStrategy } from 'passport-github2'
|
|
83
|
+
|
|
84
|
+
class GitHubAuthModule extends AbstractAuthModule {
|
|
85
|
+
async setValues () {
|
|
86
|
+
this.type = 'github'
|
|
87
|
+
this.userSchema = 'githubauthuser'
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async init () {
|
|
91
|
+
await super.init()
|
|
92
|
+
const [server, users] = await this.app.waitForModule('server', 'users', 'sessions')
|
|
93
|
+
|
|
94
|
+
this.router.expressRouter.use(passport.initialize())
|
|
95
|
+
this.router.expressRouter.use(passport.session())
|
|
96
|
+
|
|
97
|
+
passport.use(new GitHubStrategy({
|
|
98
|
+
clientID: this.getConfig('clientID'),
|
|
99
|
+
clientSecret: this.getConfig('clientSecret'),
|
|
100
|
+
callbackURL: `//${server.getConfig('host')}:${server.getConfig('port')}${this.router.path}/callback`
|
|
101
|
+
}, async (accessToken, refreshToken, profile, done) => {
|
|
102
|
+
try {
|
|
103
|
+
// Find user by any of their GitHub emails
|
|
104
|
+
let [user] = await users.find({
|
|
105
|
+
$or: profile.emails.map(({ value }) => ({ email: value }))
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
if (!user && this.getConfig('registerUserWithRoles').length) {
|
|
109
|
+
user = await this.registerUser(profile)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return done(null, user || false)
|
|
113
|
+
} catch (e) {
|
|
114
|
+
return done(e)
|
|
115
|
+
}
|
|
116
|
+
}))
|
|
117
|
+
|
|
118
|
+
passport.serializeUser((user, done) => done(null, user))
|
|
119
|
+
passport.deserializeUser((obj, done) => done(null, obj))
|
|
120
|
+
|
|
121
|
+
// OAuth flow: redirect to provider, then handle callback
|
|
122
|
+
this.router.addRoute({
|
|
123
|
+
route: '/',
|
|
124
|
+
handlers: { get: passport.authenticate('github', { scope: ['user:email'] }) }
|
|
125
|
+
}, {
|
|
126
|
+
route: '/callback',
|
|
127
|
+
handlers: { get: passport.authenticate('github', { failureRedirect: '/' }) }
|
|
128
|
+
}, {
|
|
129
|
+
route: '/callback',
|
|
130
|
+
handlers: { get: this.onAuthenticated.bind(this) }
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
this.unsecureRoute('/', 'get')
|
|
134
|
+
this.unsecureRoute('/callback', 'get')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async registerUser (profile) {
|
|
138
|
+
const email = profile.emails[0].value
|
|
139
|
+
const nameParts = profile.displayName.split(' ')
|
|
140
|
+
const roles = await this.app.waitForModule('roles')
|
|
141
|
+
const roleNames = this.getConfig('registerUserWithRoles')
|
|
142
|
+
const matchedRoles = await roles.find({
|
|
143
|
+
$or: roleNames.map(shortName => ({ shortName }))
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
return this.register({
|
|
147
|
+
email,
|
|
148
|
+
firstName: nameParts[0] || profile.displayName,
|
|
149
|
+
lastName: nameParts[1] || '',
|
|
150
|
+
roles: matchedRoles.map(r => r._id.toString())
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async onAuthenticated (req, res, next) {
|
|
155
|
+
try {
|
|
156
|
+
req.session.token = await AuthToken.generate(this.type, req.user)
|
|
157
|
+
res.redirect('/')
|
|
158
|
+
} catch (e) {
|
|
159
|
+
return next(e)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Adding UI login support
|
|
166
|
+
|
|
167
|
+
For OAuth plugins, you may need to override the default login behaviour to redirect to the provider instead of showing a login form.
|
|
168
|
+
|
|
169
|
+
Create a UI plugin:
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
// plugins/myauth/index.js
|
|
173
|
+
define(function (require) {
|
|
174
|
+
const Origin = require('core/origin')
|
|
175
|
+
|
|
176
|
+
Origin.on('router:handleLogin', function () {
|
|
177
|
+
// Redirect to OAuth provider
|
|
178
|
+
window.location = window.origin + '/api/auth/myauth'
|
|
179
|
+
})
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Register the UI plugin in your module's `init` method:
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
async init () {
|
|
187
|
+
await super.init()
|
|
188
|
+
|
|
189
|
+
const ui = await this.app.waitForModule('ui')
|
|
190
|
+
ui.addUiPlugin(path.resolve(this.rootDir, 'plugins'))
|
|
191
|
+
}
|
|
192
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-auth",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Authentication + authorisation module for the Adapt authoring tool",
|
|
5
5
|
"homepage": "https://github.com/adaptlearning/adapt-authoring-auth",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"adapt-authoring-roles": "github:adapt-security/adapt-authoring-roles",
|
|
12
12
|
"adapt-authoring-users": "github:adapt-security/adapt-authoring-users",
|
|
13
13
|
"express-session": "1.18.2",
|
|
14
|
-
"jsonwebtoken": "9.0.
|
|
14
|
+
"jsonwebtoken": "9.0.3",
|
|
15
15
|
"path-to-regexp": "^8.0.0"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name: Add labelled PRs to project
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
types: [ labeled ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
add-to-project:
|
|
9
|
-
if: ${{ github.event.label.name == 'dependencies' }}
|
|
10
|
-
name: Add to main project
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/add-to-project@v0.1.0
|
|
14
|
-
with:
|
|
15
|
-
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
16
|
-
github-token: ${{ secrets.PROJECTS_SECRET }}
|