Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Async support for OAuth2 Server 5.x #15

Merged
merged 5 commits into from
Mar 14, 2024
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
6 changes: 1 addition & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
# folders
node_modules/
packages/

# ide specific
.idea
.vscode


# config files
productionSettings.json
Expand Down Expand Up @@ -135,4 +132,3 @@ SemikolonPlus*
# meteor package specific
.meteor/local
.meteor/meteorite
.npm
78 changes: 39 additions & 39 deletions .versions
Original file line number Diff line number Diff line change
@@ -1,70 +1,70 @@
[email protected].3
accounts-password@2.3.1
[email protected].10
accounts-password@2.4.0
[email protected]
babel-compiler@7.9.0
babel-compiler@7.10.5
[email protected]
[email protected]
[email protected]
[email protected].1
[email protected].2
[email protected]
callback-hook@1.4.0
[email protected].1
callback-hook@1.5.1
[email protected].2
[email protected]
dburles:[email protected]
[email protected].0
ddp-client@2.5.0
[email protected].1
ddp-client@2.6.1
[email protected]
ddp-rate-limiter@1.1.0
ddp-server@2.5.0
[email protected].1
[email protected].2
[email protected].2
[email protected].0
ddp-rate-limiter@1.2.1
ddp-server@2.7.0
[email protected].2
[email protected].3
[email protected].8
[email protected].1
[email protected]
[email protected]
[email protected].2
[email protected].1
[email protected].1
[email protected].10
[email protected].3
[email protected].5
[email protected].4
[email protected].11
[email protected]
[email protected]
[email protected]
jkuester:[email protected]
leaonline:oauth2-server@4.2.1
leaonline:oauth2-server@5.0.0
lmieulet:[email protected]
lmieulet:[email protected]
lmieulet:[email protected]
local-test:leaonline:oauth2-server@4.2.1
local-test:leaonline:oauth2-server@5.0.0
[email protected]
[email protected].1
meteor@1.10.0
[email protected].3
meteor@1.11.5
meteortesting:[email protected]
meteortesting:[email protected]
meteortesting:[email protected]
minimongo@1.8.0
[email protected].8
modules@0.18.0
[email protected].0
mongo@1.15.0
minimongo@1.9.3
[email protected].10
modules@0.20.0
[email protected].1
mongo@1.16.8
[email protected]
[email protected]
[email protected]
npm-mongo@4.3.1
npm-mongo@4.17.2
[email protected]
practicalmeteor:[email protected]_3
[email protected].0
[email protected].0
rate-limit@1.0.9
[email protected].3
[email protected].11
[email protected].2
[email protected].1
rate-limit@1.1.1
[email protected].8
[email protected].12
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected].1
[email protected].0
[email protected].8
[email protected].1
163 changes: 82 additions & 81 deletions lib/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ export class OAuth2Server {
*/
constructor ({ serverOptions = {}, model, routes, debug } = {}) {
check(serverOptions, OptionsSchema.serverOptions)

if (debug) {
console.debug('[OAuth2Server]: create new instance')
console.debug('[OAuth2Server]: serveroptions', serverOptions)
}
this.instanceId = Random.id()
this.config = {
serverOptions: Object.assign({}, OAuth2ServerDefaults.serverOptions, serverOptions),
Expand Down Expand Up @@ -120,9 +123,8 @@ export class OAuth2Server {
* @param secret
* @returns {}
*/
registerClient ({ title, homepage, description, privacyLink, redirectUris, grants, clientId, secret }) {
const self = this
return Promise.await(self.model.createClient({
async registerClient ({ title, homepage, description, privacyLink, redirectUris, grants, clientId, secret }) {
return this.model.createClient({
title,
homepage,
description,
Expand All @@ -131,45 +133,44 @@ export class OAuth2Server {
grants,
clientId,
secret
}))
})
}

authorizeHandler (options) {
const self = this
return function (req, res, next) {
return async function (req, res, next) {
const request = new Request(req)
const response = new Response(res)
return self.oauth.authorize(request, response, options)
.then(function (code) {
res.locals.oauth = { code: code }
next()
})
.catch(function (err) {
// handle error condition
res.writeHead(500)
res.end(err)
})

try {
const code = await self.oauth.authorize(request, response, options)
res.locals.oauth = { code: code }
next()
} catch (err) {
res.writeHead(500)
res.end(err)
}
}
}

authenticateHandler (options) {
const self = this
return function (req, res, next) {
return async function (req, res, next) {
const request = new Request(req)
const response = new Response(res)
return self.oauth.authenticate(request, response, options)
.then(function (token) {
req.data = Object.assign({}, req.data, token)
next()
})
.catch(function (err) {
return errorHandler(res, {
status: err.status,
error: err.name,
description: err.message,
debug: self.debug
})

try {
const token = await self.oauth.authenticate(request, response, options)
req.data = Object.assign({}, req.data, token)
next()
} catch (err) {
return errorHandler(res, {
status: err.status,
error: err.name,
description: err.message,
debug: self.debug
})
}
}
}

Expand Down Expand Up @@ -214,10 +215,11 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
return true
}

const getValidatedClient = (req, res) => {
const getValidatedClient = async (req, res) => {
const clientId = req.method.toLowerCase() === 'get' ? req.query.client_id : req.body.client_id
const secret = req.method.toLowerCase() === 'get' ? req.query.client_secret : req.body.client_secret
const client = Promise.await(self.model.getClient(clientId, secret))
const client = await self.model.getClient(clientId, secret)

if (!client) {
// unauthorized_client - The client is not authorized to request an authorization code using this method.
return errorHandler(res, {
Expand All @@ -228,6 +230,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
debug: self.debug
})
}

return client
}

Expand Down Expand Up @@ -279,7 +282,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
// If there is something wrong with the syntax of the request, such as the redirect_uri or client_id is invalid,
// then it’s important not to redirect the user and instead you should show the error message directly.
// This is to avoid letting your authorization server be used as an open redirector.
route('get', authorizeUrl, function (req, res, next) {
route('get', authorizeUrl, async function (req, res, next) {
if (!validateParams(req.query, requiredAuthorizeGetParams, self.debug)) {
return errorHandler(res, {
status: 400,
Expand All @@ -293,7 +296,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
const validResponseType = validateResponseType(req, res)
if (!validResponseType) return

const client = getValidatedClient(req, res)
const client = await getValidatedClient(req, res)
if (!client) return

const redirectUri = getValidatedRedirectUri(req, res, client)
Expand All @@ -305,7 +308,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
// STEP 2: ADD USER TO THE REQUEST
// validate all inputs again, since all inputs
// could have been manipulated within form
route('post', authorizeUrl, function (req, res, next) {
route('post', authorizeUrl, async function (req, res, next) {
if (!validateParams(req.body, requiredAuthorizePostParams, self.debug)) {
return errorHandler(res, {
error: 'invalid_request',
Expand All @@ -316,7 +319,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
})
}

const client = getValidatedClient(req, res)
const client = await getValidatedClient(req, res)
if (!client) return

const validRedirectUri = getValidatedRedirectUri(req, res, client)
Expand Down Expand Up @@ -366,7 +369,7 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
// - on allow, assign the client_id to the user's authorized clients
// - on deny, ...?
// - construct the redirect query and redirect to the redirect_uri
route('post', authorizeUrl, function (req, res /*, next */) {
route('post', authorizeUrl, async function (req, res /*, next */) {
const request = new Request(req)
const response = new Response(res)
const authorizeOptions = {
Expand All @@ -377,37 +380,36 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
}
}

return self.oauth.authorize(request, response, authorizeOptions)
.then(bind(function (code) {
const query = new URLSearchParams({
code: code.authorizationCode,
user: req.user.id,
state: req.body.state
})

const finalRedirectUri = `${req.body.redirect_uri}?${query}`
try {
const code = await self.oauth.authorize(request, response, authorizeOptions)
const query = new URLSearchParams({
code: code.authorizationCode,
user: req.user.id,
state: req.body.state
})

res.statusCode = 302
res.setHeader('Location', finalRedirectUri)
res.end()
}))
.catch(function (err) {
errorHandler(res, {
originalError: err,
error: err.name,
description: err.message,
status: err.statusCode,
state: req.body.state,
debug: self.debug
})
const finalRedirectUri = `${req.body.redirect_uri}?${query}`

res.statusCode = 302
res.setHeader('Location', finalRedirectUri)
res.end()
} catch (err) {
errorHandler(res, {
originalError: err,
error: err.name,
description: err.message,
status: err.statusCode,
state: req.body.state,
debug: self.debug
})
}
})

// STEP 4: GENERATE ACCESS TOKEN RESPONSE
// - validate params
// - validate authorization code
// - issue accessToken and refreshToken
route('post', accessTokenUrl, function (req, res, next) {
route('post', accessTokenUrl, async function (req, res, /* next */) {
if (!validateParams(req.body, requiredAccessTokenPostParams, self.debug)) {
return errorHandler(res, {
status: 400,
Expand All @@ -421,30 +423,29 @@ const initRoutes = (self, { accessTokenUrl = '/oauth/token', authorizeUrl = '/oa
const request = new Request(req)
const response = new Response(res)

return self.oauth.token(request, response)
.then(function (token) {
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'no-store',
Pragma: 'no-cache'
})
const body = JSON.stringify({
access_token: token.accessToken,
token_type: 'bearer',
expires_in: token.accessTokenExpiresAt,
refresh_token: token.refreshToken
})
res.end(body)
try {
const token = await self.oauth.token(request, response)
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'no-store',
Pragma: 'no-cache'
})
.catch(function (err) {
return errorHandler(res, {
error: 'unauthorized_client',
description: err.message,
state: req.body.state,
debug: self.debug,
status: err.statusCode
})
const body = JSON.stringify({
access_token: token.accessToken,
token_type: 'bearer',
expires_in: token.accessTokenExpiresAt,
refresh_token: token.refreshToken
})
res.end(body)
} catch (err) {
return errorHandler(res, {
error: 'unauthorized_client',
description: err.message,
state: req.body.state,
debug: self.debug,
status: err.statusCode
})
}
})

route('use', fallbackUrl, function (req, res, next) {
Expand Down
Loading
Loading