Open evanjd opened 11 months ago
@evanjd, if you still need it:
yarn add -D jmferreiratech/serverless-offline-local-authorizers-plugin#v1.3.0
For anyone having issues with this plugin since it's not actively maintained you can disable authorizers on local for serverless-offline itself as an alternative for using this plugin:
custom:
stage: ${opt:stage, self:provider.stage}
region: ${opt:region, self:provider.region}
...
serverless-offline:
noAuth: true # <-- this
If you want to just override for the sake of development purposes and want to get a feedback loop locally, don't use this plugin.
I am using serverless@3.33.0
and serverless-offline@14.0.0
what I did is create one typescript file at the root level of the project named: localAuthorizer.ts
and then exported one function like the below, note that I have implemented cognito locally
//localAuthorizer.ts
require('dotenv').config();
const jwt = require('jsonwebtoken');
const axios = require('axios');
const jwkToPem = require('jwk-to-pem');
const region = process.env.AWS_DEFAULT_REGION;
const userPoolId = process.env.COGNITO_USER_POOL_ID;
const appClientId = process.env.COGNITO_APP_CLIENT_ID;
const getPublicKeys = async () => {
const url = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}/.well-known/jwks.json`;
const response = await axios.get(url);
return response.data.keys as {
alg: string;
kty: string;
kid: string;
x5c: string;
}[];
};
const verifyToken = async (token: string) => {
try {
const decodedToken = jwt.decode(token, { complete: true });
const kid = decodedToken.header.kid;
const keys = await getPublicKeys();
const key = keys.find((k) => k.kid === kid);
if (!key) {
throw new Error('Public key not found.');
}
let publicKey;
if (key.x5c && key.x5c.length > 0) {
publicKey = `-----BEGIN CERTIFICATE-----\n${key.x5c[0]}\n-----END CERTIFICATE-----`;
} else {
// Convert JWK to PEM format if x5c is not available
publicKey = jwkToPem(key);
}
const verified = jwt.verify(token, publicKey, {
audience: appClientId,
issuer: `https://cognito-idp.${region}.amazonaws.com/${userPoolId}`,
});
return verified;
} catch (error) {
console.error('Token verification error:', error);
throw new Error('Unauthorized');
}
};
const mylocalAuthProxyFn = async (event, context) => {
const token = event.headers.authorization || event.headers.Authorization;
if (!token) {
throw new Error('Unauthorized');
}
try {
const verified = await verifyToken(token.replace('Bearer ', ''));
return {
principalId: verified.sub,
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: 'Allow',
Resource: '*',
},
],
},
};
} catch (error) {
throw new Error('Unauthorized');
}
};
module.exports = { mylocalAuthProxyFn };
then in my serverless.yml
I did configure like below
# serverless.yml
service: <service-name>
plugins:
- serverless-offline
custom:
serverless-offline:
httpPort: 4000
prefix: 'http'
http:
stage: $default
basePath: http
provider:
name: aws
runtime: nodejs16.x
memorySize: 1024
region: ${env:AWS_DEFAULT_REGION}
httpApi:
authorizers:
serviceAuthorizer:
type: request
identitySource: $request.header.Authorization
issuerUrl: https://cognito-idp.${env:AWS_DEFAULT_REGION}.amazonaws.com/${env:COGNITO_USER_POOL_ID}
audience: ${env:COGNITO_APP_CLIENT_ID}
functions:
lambda1:
handler: functions/lambda1.handler
events:
- httpApi:
path: /endpoint1
method: post
serviceAuthorizer:
handler: localAuthorizer.mylocalAuthProxyFn
and I am running npx serverless offline
only, now this is working for me earlier I was getting an error like below
Error: Serverless Offline only supports retrieving JWT from the headers (undefined)
so I changed the serviceAuthorizer type to request
then I was getting an error below
Error:
Function "serviceAuthorizer" doesn't exist in this Service
so I have added the below lines in the Function scope
serviceAuthorizer:
handler: localAuthorizer.mylocalAuthProxyFn
then it is working for me, I mean it's not the perfect way but the only thing I needed was to get the feedback loop locally so I can test my lambdas faster after the change. I will not commit this code because I think it would mess up with the deployment
I guess, but I want to know if anyone has a work around for this as well.
Thanks
In Serverless 3.32.0, support for the
nodejs12.x
runtime was dropped.This causes this plugin to become inoperable, as the runtime of
nodejs12.x
is hard-coded into the latest npm release of this plugin. I've noticed that the hard-coded runtime was removed in this PR. However, it has not been released to npm.