OIDC implementation workflow - AWS HealthImaging

OIDC implementation workflow

Diagram showing the OIDC Lambda workflow in HealthImaging.

The authentication flow consists of the following steps:

  1. HTTP Request with Bearer token to DICOMweb endpoint

  2. AWS HealthImaging checks token expiry

  3. Forward request to Lambda authorizer

  4. Lambda validates token with Identity Provider (IdP)

  5. Lambda returns IAM role

  6. Policy evaluation and user authentication complete

Prerequisites

1. Lambda Authorizer Setup

  • Create authorizer that accepts AuthInput and returns AuthResult

  • Validates BearerToken (signature, expiry, scopes, issuer, and business rules)

  • Returns IAM Role ARN with required DICOMweb operation permissions

  • Must respond in ≤ 1 second (configure provisioned concurrency)

Implement token extraction:

// in Node.js export const handler = async (event) => { try { const token = event.bearerToken; const operation = event.operation; } }

2. Datastore Configuration

  • Enable feature by providing lambdaAuthorizerArn at creation

Note

Your AWS account is billed for Lambda invocations and duration. For more information, see AWS Lambda pricing.

Authorization Process Details

Token Validation Rules

HealthImaging evaluates the following token claims:

  • exp – Must be after the current time in UTC

  • nbf – Must be before the current time in UTC

  • iat – Must be before current time in UTC and NOT earlier than 12 hours before (maximum token lifetime)

Event and Response Schemas

AHI invokes your function with the following input and expects the following output.

Authorizer input

{ "datastoreId": "{datastore id}", "operation": "{Healthimaging API name e.g. GetDICOMInstance}", "bearerToken": "{access token}" }
Authorizer output

{ "isTokenValid": {true or false}, "roleArn": "{role arn or empty string meaning to deny the request explicitly}" }

Request Processing

Initial Request Handling:

  • If no Authorization: Bearer header → request proceeds to SigV4 auth

  • If Bearer token present:

    • Resolves datastore's LambdaAuthorizerArn

    • Invokes authorizer using Forward Access Sessions (FAS)

Lambda Authorization Process:

  • Receives AuthInput with datastoreId, operation, and bearerToken

  • Must complete validation within 1 second

  • Returns AuthResult with validation status and role ARN

Implementation Flow

Client-Side Authentication Flow

  1. User Authentication: Direct user to IdP's authorization endpoint

  2. Token Acquisition: Exchange authorization code for ID and Access tokens (JWT)

  3. API Call: Include access token in HTTP Authorization Bearer header

  4. Token Validation: Full validation process by HealthImaging and Lambda authorizer

Setup Steps

Lambda Authorizer Implementation

  • Implement AuthInput/AuthResult interface

  • Validate token (signature, expiration, issuer, audience, scopes)

  • Return decision and IAM Role ARN

IAM Configuration

  • Create policy with minimum DICOMweb operation permissions

  • Create role with trust policy for medical-imaging.region.amazonaws.com

  • Configure Lambda execution permissions

  • Add resource policy with AllowHealthLakeInvocation statement for datastore ARN

The authorizer should have the following resource policy statement:

{ "Sid": "health-imaging", "Effect": "Allow", "Principal": { "Service": "medical-imaging.region.amazonaws.com" }, "Action": "lambda:InvokeFunction", "Resource": "arn:aws:lambda:region:123456789012:function:LambdaAuthorizerName" }

For the IAM role the auth lambda returned, it must have the following trust relationship policy:

{ "Effect": "Allow", "Principal": { "Service": "medical-imaging.region.amazonaws.com" }, "Action": "sts:AssumeRole" }

Concurrency Configuration

  • Set up provisioned concurrency for ≤ 1 second SLO

  • Implement cold-start mitigations if needed

Lambda Authorizer Template

import jwt from 'jsonwebtoken'; import jwksClient from 'jwks-rsa'; const CACHE_TTL = 10 * 60 * 1000; const client = jwksClient({ jwksUri: '{Jwks Url}', cache: true, cacheMaxEntries: 5, cacheMaxAge: 600000, rateLimit: true, jwksRequestsPerMinute: 10 }); export const handler = async (event) => { try { console.log(event); const token = event.bearerToken; const decoded = jwt.decode(token, { complete: true }); if (!decoded || !decoded.header.kid) { console.log('Invalid token structure'); return generatePolicy(null, false); } const key = await client.getSigningKey(decoded.header.kid); const signingKey = key.getPublicKey(); const payload = jwt.verify(token, signingKey, { issuer: '{issuer to be verified}', algorithms: ['RS256'], // Additional verification parameters as needed }); return generatePolicy(payload.sub, true); } catch (error) { console.error('Authorization error:', error); return generatePolicy(null, false); } }; function generatePolicy(user, isValid) { return { isTokenValid: isValid, roleArn: user ? `arn:aws:iam::123456789012:role/${user}` : "" }; }

Final Validation by HealthImaging

After receiving AuthResult, HealthImaging:

  1. Verifies all token claims (nbf, exp, iat)

  2. Validates Role ARN format

  3. Assumes the role

  4. Signs the original request with SigV4 on user's behalf

  5. Processes the DICOMweb request

Exceptions

Condition AHI response
Lambda Authorizer does not exist or is invalid 424 Authorizer Misconfiguration
Authorizer terminated due to execution failure 424 Authorizer Failed
Any other unmapped authorizer error 424 Authorizer Failed
Authorizer returned invalid/ill-formed response 424 Authorizer Misconfiguration
Authorizer ran more than 1s 408 Authorizer Timeout
Token is expired or otherwise invalid 403 Invalid or Expired Token
AHI can't federate the returned IAM Role due to authorizer misconfiguration 424 Authorizer Misconfiguration
Authorizer returned an empty Role 403 Access Denied
Returned Role is not callable (assume-role/trust misconfig) 424 Authorizer Misconfiguration
Request rate exceeds DICOMweb Gateway limits 429 Too many requests
Datastore, Return Role, or Authorizer Cross Account/Cross Region 424 Authorizer Cross Account/Cross Region Access