UNPKG

auth-center

Version:
167 lines (149 loc) 5.55 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = _default; var _util = require("../util"); var _errors = require("./errors"); function _default(config) { async function authorize(ctx) { const { Client, Code } = ctx.orm(); const user = ctx.session.user; const { client_id, response_type, redirect_uri, state } = ctx.query; (0, _errors.assert)(ctx, client_id, _errors.CodeErrors.unrecognized_client_id('client_id is missing')); const client = await Client.findByPk(client_id); (0, _errors.assert)(ctx, client, _errors.CodeErrors.unrecognized_client_id('client not found')); if (redirect_uri) { const isChecked = (0, _util.checkURI)(client.redirect_uri, redirect_uri); (0, _errors.assert)(ctx, isChecked, _errors.CodeErrors.invalid_redirect_uri('redirect_uri is invalid')); } const uri = redirect_uri || client.redirect_uri; if (!response_type) { return ctx.redirect((0, _util.buildURI)(uri, { state, error: 'invalid_request' })); } if (response_type !== 'code') { return ctx.redirect((0, _util.buildURI)(uri, { state, error: 'unsupported_response_type' })); } const code = await Code.create({ user_id: user.id, client_id: client.id, redirect_uri: uri }); ctx.redirect((0, _util.buildURI)(uri, { code: code.id, state: state })); } async function accessToken(ctx) { const { Client, Token, Code } = ctx.orm(); const isForm = ctx.request.is('application/x-www-form-urlencoded'); (0, _errors.assert)(ctx, isForm, _errors.TokenErrors.invalid_request('content-type is invalid')); const { grant_type, client_id, client_secret, state } = ctx.request.body; (0, _errors.assert)(ctx, client_id, _errors.TokenErrors.invalid_request('client_id is missing')); (0, _errors.assert)(ctx, client_secret, _errors.TokenErrors.invalid_request('client_secret is missing')); const client = await Client.findByPk(client_id); (0, _errors.assert)(ctx, client, _errors.TokenErrors.invalid_client('client_id is invalid')); (0, _errors.assert)(ctx, client.secret === client_secret, _errors.TokenErrors.invalid_client('client_secret is invalid')); const obj = { client_id: client.id, ttl: config.accessTokenTTL }; if (grant_type === 'authorization_code') { const { code: code_id, redirect_uri } = ctx.request.body; (0, _errors.assert)(ctx, redirect_uri, _errors.TokenErrors.invalid_request('redirect_uri is missing')); (0, _errors.assert)(ctx, code_id, _errors.TokenErrors.invalid_request('code is missing')); const code = await Code.findByPk(code_id, { where: { client_id: client.id } }); (0, _errors.assert)(ctx, code, _errors.TokenErrors.invalid_grant('code is invalid')); const expiresAt = code.createdAt.getTime() + config.codeTTL * 1000; (0, _errors.assert)(ctx, expiresAt > Date.now(), _errors.TokenErrors.invalid_grant('code has expired')); const isChecked = (0, _util.checkURI)(code.redirect_uri, redirect_uri); (0, _errors.assert)(ctx, isChecked, _errors.TokenErrors.invalid_grant('redirect_uri is invalid')); obj.user_id = code.user_id; await code.destroy(); } else if (grant_type === 'refresh_token') { const { refresh_token } = ctx.request.body; (0, _errors.assert)(ctx, refresh_token, _errors.TokenErrors.invalid_request('refresh_token is missing')); const token = await Token.findOne({ where: { refresh_token, client_id: client.id } }); (0, _errors.assert)(ctx, token, _errors.TokenErrors.invalid_grant('refresh_token is invalid')); const expiresAt = token.createdAt.getTime() + config.refreshTokenTTL * 1000; (0, _errors.assert)(ctx, expiresAt > Date.now(), _errors.TokenErrors.invalid_grant('refresh_token has expired')); // Reuse refresh token obj.user_id = token.user_id; obj.refresh_token = refresh_token; await token.destroy(); } else { (0, _errors.assert)(ctx, false, _errors.TokenErrors.unsupported_grant_type('unsupported grant type')); } const result = await Token.create(obj); ctx.set('Cache-Control', 'no-store'); ctx.set('Pragma', 'no-cache'); ctx.body = { access_token: result.id, refresh_token: result.refresh_token, token_type: 'bearer', expires_in: result.ttl, state: state }; } async function authenticate(ctx, next) { const { Token } = ctx.orm(); let tokenId = ctx.get('authorization'); const matches = tokenId.match(/bearer\s(\S+)/i); if (!matches) { tokenId = ctx.query.access_token; } else { tokenId = matches[1]; } (0, _errors.assert)(ctx, tokenId, _errors.TokenErrors.invalid_token('access_token is missing')); const token = await Token.findByPk(tokenId); (0, _errors.assert)(ctx, token, _errors.TokenErrors.invalid_token('access_token is invalid')); const expiresAt = token.createdAt.getTime() + token.ttl * 1000; (0, _errors.assert)(ctx, expiresAt > Date.now(), _errors.TokenErrors.invalid_token('access_token has expired')); ctx._userId = token.user_id; await next(); } return { authorize, accessToken, authenticate }; } module.exports = exports.default;