Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# VisualDx API Configuration
# Copy this file to .env.local and fill in your actual values
# These keys will be generated for this project with the new 'sandbox' permission

# OAuth2 Client Credentials
CLIENT_ID=your_client_id_here
CLIENT_SECRET=your_client_secret_here

# API URLs (optional, defaults are set in config.ts)
API_BASE_URL=https://api-dev.visualdx.com/v1
TOKEN_URL=https://api-dev.visualdx.com/v1/auth/token

# Audience setting: "consumer" or "clinical" (optional, default: consumer)
AUDIENCE=consumer

# Cache settings (time-to-live in seconds, optional, default: 259200)
CACHE_TTL=259200
3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Dependencies
/node_modules
/.pnp
.pnp.js

# Testing
/coverage

# Next.js
/.next/
/out/

# Production
/build

# Misc
.DS_Store
*.tsbuildinfo
next-env.d.ts

# Environment files
.env*.local

# Vercel
.vercel

# Typescript
*.tsbuildinfo
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"github.copilot-chat"
]
}
120 changes: 120 additions & 0 deletions AUTHENTICATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# OAuth2 Authentication Implementation

## Overview
The application now uses OAuth2 client credentials flow for authentication with the VisualDx API, replacing the previous API key authentication.

## Architecture

### Configuration (`src/lib/config.ts`)
Centralized configuration file that manages:
- API Base URL
- Token URL
- Audience (consumer/clinical)
- Cache TTL settings

### Token Management (`src/app/api/analyze/route.ts`)
Implements automatic token lifecycle management:

#### Token State
- `apiToken`: Stores the current access token
- `tokenExpiration`: Tracks when the token expires

#### Key Functions

**`fetchToken()`**
- Requests a new access token from the OAuth2 endpoint
- Uses Basic Auth with CLIENT_ID and CLIENT_SECRET
- Stores the token and calculates expiration time
- Handles errors gracefully with detailed logging

**`ensureToken()`**
- Middleware function that checks token validity
- Automatically refreshes expired tokens
- Called before each API request

**`analyzeImage()`**
- Updated to use the token-based authentication
- Calls `ensureToken()` before making requests
- Uses the `config.API_BASE_URL` for the image analysis endpoint
- Handles 401 errors by clearing the token for retry

## Environment Variables

Required in `.env.local`:
```env
CLIENT_ID=your_client_id_here
CLIENT_SECRET=your_client_secret_here
```

Optional (have defaults):
```env
API_BASE_URL=https://api-dev.visualdx.com/v1
TOKEN_URL=https://api-dev.visualdx.com/v1/auth/token
AUDIENCE=consumer
CACHE_TTL=259200
```

## Authentication Flow

1. Client uploads image via the web form
2. Request arrives at `/api/analyze` endpoint
3. `ensureToken()` checks if token is valid
4. If token is missing or expired:
- Calls `fetchToken()`
- Requests new token with client credentials
- Stores token and expiration
5. Image analysis request is made with Bearer token
6. Response is processed and returned to client

## Benefits

- **Automatic token refresh**: No manual token management needed
- **Secure**: Client credentials never exposed to frontend
- **Efficient**: Tokens are reused until expiration
- **Resilient**: Handles token expiration and auth failures gracefully
- **Configurable**: Easy to switch between dev/prod environments

## Error Handling

The implementation handles various error scenarios:

- **Missing credentials**: Returns clear error message
- **Token fetch failure**: Logs error and throws exception
- **Authentication failure (401)**: Clears token and allows retry
- **Permission errors (403)**: Returns user-friendly message
- **API failures**: Generic error handling with logging

## Security Considerations

- Client credentials stored in environment variables (`.env.local`)
- `.env.local` excluded from git via `.gitignore`
- Token stored in memory only (not persisted)
- Basic Auth header properly encoded
- HTTPS required for all API communications

## Migration Notes

**Old Authentication (API Key)**
```typescript
headers: {
'Authorization': `Bearer ${apiKey}`
}
```

**New Authentication (OAuth2)**
```typescript
await ensureToken(); // Ensures valid token
headers: {
'Authorization': `Bearer ${apiToken}`
}
```

## Testing

To test the authentication:

1. Set up `.env.local` with valid CLIENT_ID and CLIENT_SECRET
2. Start the development server: `npm run dev`
3. Upload an image through the UI
4. Check server logs for "Fetching new API token..." and "Token obtained successfully"
5. Subsequent requests should reuse the token until expiration
51 changes: 51 additions & 0 deletions PROJECT_SPEC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Image Analysis
## Description

A simple app to analyze a user-supplied image for lesion confidences and return a list of recommended cosmetic products.

# Image Upload form
## Description
create a page to demonstrate the API's ability to analyze an image

## ECOA
- create a new next js demo app as a peer of the image proxy repo in our public github

- create an index/home page at the root of the new app’s directory (e.g. /lesionAnalysis/)

- the home page should have a “VisualDx API - Lesion Analysis Example” as an <h1> and the page’s title

- beneath the title should be a paragraph: “Analyze a picture of your skin to find cosmetic product recommendations.”

