128 lines
3.3 KiB
TypeScript
128 lines
3.3 KiB
TypeScript
import { InvalidRequest, ServerError, InvalidGrant } from '../../model/error';
|
|
import {
|
|
OAuth2,
|
|
OAuth2Client,
|
|
OAuth2Code,
|
|
OAuth2TokenResponse,
|
|
} from '../../model/model';
|
|
|
|
/**
|
|
* Issue an access token by authorization code
|
|
* @param oauth2 - OAuth2 instance
|
|
* @param client - OAuth2 client
|
|
* @param providedCode - Authorization code
|
|
* @returns Access token.
|
|
*/
|
|
export async function authorizationCode(
|
|
oauth2: OAuth2,
|
|
client: OAuth2Client,
|
|
providedCode: string
|
|
): Promise<OAuth2TokenResponse> {
|
|
const respObj: OAuth2TokenResponse = {
|
|
token_type: 'bearer',
|
|
};
|
|
|
|
let code: OAuth2Code | null = null;
|
|
|
|
if (!providedCode) {
|
|
throw new InvalidRequest(
|
|
'code is mandatory for authorization_code grant type'
|
|
);
|
|
}
|
|
|
|
try {
|
|
code = await oauth2.model.code.fetchByCode(providedCode);
|
|
} catch (err) {
|
|
oauth2.logger.error(err);
|
|
throw new ServerError('Failed to call code.fetchByCode function');
|
|
}
|
|
|
|
if (code) {
|
|
if (
|
|
oauth2.model.code.getClientId(code) !== oauth2.model.client.getId(client)
|
|
) {
|
|
throw new InvalidGrant('Code was issued by another client');
|
|
}
|
|
|
|
if (!oauth2.model.code.checkTTL(code)) {
|
|
throw new InvalidGrant('Code has already expired');
|
|
}
|
|
} else {
|
|
throw new InvalidGrant('Code not found');
|
|
}
|
|
|
|
oauth2.logger.debug('Code fetched', code);
|
|
|
|
const scope = oauth2.model.code.getScope(code);
|
|
const cleanScope = oauth2.model.client.transformScope(scope);
|
|
const userId = oauth2.model.code.getUserId(code);
|
|
const clientId = oauth2.model.code.getClientId(code);
|
|
|
|
if (oauth2.model.refreshToken.invalidateOld) {
|
|
try {
|
|
await oauth2.model.refreshToken.removeByUserIdClientId(userId, clientId);
|
|
} catch (err) {
|
|
oauth2.logger.error(err);
|
|
throw new ServerError(
|
|
'Failed to call refreshToken.removeByUserIdClientId function'
|
|
);
|
|
}
|
|
|
|
oauth2.logger.debug('Refresh token removed');
|
|
}
|
|
|
|
if (!oauth2.model.client.checkGrantType(client, 'refresh_token')) {
|
|
oauth2.logger.debug(
|
|
'Client does not allow grant type refresh_token, skip creation'
|
|
);
|
|
} else {
|
|
try {
|
|
respObj.refresh_token = await oauth2.model.refreshToken.create(
|
|
userId,
|
|
clientId,
|
|
scope
|
|
);
|
|
} catch (err) {
|
|
oauth2.logger.error(err);
|
|
throw new ServerError('Failed to call refreshToken.create function');
|
|
}
|
|
}
|
|
|
|
try {
|
|
respObj.access_token = await oauth2.model.accessToken.create(
|
|
userId,
|
|
clientId,
|
|
scope,
|
|
oauth2.model.accessToken.ttl
|
|
);
|
|
} catch (err) {
|
|
oauth2.logger.error(err);
|
|
throw new ServerError('Failed to call accessToken.create function');
|
|
}
|
|
|
|
respObj.expires_in = oauth2.model.accessToken.ttl;
|
|
oauth2.logger.debug('Access token saved:', respObj.access_token);
|
|
|
|
try {
|
|
await oauth2.model.code.removeByCode(providedCode);
|
|
} catch (err) {
|
|
oauth2.logger.error(err);
|
|
throw new ServerError('Failed to call code.removeByCode function');
|
|
}
|
|
|
|
if (cleanScope.includes('openid') && oauth2.model.jwt) {
|
|
const user = await oauth2.model.user.fetchById(
|
|
oauth2.model.code.getUserId(code)
|
|
);
|
|
|
|
try {
|
|
respObj.id_token = await oauth2.model.jwt.issueIdToken(user, cleanScope);
|
|
} catch (err) {
|
|
oauth2.logger.error(err);
|
|
throw new ServerError('Failed to issue an ID token');
|
|
}
|
|
}
|
|
|
|
return respObj;
|
|
}
|