2022-03-07 19:32:20 +00:00
|
|
|
import * as tokens from './tokens';
|
2022-02-25 16:31:59 +00:00
|
|
|
import {
|
|
|
|
InvalidRequest,
|
|
|
|
InvalidClient,
|
|
|
|
UnauthorizedClient,
|
|
|
|
UnsupportedGrantType,
|
2022-03-07 19:32:20 +00:00
|
|
|
OAuth2Error,
|
|
|
|
} from '../model/error';
|
|
|
|
import {
|
|
|
|
data as dataResponse,
|
|
|
|
error as errorResponse,
|
|
|
|
} from '../utils/response';
|
|
|
|
import wrap from '../utils/wrap';
|
2022-02-25 16:31:59 +00:00
|
|
|
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;
|
2022-03-07 19:32:20 +00:00
|
|
|
req.oauth2.logger.debug(
|
|
|
|
'Client credentials parsed from body parameters',
|
|
|
|
clientId,
|
|
|
|
clientSecret
|
|
|
|
);
|
2022-02-25 16:31:59 +00:00
|
|
|
} 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') {
|
2022-03-07 19:32:20 +00:00
|
|
|
throw new InvalidRequest(
|
|
|
|
`Unsupported authorization method: ${pieces[0]}`
|
|
|
|
);
|
2022-02-25 16:31:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
2022-03-07 19:32:20 +00:00
|
|
|
req.oauth2.logger.debug(
|
|
|
|
'Client credentials parsed from basic auth header:',
|
|
|
|
clientId,
|
|
|
|
clientSecret
|
|
|
|
);
|
2022-02-25 16:31:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!req.body.grant_type) {
|
2022-03-07 19:32:20 +00:00
|
|
|
throw new InvalidRequest(
|
|
|
|
'Request body does not contain grant_type parameter'
|
|
|
|
);
|
2022-02-25 16:31:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
grantType = req.body.grant_type as string;
|
2022-03-07 19:32:20 +00:00
|
|
|
req.oauth2.logger.debug('Parameter grant_type is', grantType);
|
2022-02-25 16:31:59 +00:00
|
|
|
|
|
|
|
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');
|
|
|
|
}
|
|
|
|
|
2022-03-07 19:32:20 +00:00
|
|
|
if (
|
|
|
|
!oauth2.model.client.checkGrantType(client, grantType) &&
|
|
|
|
grantType !== 'refresh_token'
|
|
|
|
) {
|
2022-02-25 16:31:59 +00:00
|
|
|
throw new UnauthorizedClient('Invalid grant type for the client');
|
|
|
|
} else {
|
2022-03-07 19:32:20 +00:00
|
|
|
req.oauth2.logger.debug('Grant type check passed');
|
2022-02-25 16:31:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let tokenResponse: OAuth2TokenResponse;
|
|
|
|
try {
|
|
|
|
switch (grantType) {
|
2022-03-07 19:32:20 +00:00
|
|
|
case 'authorization_code':
|
|
|
|
tokenResponse = await tokens.authorizationCode(
|
|
|
|
oauth2,
|
|
|
|
client,
|
2022-12-03 08:10:11 +00:00
|
|
|
req.body.code,
|
|
|
|
req.body.code_verifier
|
2022-03-07 19:32:20 +00:00
|
|
|
);
|
|
|
|
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'
|
|
|
|
);
|
2022-02-25 16:31:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (tokenResponse) {
|
|
|
|
dataResponse(req, res, tokenResponse);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
errorResponse(req, res, e as OAuth2Error);
|
|
|
|
}
|
2022-03-07 19:32:20 +00:00
|
|
|
});
|