- beneath that paragraph should be an <a> tag: “Click here to see the code”, which will be a link to the github repo

- beneath that <a> tag should be a file input form that accepts images, just like the UX for DermExpert on the web

- submitting the form sends the image to be analyzed by the api

- handle auth automatically for the image analysis endpoint on the back-end

- keys for authentication will be stored privately, and not committed to the repo

+ Note: keys will be generated for this project that us the new ‘sandbox’ permission

- unlike other demo endpoints, there is no point in caching JSON results - we expect each POST will return a unique answer and we’re not monitoring the input

- handle all expected error states from image analysis endpoint and display appropriate messages (e.g. “This account lacks permission to analyze images“, “Only .png and .jpg Images smaller than 10MB are supported“, etc.)

- show a progress spinner while the image analysis is being processed async

- when the result is returned:

+ clear any previous results or error messages from previous analysis runs

+ display the top lesion finding's name below the input for and scroll the page to the results container.

+ display results based on top lesion finding below the input in a <div> entitled “lesion-analysis”

+ use the attached spreadsheet to determine the new content of the results container: “<p>It looks like you might have [lesionName].</p><p>[Therapy Message]</p>

- The data in this spreadsheet will be updated in other Jira tickets - persist the data however you wish in the repo itself

- if a lesion is not listed or is not recognized, the default behavior should be to display: “<p>I'm not sure what the condition of your skin is</p><p>Just to be safe, get this checked out by a dermatologist.</p>”

+ scroll the page to the top of this results container.
143 changes: 143 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# VisualDx API - Lesion Analysis Demo

A Next.js application that demonstrates the VisualDx API's ability to analyze skin images and provide cosmetic product recommendations.

## Features

- Image upload form for PNG and JPG files
- Real-time validation (PNG/JPG files under 10MB)
- Automatic OAuth2 token management for API access
- Progress spinner during analysis
- Error handling for various API states
- Responsive design
- Results display with lesion identification and therapy recommendations

## Getting Started

### Prerequisites

- Node.js 18+
- npm or yarn
- VisualDx API credentials with sandbox permissions

### Installation

1. Clone the repository:
```bash
git clone https://github.com/VisualDx/visualdx-api-image-analysis-demo.git
cd visualdx-api-image-analysis-demo
```

2. Install dependencies:
```bash
npm install
```

3. Set up environment variables:
Create a `.env.local` file in the root directory and add your VisualDx API credentials:
```env
CLIENT_ID=your_client_id_here
CLIENT_SECRET=your_client_secret_here
API_BASE_URL=https://api-dev.visualdx.com/v1
TOKEN_URL=https://api-dev.visualdx.com/v1/auth/token
AUDIENCE=consumer
```

4. Run the development server:
```bash
npm run dev
```

5. Open [http://localhost:3000](http://localhost:3000) in your browser.

## Usage

1. Navigate to the home page
2. Select a skin image file (PNG or JPG, under 10MB)
3. Click "Analyze Image" to submit
4. Wait for the analysis to complete
5. View the results with lesion identification and therapy recommendations

## Project Structure

```
src/
├── app/
│ ├── api/
│ │ └── analyze/
│ │ └── route.ts # API endpoint for image analysis
│ ├── layout.tsx # Root layout component
│ ├── page.tsx # Home page component
│ └── page.module.css # Styles for home page
└── lib/
├── config.ts # Centralized environment configuration
├── lesion-info.ts # Lesion lookup helpers
└── lesions-data.ts # Lesion database and therapy messages
```

## API Integration

The application integrates with the VisualDx API through a secure backend endpoint that:

- Handles authentication automatically using stored API keys
- Validates uploaded images (type, size)
- Processes API responses and maps them to lesion data
- Handles error states gracefully

## Error Handling

The application handles various error states:

- **Permission errors**: "This account lacks permission to analyze images"
- **File validation**: "Only .png and .jpg images smaller than 10MB are supported"
- **Network errors**: Generic error messages for connection issues
- **Unknown lesions**: Default response for unrecognized conditions

## Customization

### Adding New Lesions

Update the entries in `src/lib/lesions-data.ts` (and regenerate any helpers in `src/lib/lesion-info.ts` if needed) to add new lesion types and their corresponding therapy messages.

### Result Messaging

Known lesions render as:

```html
<p>It looks like you might have [lesionName].</p>
<p>[Therapy Message]</p>
```

Unknown lesions fall back to:

```html
<p>I'm not sure what the condition of your skin is</p>
<p>Just to be safe, get this checked out by a dermatologist.</p>
```

### Styling

Modify `src/app/page.module.css` to customize the appearance of the application.

## Deployment

This application can be deployed to any platform that supports Next.js:

- Vercel
- Netlify
- Heroku
- AWS
- Google Cloud Platform

Make sure to set your environment variables in your deployment platform.

## Security Notes

- API keys are stored securely as environment variables
- Keys are never exposed to the client-side code
- All API requests are proxied through the backend
- File uploads are validated on both client and server

## License

This project is licensed under the MIT License.
6 changes: 6 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
// App directory is now stable in Next.js 14
}

module.exports = nextConfig
Loading