Not using AWS Lambda? You're probably looking for Civic SIP API.
A library to secure AWS Lambda resources using Civic Authentication.
This library allows you to protect your AWS Lambda endpoints with a custom authorizer. The session token is generated by calling the /login function, passing a single-use login token generated by Civic. This login token contains details about the user logging in, that you can then validate, store or send to the front-end
For information on how to integrate your front-end with civic, see https://docs.civic.com and additionally, https://github.com/civicteam/civic-login-redux for a Redux example.
run npm install @civic/login-lambdas
See /example for an example using the Serverless framework.
node node_modules/civic-login-lambdas/scripts/generateSessionTokenKeyPair.js
The session token signer uses an ECDSA signing algorithm using the secp256r1 ECC curve. Note - the private key must be kept secret. If it is compromised, an attacker could generate a token that would be accepted by your back-end services.
loginHandler.js
const authFactory = require('civic-login-lambdas');
const config = // SEE BELOW;
// add login business logic here - acceptable return values are objects, promises or null.
// UserData contains the details that you request from the user (see /example for a sample loginCallback)
// any return values will be added to the login response to the client
const loginCallback(event, userData) = () => null;
module.exports = authFactory(logger, config.login, loginCallback);
where config is a JS object that looks like:
{
login: {
app: {
appId: The appId you receive when setting up your app on integrate.civic.com,
appSecret: The app secret from integrate.civic.com*
pubKey: Your signing public key from integrate.civic.com
prvKey: Your signing private key from integrate.civic.com*
encPubKey: Your encryption public key from integrate.civic.com
encPrvKey: Your encryption private key from integrate.civic.com*
},
sessionToken: {
issuer: your-app,
audience: your-app-url,
prvKey: the session token private key*
pubKey: the session token public key
resourceArn: [Optional] the ARN pattern of the lambdas that should be authorised using this session token (see below: sessionAuthorizer policy generation)
}
}
}
Note - the session token issuer and audience are not used in the token verification. You can set any values you like here. The subject of the token will be the user ID passed from Civic.
- Warning - the appSecret, prvKey, encPrvKey and sessionToken.prvKey are all sensitive values that could compromise the security of your application if shared. These should not be checked in to source code.
If using the Serverless Framework:
serverless.yml
functions:
# The login endpoint to pass the civic login token to.
# The response contains a session JWT token
login:
handler: handler.login
events:
- http:
path: login
method: POST
# post the session token here to retrieve a renewed one
keepAlive:
handler: handler.keepAlive
events:
- http:
path: session/keepAlive
method: POST
# a custom authorizer that validates the JWT token
sessionAuthorizer:
handler: handler.sessionAuthorizer
# your lambda, secured using civic-login
my-secured-lambda:
handler: handler.helloworld
events:
- http:
path: hello
method: GET
authorizer: sessionAuthorizer
The session token contains by default a unique user ID generated by Civic. To obtain this user ID in the loginCallback, call:
const loginUtil = require('civic-login-lambdas/src/util');
const userId = loginUtils.getUserIdFromUserData(userData);
You can customise the session token contents by returning an object of type LoginData from the loginCallback e.g.
const LoginData = require('civic-login-lambdas/src/loginData');
function loginCallback(event, userData) {
// this will be passed back as the response from the login call
const loginResponse = {
someKey: 'someValue'
}
// this will be added to the session token payload
const sessionTokenContents = {
userId: myGeneratedUserID
}
return new LoginData(loginResponse, sessionTokenContents);
}
The session authorizer validates the session token and generates a policy document that tells API Gateway which lambdas can be accessed by the session token. By default, this is the methodARN on the event, i.e. the ARN of the lambda which is being accessed.
This works fine, except that the policy document is then cached by API Gateway for a particular session token. This means that if you then use the same session token for a second lambda, API Gateway retrieves the cached policy document that allows access only to the first lambda, and denies access.
There are two ways to solve this:
-
Prevent caching of the policy by setting the TTL to 0 (see here) This has an effect on performance.
-
Set the resourceARN to cover all lambdas that you wish to authorise in the sessionToken config 'resourceARN' property.
The property should look something like this:
arn:aws:lambda:#{AWS::Region}:#{AWS::AccountId}:function/${self:service}-${opt:stage, self:provider.stage}-*
You can either set this explicitly in the configuration (substituting all the variables above), or add the above line to serverless.yml as an environment variable (use the serverless-cf-vars plugin to substitute the AWS properties), and refer to that environment variable in your code.
This project is using the airbnb linting rules.
Run the following to lint the project
npm run lint
This project was tested using chai.js and the expect assertion library
Run the following to test the project
npm test