99 lines
3.1 KiB
TypeScript
99 lines
3.1 KiB
TypeScript
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;
|
|
console.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];
|
|
console.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;
|
|
console.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 {
|
|
console.debug('Grant type check passed');
|
|
}
|
|
|
|
let tokenResponse: OAuth2TokenResponse;
|
|
try {
|
|
switch (grantType) {
|
|
case 'authorization_code':
|
|
tokenResponse = await tokens.authorizationCode(oauth2, client, req.body.code);
|
|
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);
|
|
}
|
|
})
|