Skip to content

Commit

Permalink
Implements Refresh Token Flow for Meteor 3
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeff Flynt committed Aug 1, 2024
1 parent 411b17d commit 3ba0c44
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 5 deletions.
7 changes: 6 additions & 1 deletion lib/model/meteor-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export const saveAuthorizationCode = async (code, client, user) => {
redirectUri,
scope: code.scope,
client: {
id: client.client_id
id: client.clientId
},
user: {
id: user.id
Expand Down Expand Up @@ -154,3 +154,8 @@ export const saveRefreshToken = async (token, clientId, expires, user) => {
export const getRefreshToken = async (refreshToken) => {
return collections.RefreshTokens.findOneAsync({ refreshToken })
}

export const revokeToken = async (token) => {
const result = await collections.AccessTokens.removeAsync({ refreshToken: token.refreshToken })
return !!result
}

Check failure on line 161 in lib/model/meteor-model.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

Newline required at end of file but not found
11 changes: 10 additions & 1 deletion lib/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
saveAuthorizationCode,
saveRefreshToken,
saveToken,
getAccessToken
getAccessToken,
revokeToken
} from './meteor-model'

/**
Expand Down Expand Up @@ -176,6 +177,14 @@ class OAuthMeteorModel {
async verifyScope (accessToken, scope) {
return accessToken.scope.sort().join(',') === scope.sort().join(',')
}

/**
* revokeToken(refreshToken) is required and should return true
*/
async revokeToken (refreshToken) {
this.log(`revokeToken (refreshToken: ${refreshToken})`)
return revokeToken(refreshToken)
}
}

export { OAuthMeteorModel }
3 changes: 2 additions & 1 deletion lib/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { validateParams } from './validation/validateParams'
import { requiredAuthorizeGetParams } from './validation/requiredAuthorizeGetParams'
import { requiredAuthorizePostParams } from './validation/requiredAuthorizePostParams'
import { requiredAccessTokenPostParams } from './validation/requiredAccessTokenPostParams'
import { requiredRefreshTokenPostParams } from './validation/requiredRefreshTokenPostParams'
import { UserValidation } from './validation/UserValidation'
import { OptionsSchema } from './validation/OptionsSchema'

Expand Down Expand Up @@ -451,7 +452,7 @@ const initRoutes = (self, {
url: accessTokenUrl,
description: 'step 4 - generate access token response',
handler: async function (req, res /*, next */) {
if (!validateParams(req.body, requiredAccessTokenPostParams, self.debug)) {
if (!validateParams(req.body, req.body?.refresh_token ? requiredRefreshTokenPostParams : requiredAccessTokenPostParams, self.debug)) {
return errorHandler(res, {
status: 400,
error: 'invalid_request',
Expand Down
4 changes: 3 additions & 1 deletion lib/utils/isModelInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ const modelNames = [
'saveAuthorizationCode',
'saveRefreshToken',
'saveToken',
'getAccessToken'
'getAccessToken',
'revokeToken'
]

/**
Expand All @@ -28,6 +29,7 @@ const modelNames = [
* - 'saveRefreshToken',
* - 'saveToken',
* - 'getAccessToken'
* - 'revokeToken'
* @param model {Object} the model implementation
* @return {boolean} true if valid, otherwise false
*/
Expand Down
11 changes: 11 additions & 0 deletions lib/validation/requiredRefreshTokenPostParams.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Match } from 'meteor/check'
import { nonEmptyString } from './nonEmptyString'

const isNonEmptyString = Match.Where(nonEmptyString)

export const requiredRefreshTokenPostParams = {
grant_type: isNonEmptyString,
refresh_token: isNonEmptyString,
client_id: Match.Maybe(String),
client_secret: Match.Maybe(String)
}

Check failure on line 11 in lib/validation/requiredRefreshTokenPostParams.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

Newline required at end of file but not found
23 changes: 23 additions & 0 deletions tests/model-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,29 @@ describe('model', function () {
})
})

describe('revokeRefreshToken', () => {
let model

beforeEach(function () {
model = new OAuthMeteorModel()
})

it('returns true if the refresh token was revoked', async () => {
const collection = Mongo.Collection.get(DefaultModelConfig.accessTokensCollectionName)
const refreshToken = Random.id()
await collection.insertAsync({ refreshToken })
const tokenDoc = await model.revokeToken({refreshToken})

Check failure on line 235 in tests/model-tests.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

A space is required after '{'

Check failure on line 235 in tests/model-tests.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

A space is required before '}'
assert.isTrue(tokenDoc)
})

it('returns false if the refresh token was not found', async () => {
const collection = Mongo.Collection.get(DefaultModelConfig.accessTokensCollectionName)

Check failure on line 240 in tests/model-tests.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

'collection' is assigned a value but never used
const refreshToken = Random.id()
const tokenDoc = await model.revokeToken({refreshToken})

Check failure on line 242 in tests/model-tests.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

A space is required after '{'

Check failure on line 242 in tests/model-tests.js

View workflow job for this annotation

GitHub Actions / StandardJS lint

A space is required before '}'
assert.isFalse(tokenDoc)
})
})

describe('saveAuthorizationCode', function () {
it('is not yet implemented')
})
Expand Down
3 changes: 2 additions & 1 deletion tests/oauth-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ describe('constructor', function () {
revokeAuthorizationCode: async () => true,
saveAuthorizationCode: async () => true,
saveRefreshToken: async () => true,
saveToken: async () => true
saveToken: async () => true,
revokeToken: async () => true
}
const server = new OAuth2Server({ model })
assert.isDefined(server)
Expand Down

0 comments on commit 3ba0c44

Please sign in to comment.