Skip to content

Commit

Permalink
MCR-3834 : API Auth: Create Lambda Authorizer to validate incoming JW…
Browse files Browse the repository at this point in the history
…Ts (#2146)

* Add createAPIToken endpoint and jwtLib service

* initial authorizer

* create lambda authorizer

* revert changes to apollo_gql.ts

* create new health check endpoint with the authorizer attached

* pr fixes: distinguish the health check path used for the authorizer, update authorizer to return deny policies on error

* explictly make userID string or undefined, improve err msg language

---------

Co-authored-by: MacRae Linton <macrael@truss.works>
  • Loading branch information
pearl-truss and macrael authored Jan 2, 2024
1 parent a2e007b commit 63e45ca
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 0 deletions.
14 changes: 14 additions & 0 deletions services/app-api/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,20 @@ functions:
method: get
cors: true

third_party_api_authorizer:
handler: src/handlers/third_party_API_authorizer.main

jwthealth:
handler: src/handlers/health_check.main
events:
- http:
path: jwt_health_check
method: get
cors: true
authorizer:
name: third_party_api_authorizer
identitySource: method.request.header.Authorization

otel:
handler: src/handlers/otel_proxy.main
events:
Expand Down
71 changes: 71 additions & 0 deletions services/app-api/src/handlers/third_party_API_authorizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type {
APIGatewayAuthorizerResult,
APIGatewayTokenAuthorizerEvent,
PolicyDocument,
APIGatewayTokenAuthorizerHandler,
} from 'aws-lambda'
import { newJWTLib } from '../jwt'

// Hard coding this for now, next job is to run this config to this app.
const jwtLib = newJWTLib({
issuer: 'fakeIssuer',
signingKey: 'notrandom',
expirationDurationS: 90 * 24 * 60 * 60, // 90 days
})

export const main: APIGatewayTokenAuthorizerHandler = async (
event
): Promise<APIGatewayAuthorizerResult> => {
const authToken = event.authorizationToken.replace('Bearer ', '')
try {
// authentication step for validating JWT token
const userId = await jwtLib.userIDFromToken(authToken)

if (userId instanceof Error) {
const msg = 'Invalid auth token'
console.error(msg)

return generatePolicy(undefined, event)
}

console.info({
message: 'third_party_API_authorizer succeeded',
operation: 'third_party_API_authorizer',
status: 'SUCCESS',
})

return generatePolicy(userId, event)
} catch (err) {
console.error(
'unexpected exception attempting to validate authorization',
err
)
return generatePolicy(undefined, event)
}
}

const generatePolicy = function (
userId: string | undefined,
event: APIGatewayTokenAuthorizerEvent
): APIGatewayAuthorizerResult {
// If the JWT is verified as valid, send an Allow policy
// this will allow the request to go through
// otherwise a Deny policy is returned which restricts access
const policyDocument: PolicyDocument = {
Version: '2012-10-17', // current version of the policy language
Statement: [
{
Action: 'execute-api:Invoke',
Effect: userId ? 'Allow' : 'Deny',
Resource: event['methodArn'],
},
],
}

const response: APIGatewayAuthorizerResult = {
principalId: userId || '',
policyDocument,
}

return response
}

0 comments on commit 63e45ca

Please sign in to comment.