import * as tokens from './tokens'; import { InvalidRequest, InvalidClient, UnauthorizedClient, UnsupportedGrantType, OAuth2Error, } from '../model/error'; import { data as dataResponse, error as errorResponse, } from '../utils/response'; import wrap from '../utils/wrap'; import { OAuth2TokenResponse } from '../model/model'; export const token = wrap(async (req, res) => { let clientId: string | null = null; let clientSecret: string | null = null; let grantType: string | null = null; const { oauth2 } = req; if (req.body.client_id && req.body.client_secret) { clientId = req.body.client_id as string; clientSecret = req.body.client_secret as string; req.oauth2.logger.debug( 'Client credentials parsed from body parameters', clientId, clientSecret ); } else { if (!req.headers || !req.headers.authorization) { throw new InvalidRequest('No authorization header passed'); } let pieces = req.headers.authorization.split(' ', 2); if (!pieces || pieces.length !== 2) { throw new InvalidRequest('Authorization header is corrupted'); } if (pieces[0] !== 'Basic') { throw new InvalidRequest( `Unsupported authorization method: ${pieces[0]}` ); } pieces = Buffer.from(pieces[1], 'base64').toString('ascii').split(':', 2); if (!pieces || pieces.length !== 2) { throw new InvalidRequest('Authorization header has corrupted data'); } clientId = pieces[0]; clientSecret = pieces[1]; req.oauth2.logger.debug( 'Client credentials parsed from basic auth header:', clientId, clientSecret ); } if (!req.body.grant_type) { throw new InvalidRequest( 'Request body does not contain grant_type parameter' ); } grantType = req.body.grant_type as string; req.oauth2.logger.debug('Parameter grant_type is', grantType); const client = await oauth2.model.client.fetchById(clientId); if (!client) { throw new InvalidClient('Client not found'); } const valid = oauth2.model.client.checkSecret(client, clientSecret); if (!valid) { throw new UnauthorizedClient('Invalid client secret'); } if ( !oauth2.model.client.checkGrantType(client, grantType) && grantType !== 'refresh_token' ) { throw new UnauthorizedClient('Invalid grant type for the client'); } else { req.oauth2.logger.debug('Grant type check passed'); } let tokenResponse: OAuth2TokenResponse; try { switch (grantType) { case 'authorization_code': tokenResponse = await tokens.authorizationCode( oauth2, client, req.body.code, req.body.code_verifier ); break; case 'password': tokenResponse = await tokens.password( oauth2, client, req.body.username, req.body.password, req.body.scope ); break; case 'client_credentials': tokenResponse = await tokens.clientCredentials( oauth2, client, req.body.scope ); break; case 'refresh_token': tokenResponse = await tokens.refreshToken( oauth2, client, req.body.refresh_token ); break; default: throw new UnsupportedGrantType( 'Grant type does not match any supported type' ); } if (tokenResponse) { dataResponse(req, res, tokenResponse); } } catch (e) { errorResponse(req, res, e as OAuth2Error); } });