@labdigital/commercetools-mock 2.11.0 → 2.12.0
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.
- package/dist/index.cjs +50 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +50 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/exceptions.ts +7 -0
- package/src/oauth/server.test.ts +34 -0
- package/src/oauth/server.ts +33 -3
- package/src/oauth/store.ts +24 -0
package/package.json
CHANGED
package/src/exceptions.ts
CHANGED
|
@@ -21,3 +21,10 @@ export interface InvalidRequestError {
|
|
|
21
21
|
readonly code: 'invalid_request'
|
|
22
22
|
readonly message: string
|
|
23
23
|
}
|
|
24
|
+
|
|
25
|
+
export interface AuthError {
|
|
26
|
+
readonly statusCode: number
|
|
27
|
+
readonly message: string
|
|
28
|
+
readonly error: string
|
|
29
|
+
readonly error_description: string
|
|
30
|
+
}
|
package/src/oauth/server.test.ts
CHANGED
|
@@ -26,6 +26,40 @@ describe('OAuth2Server', () => {
|
|
|
26
26
|
expect(response.status, JSON.stringify(body)).toBe(200)
|
|
27
27
|
expect(body).toHaveProperty('access_token')
|
|
28
28
|
})
|
|
29
|
+
|
|
30
|
+
it('should failed on invalid refresh token', async () => {
|
|
31
|
+
const response = await supertest(app)
|
|
32
|
+
.post('/token')
|
|
33
|
+
.auth('validClientId', 'validClientSecret')
|
|
34
|
+
.query({ grant_type: 'refresh_token', refresh_token: 'invalid' })
|
|
35
|
+
.send()
|
|
36
|
+
|
|
37
|
+
const body = await response.body
|
|
38
|
+
|
|
39
|
+
expect(response.status, JSON.stringify(body)).toBe(400)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should refresh a token', async () => {
|
|
43
|
+
const createResponse = await supertest(app)
|
|
44
|
+
.post(`/my-project/anonymous/token`)
|
|
45
|
+
.auth('validClientId', 'validClientSecret')
|
|
46
|
+
.query({ grant_type: 'client_credentials' })
|
|
47
|
+
.send()
|
|
48
|
+
|
|
49
|
+
const refreshToken = createResponse.body.refresh_token
|
|
50
|
+
|
|
51
|
+
const response = await supertest(app)
|
|
52
|
+
.post('/token')
|
|
53
|
+
.auth('validClientId', 'validClientSecret')
|
|
54
|
+
.query({ grant_type: 'refresh_token', refresh_token: refreshToken })
|
|
55
|
+
.send()
|
|
56
|
+
|
|
57
|
+
const body = await response.body
|
|
58
|
+
|
|
59
|
+
expect(response.status, JSON.stringify(body)).toBe(200)
|
|
60
|
+
expect(body.access_token).not.toBe(createResponse.body.access_token)
|
|
61
|
+
expect(body.refresh_token).toBeUndefined()
|
|
62
|
+
})
|
|
29
63
|
})
|
|
30
64
|
|
|
31
65
|
describe('POST /:projectKey/anonymous/token', () => {
|
package/src/oauth/server.ts
CHANGED
|
@@ -6,7 +6,11 @@ import express, {
|
|
|
6
6
|
type Response,
|
|
7
7
|
} from 'express'
|
|
8
8
|
import { InvalidTokenError } from '@commercetools/platform-sdk'
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
AuthError,
|
|
11
|
+
CommercetoolsError,
|
|
12
|
+
InvalidRequestError,
|
|
13
|
+
} from '../exceptions.js'
|
|
10
14
|
import { InvalidClientError, UnsupportedGrantType } from './errors.js'
|
|
11
15
|
import { OAuth2Store } from './store.js'
|
|
12
16
|
import { getBearerToken } from './helpers.js'
|
|
@@ -160,11 +164,37 @@ export class OAuth2Server {
|
|
|
160
164
|
)
|
|
161
165
|
return response.status(200).send(token)
|
|
162
166
|
} else if (grantType === 'refresh_token') {
|
|
163
|
-
const
|
|
167
|
+
const refreshToken = request.query.refresh_token?.toString()
|
|
168
|
+
if (!refreshToken) {
|
|
169
|
+
return next(
|
|
170
|
+
new CommercetoolsError<InvalidRequestError>(
|
|
171
|
+
{
|
|
172
|
+
code: 'invalid_request',
|
|
173
|
+
message: 'Missing required parameter: refresh_token.',
|
|
174
|
+
},
|
|
175
|
+
400
|
|
176
|
+
)
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
const token = this.store.refreshToken(
|
|
164
180
|
request.credentials.clientId,
|
|
165
181
|
request.credentials.clientSecret,
|
|
166
|
-
|
|
182
|
+
refreshToken
|
|
167
183
|
)
|
|
184
|
+
if (!token) {
|
|
185
|
+
return next(
|
|
186
|
+
new CommercetoolsError<AuthError>(
|
|
187
|
+
{
|
|
188
|
+
statusCode: 400,
|
|
189
|
+
message: 'The refresh token was not found. It may have expired.',
|
|
190
|
+
error: 'invalid_grant',
|
|
191
|
+
error_description:
|
|
192
|
+
'The refresh token was not found. It may have expired.',
|
|
193
|
+
},
|
|
194
|
+
400
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
}
|
|
168
198
|
return response.status(200).send(token)
|
|
169
199
|
} else {
|
|
170
200
|
return next(
|
package/src/oauth/store.ts
CHANGED
|
@@ -6,6 +6,7 @@ type Token = {
|
|
|
6
6
|
token_type: 'Bearer'
|
|
7
7
|
expires_in: number
|
|
8
8
|
scope: string
|
|
9
|
+
refresh_token?: string
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export class OAuth2Store {
|
|
@@ -22,6 +23,7 @@ export class OAuth2Store {
|
|
|
22
23
|
token_type: 'Bearer',
|
|
23
24
|
expires_in: 172800,
|
|
24
25
|
scope: scope || 'todo',
|
|
26
|
+
refresh_token: `my-project-${randomBytes(16).toString('base64')}`,
|
|
25
27
|
}
|
|
26
28
|
this.tokens.push(token)
|
|
27
29
|
return token
|
|
@@ -38,6 +40,7 @@ export class OAuth2Store {
|
|
|
38
40
|
scope: scope
|
|
39
41
|
? `${scope} anonymous_id:${anonymousId}`
|
|
40
42
|
: `anonymous_id:${anonymousId}`,
|
|
43
|
+
refresh_token: `my-project-${randomBytes(16).toString('base64')}`,
|
|
41
44
|
}
|
|
42
45
|
this.tokens.push(token)
|
|
43
46
|
return token
|
|
@@ -51,11 +54,32 @@ export class OAuth2Store {
|
|
|
51
54
|
scope: scope
|
|
52
55
|
? `${scope} customer_id:${customerId}`
|
|
53
56
|
: `customer_id:${customerId}`,
|
|
57
|
+
refresh_token: `my-project-${randomBytes(16).toString('base64')}`,
|
|
54
58
|
}
|
|
55
59
|
this.tokens.push(token)
|
|
56
60
|
return token
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
refreshToken(clientId: string, clientSecret: string, refreshToken: string) {
|
|
64
|
+
const existing = this.tokens.find((t) => t.refresh_token === refreshToken)
|
|
65
|
+
if (!existing) {
|
|
66
|
+
return undefined
|
|
67
|
+
}
|
|
68
|
+
const token: Token = {
|
|
69
|
+
...existing,
|
|
70
|
+
access_token: randomBytes(16).toString('base64'),
|
|
71
|
+
}
|
|
72
|
+
this.tokens.push(token)
|
|
73
|
+
|
|
74
|
+
// We don't want to return the refresh_token again
|
|
75
|
+
return {
|
|
76
|
+
access_token: token.access_token,
|
|
77
|
+
token_type: token.token_type,
|
|
78
|
+
expires_in: token.expires_in,
|
|
79
|
+
scope: token.scope,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
validateToken(token: string) {
|
|
60
84
|
if (!this.validate) return true
|
|
61
85
|
|