Skip to content

Commit

Permalink
feat: support dev Okta JWT tokens (#1790)
Browse files Browse the repository at this point in the history
  • Loading branch information
ktwbc committed May 28, 2024
1 parent febd1e7 commit 5139c43
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/events/http/HttpServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ export default class HttpServer {
request.payload = request.payload && request.payload.toString(encoding)
request.rawPayload = request.payload

// incomming request message
// incoming request message
log.notice()

log.notice()
Expand Down
9 changes: 4 additions & 5 deletions src/events/http/createJWTAuthScheme.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { log } from "../../utils/log.js"
const { isArray } = Array
const { now } = Date

export default function createAuthScheme(jwtOptions) {
export default function createJWTAuthScheme(jwtOptions) {
const authorizerName = jwtOptions.name

const identitySourceMatch = /^\$request.header.((?:\w+-?)+\w+)$/.exec(
Expand Down Expand Up @@ -43,7 +43,7 @@ export default function createAuthScheme(jwtOptions) {
return Boom.unauthorized("JWT Token expired")
}

const { aud, iss, scope, client_id: clientId } = claims
const { aud, iss, scope, scp, client_id: clientId } = claims
if (iss !== jwtOptions.issuerUrl) {
log.notice(`JWT Token not from correct issuer url`)

Expand All @@ -68,13 +68,13 @@ export default function createAuthScheme(jwtOptions) {

let scopes = null
if (jwtOptions.scopes && jwtOptions.scopes.length > 0) {
if (!scope) {
if (!scope && !scp) {
log.notice(`JWT Token missing valid scope`)

return Boom.forbidden("JWT Token missing valid scope")
}

scopes = scope.split(" ")
scopes = scp || scope.split(" ")
if (scopes.every((s) => !jwtOptions.scopes.includes(s))) {
log.notice(`JWT Token missing valid scope`)

Expand All @@ -85,7 +85,6 @@ export default function createAuthScheme(jwtOptions) {
log.notice(`JWT Token validated`)

// Set the credentials for the rest of the pipeline
// return resolve(
return h.authenticated({
credentials: {
claims,
Expand Down
4 changes: 2 additions & 2 deletions src/events/http/lambda-events/LambdaProxyIntegrationEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ export default class LambdaProxyIntegrationEvent {
if (token) {
try {
claims = decodeJwt(token)
if (claims.scope) {
scopes = claims.scope.split(" ")
if (claims.scp || claims.scope) {
scopes = claims.scp || claims.scope.split(" ")
// In AWS HTTP Api the scope property is removed from the decoded JWT
// I'm leaving this property because I'm not sure how all of the authorizers
// for AWS REST Api handle JWT.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ export default class LambdaProxyIntegrationEventV2 {
if (token) {
try {
claims = decodeJwt(token)
if (claims.scope) {
scopes = claims.scope.split(" ")
if (claims.scp || claims.scope) {
scopes = claims.scp || claims.scope.split(" ")
// In AWS HTTP Api the scope property is removed from the decoded JWT
// I'm leaving this property because I'm not sure how all of the authorizers
// for AWS REST Api handle JWT.
Expand Down
27 changes: 27 additions & 0 deletions tests/integration/jwt-authorizer/jwt-authorizer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ const baseJWT = {
version: 2,
}

const oktaJWT = {
aud: "api://default",
auth_time: floor(now() / 1000),
cid: "ZjE4ZGVlYzUtMDU1Ni00",
eid: "5d6f052a03414da69c500",
exp: floor(now() / 1000) + 5000,
iat: floor(now() / 1000),
iss: "https://dev-00000000.okta.com/oauth2/default",
jti: "9a2f8ae5-9a8d-4d88-be36-bc0a1e042718",
scp: ["email", "profile", "openid"],
sub: "[email protected]",
ver: 1,
}

const expiredJWT = {
...baseJWT,
exp: floor(now() / 1000) - 2000,
Expand Down Expand Up @@ -149,6 +163,19 @@ describe("jwt authorizer tests", function desc() {
path: "/user2",
status: 200,
},
{
description: "Valid Okta format JWT with scp for scopes",
expected: {
requestContext: {
claims: oktaJWT,
scopes: ["email", "profile", "openid"],
},
status: "authorized",
},
jwt: oktaJWT,
path: "/user3",
status: 200,
},
{
description: "Expired JWT",
expected: {
Expand Down
14 changes: 14 additions & 0 deletions tests/integration/jwt-authorizer/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ provider:
- ZjE4ZGVlYzUtMDU1Ni00ZWM4LThkMDAtYTlkMmIzNWE4NTNj
identitySource: $request.header.Authorization
issuerUrl: https://cognito-idp.us-east-1.amazonaws.com/us-east-1_notreal
oktaJwtAuthorizer:
audience:
- "api://default"
identitySource: $request.header.Authorization
issuerUrl: https://dev-00000000.okta.com/oauth2/default
payload: "1.0"
memorySize: 1024
name: aws
Expand All @@ -39,4 +44,13 @@ functions:
- email
method: get
path: /user2
- httpApi:
authorizer:
name: oktaJwtAuthorizer
scopes:
- openid
- profile
- email
method: get
path: /user3
handler: src/handler.user

0 comments on commit 5139c43

Please sign in to comment.