feat: Begin support for OIDC login
This commit is contained in:
109
docs/MICROSOFT_ENTRA_QUICKSTART.md
Normal file
109
docs/MICROSOFT_ENTRA_QUICKSTART.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Microsoft Entra OpenID Connect - Quick Start
|
||||
|
||||
## What Was Implemented
|
||||
|
||||
The Login flow now supports Microsoft Entra ID (Azure AD) authentication via OpenID Connect using Supabase's Azure OAuth provider.
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. **[Login.tsx](management-dashboard-web-app/src/components/Login.tsx)**: Added Microsoft login button and OAuth flow
|
||||
2. **[MicrosoftIcon.tsx](management-dashboard-web-app/src/components/MicrosoftIcon.tsx)**: Created Microsoft logo component
|
||||
3. **[vite-env.d.ts](management-dashboard-web-app/src/vite-env.d.ts)**: Added TypeScript type for new environment variable
|
||||
4. **[.env.example](management-dashboard-web-app/.env.example)**: Added Microsoft login configuration
|
||||
|
||||
## How It Works
|
||||
|
||||
### User Experience
|
||||
1. User visits login page and sees two options:
|
||||
- Traditional email/password login (existing)
|
||||
- "Sign in with Microsoft" button (new)
|
||||
2. Clicking Microsoft button redirects to Microsoft login
|
||||
3. User authenticates with Microsoft credentials
|
||||
4. Microsoft redirects back to app with authenticated session
|
||||
|
||||
### Technical Flow
|
||||
```
|
||||
User clicks "Sign in with Microsoft"
|
||||
↓
|
||||
Supabase signInWithOAuth() with provider: 'azure'
|
||||
↓
|
||||
Redirect to Microsoft Entra login page
|
||||
↓
|
||||
User authenticates with Microsoft
|
||||
↓
|
||||
Microsoft redirects to Supabase callback URL
|
||||
↓
|
||||
Supabase validates and creates session
|
||||
↓
|
||||
User redirected back to application (authenticated)
|
||||
```
|
||||
|
||||
## Configuration Required
|
||||
|
||||
### 1. Azure Portal Setup
|
||||
- Register application in Microsoft Entra ID
|
||||
- Configure redirect URI: `https://<supabase-ref>.supabase.co/auth/v1/callback`
|
||||
- Generate client ID and client secret
|
||||
- Set API permissions (openid, profile, email)
|
||||
|
||||
### 2. Supabase Configuration
|
||||
Navigate to Authentication > Providers > Azure and configure:
|
||||
- **Azure Client ID**: From Azure app registration
|
||||
- **Azure Secret**: From Azure client secrets
|
||||
- **Azure Tenant**: Use `common` for multi-tenant or specific tenant ID
|
||||
|
||||
### 3. Application Environment
|
||||
Set in `.env` file:
|
||||
```bash
|
||||
VITE_ENABLE_MICROSOFT_LOGIN=true
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Enable Microsoft Login
|
||||
```bash
|
||||
# In .env file
|
||||
VITE_ENABLE_MICROSOFT_LOGIN=true
|
||||
```
|
||||
|
||||
### Disable Microsoft Login
|
||||
```bash
|
||||
# In .env file
|
||||
VITE_ENABLE_MICROSOFT_LOGIN=false
|
||||
# Or simply remove the variable
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
✅ **Hybrid Authentication**: Supports both email/password and Microsoft login
|
||||
✅ **Feature Flag**: Microsoft login can be enabled/disabled via environment variable
|
||||
✅ **Dark Mode Support**: Microsoft button matches the existing theme
|
||||
✅ **Error Handling**: Displays authentication errors to users
|
||||
✅ **Loading States**: Shows loading indicator during authentication
|
||||
✅ **Type Safety**: Full TypeScript support with proper types
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Complete Azure Setup**: Follow [MICROSOFT_ENTRA_SETUP.md](./MICROSOFT_ENTRA_SETUP.md) for detailed configuration
|
||||
2. **Configure Supabase**: Enable Azure provider in Supabase dashboard
|
||||
3. **Test Authentication**: Verify the complete login flow
|
||||
4. **Deploy**: Update production environment variables
|
||||
|
||||
## Documentation
|
||||
|
||||
- **Full Setup Guide**: [MICROSOFT_ENTRA_SETUP.md](./MICROSOFT_ENTRA_SETUP.md) - Complete Azure and Supabase configuration
|
||||
- **Supabase Docs**: https://supabase.com/docs/guides/auth/social-login/auth-azure
|
||||
- **Microsoft Identity Platform**: https://docs.microsoft.com/azure/active-directory/develop/
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- Check [MICROSOFT_ENTRA_SETUP.md](./MICROSOFT_ENTRA_SETUP.md) troubleshooting section
|
||||
- Review Supabase Auth logs
|
||||
- Check Azure sign-in logs in Azure Portal
|
||||
- Verify redirect URIs match exactly
|
||||
|
||||
---
|
||||
|
||||
**Implementation Date**: January 9, 2026
|
||||
**Status**: Ready for configuration and testing
|
||||
342
docs/MICROSOFT_ENTRA_SETUP.md
Normal file
342
docs/MICROSOFT_ENTRA_SETUP.md
Normal file
@@ -0,0 +1,342 @@
|
||||
# Microsoft Entra (Azure AD) OpenID Connect Setup Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide walks you through configuring Microsoft Entra ID (formerly Azure Active Directory) authentication for the USDA Vision Management Dashboard using Supabase's Azure OAuth provider.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Access to Azure Portal (https://portal.azure.com)
|
||||
- Admin permissions to register applications in Azure AD
|
||||
- Access to your Supabase project dashboard
|
||||
- The USDA Vision application deployed and accessible via URL
|
||||
|
||||
## Step 1: Register Application in Microsoft Entra ID
|
||||
|
||||
### 1.1 Navigate to Azure Portal
|
||||
|
||||
1. Log in to [Azure Portal](https://portal.azure.com)
|
||||
2. Navigate to **Microsoft Entra ID** (or **Azure Active Directory**)
|
||||
3. Select **App registrations** from the left sidebar
|
||||
4. Click **+ New registration**
|
||||
|
||||
### 1.2 Configure Application Registration
|
||||
|
||||
Fill in the following details:
|
||||
|
||||
- **Name**: `USDA Vision Management Dashboard` (or your preferred name)
|
||||
- **Supported account types**: Choose one of:
|
||||
- **Single tenant**: Only users in your organization can sign in (most restrictive)
|
||||
- **Multitenant**: Users in any Azure AD tenant can sign in
|
||||
- **Multitenant + personal Microsoft accounts**: Broadest support
|
||||
- **Redirect URI**:
|
||||
- Platform: **Web**
|
||||
- URI: `https://<your-supabase-project-ref>.supabase.co/auth/v1/callback`
|
||||
- Example: `https://abcdefghij.supabase.co/auth/v1/callback`
|
||||
|
||||
Click **Register** to create the application.
|
||||
|
||||
### 1.3 Note Application (Client) ID
|
||||
|
||||
After registration, you'll be taken to the app overview page. Copy and save:
|
||||
- **Application (client) ID**: This is your `AZURE_CLIENT_ID`
|
||||
- **Directory (tenant) ID**: This is your `AZURE_TENANT_ID`
|
||||
|
||||
## Step 2: Configure Client Secret
|
||||
|
||||
### 2.1 Create a Client Secret
|
||||
|
||||
1. In your app registration, navigate to **Certificates & secrets**
|
||||
2. Click **+ New client secret**
|
||||
3. Add a description: `Supabase Auth`
|
||||
4. Choose an expiration period (recommendation: 12-24 months)
|
||||
5. Click **Add**
|
||||
|
||||
### 2.2 Save the Secret Value
|
||||
|
||||
**IMPORTANT**: Copy the **Value** immediately - it will only be shown once!
|
||||
- This is your `AZURE_CLIENT_SECRET`
|
||||
- Store it securely (password manager, secure vault, etc.)
|
||||
|
||||
## Step 3: Configure API Permissions
|
||||
|
||||
### 3.1 Add Required Permissions
|
||||
|
||||
1. Navigate to **API permissions** in your app registration
|
||||
2. Click **+ Add a permission**
|
||||
3. Select **Microsoft Graph**
|
||||
4. Choose **Delegated permissions**
|
||||
5. Add the following permissions:
|
||||
- `openid` (Sign users in)
|
||||
- `profile` (View users' basic profile)
|
||||
- `email` (View users' email address)
|
||||
- `User.Read` (Sign in and read user profile)
|
||||
|
||||
6. Click **Add permissions**
|
||||
|
||||
### 3.2 Grant Admin Consent (Optional but Recommended)
|
||||
|
||||
If you have admin privileges:
|
||||
1. Click **Grant admin consent for [Your Organization]**
|
||||
2. Confirm the action
|
||||
|
||||
This prevents users from seeing a consent prompt on first login.
|
||||
|
||||
## Step 4: Configure Authentication Settings
|
||||
|
||||
### 4.1 Set Token Configuration
|
||||
|
||||
1. Navigate to **Token configuration** in your app registration
|
||||
2. Click **+ Add optional claim**
|
||||
3. Choose **ID** token type
|
||||
4. Add the following claims:
|
||||
- `email`
|
||||
- `family_name`
|
||||
- `given_name`
|
||||
- `upn` (User Principal Name)
|
||||
|
||||
5. Check **Turn on the Microsoft Graph email, profile permission** if prompted
|
||||
|
||||
### 4.2 Configure Authentication Flow
|
||||
|
||||
1. Navigate to **Authentication** in your app registration
|
||||
2. Under **Implicit grant and hybrid flows**, ensure:
|
||||
- ✅ **ID tokens** (used for implicit and hybrid flows) is checked
|
||||
3. Under **Allow public client flows**:
|
||||
- Select **No** (keep it secure)
|
||||
|
||||
## Step 5: Configure Supabase
|
||||
|
||||
### 5.1 Navigate to Supabase Auth Settings
|
||||
|
||||
1. Log in to your [Supabase Dashboard](https://app.supabase.com)
|
||||
2. Select your project
|
||||
3. Navigate to **Authentication** > **Providers**
|
||||
4. Find **Azure** in the provider list
|
||||
|
||||
### 5.2 Enable and Configure Azure Provider
|
||||
|
||||
1. Toggle **Enable Sign in with Azure** to ON
|
||||
2. Fill in the configuration:
|
||||
|
||||
- **Azure Client ID**: Paste your Application (client) ID from Step 1.3
|
||||
- **Azure Secret**: Paste your client secret value from Step 2.2
|
||||
- **Azure Tenant**: You have two options:
|
||||
- Use `common` for multi-tenant applications
|
||||
- Use your specific **Directory (tenant) ID** for single-tenant
|
||||
- Format: Just the GUID (e.g., `12345678-1234-1234-1234-123456789012`)
|
||||
|
||||
3. Click **Save**
|
||||
|
||||
### 5.3 Note the Callback URL
|
||||
|
||||
Supabase provides the callback URL in the format:
|
||||
```
|
||||
https://<your-project-ref>.supabase.co/auth/v1/callback
|
||||
```
|
||||
|
||||
Verify this matches what you configured in Azure (Step 1.2).
|
||||
|
||||
## Step 6: Configure Application Environment
|
||||
|
||||
### 6.1 Update Environment Variables
|
||||
|
||||
In your application's `.env` file, add or update:
|
||||
|
||||
```bash
|
||||
# Supabase Configuration (if not already present)
|
||||
VITE_SUPABASE_URL=https://<your-project-ref>.supabase.co
|
||||
VITE_SUPABASE_ANON_KEY=<your-anon-key>
|
||||
|
||||
# Enable Microsoft Login
|
||||
VITE_ENABLE_MICROSOFT_LOGIN=true
|
||||
```
|
||||
|
||||
### 6.2 Restart Development Server
|
||||
|
||||
If running locally:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Step 7: Test the Integration
|
||||
|
||||
### 7.1 Test Login Flow
|
||||
|
||||
1. Navigate to your application's login page
|
||||
2. You should see a "Sign in with Microsoft" button
|
||||
3. Click the button
|
||||
4. You should be redirected to Microsoft's login page
|
||||
5. Sign in with your Microsoft account
|
||||
6. Grant consent if prompted
|
||||
7. You should be redirected back to your application, logged in
|
||||
|
||||
### 7.2 Verify User Data
|
||||
|
||||
After successful login, check that:
|
||||
- User profile information is available
|
||||
- Email address is correctly populated
|
||||
- User roles/permissions are properly assigned (if using RBAC)
|
||||
|
||||
### 7.3 Common Issues and Troubleshooting
|
||||
|
||||
#### Redirect URI Mismatch
|
||||
**Error**: `AADSTS50011: The redirect URI ... does not match the redirect URIs configured`
|
||||
|
||||
**Solution**: Ensure the redirect URI in Azure matches exactly:
|
||||
```
|
||||
https://<your-project-ref>.supabase.co/auth/v1/callback
|
||||
```
|
||||
|
||||
#### Invalid Client Secret
|
||||
**Error**: `Invalid client secret provided`
|
||||
|
||||
**Solution**:
|
||||
- Verify you copied the secret **Value**, not the Secret ID
|
||||
- Generate a new client secret if the old one expired
|
||||
|
||||
#### Missing Permissions
|
||||
**Error**: User consent required or permission denied
|
||||
|
||||
**Solution**:
|
||||
- Add the required API permissions in Azure (Step 3)
|
||||
- Grant admin consent if available
|
||||
|
||||
#### CORS Errors
|
||||
**Error**: CORS policy blocking requests
|
||||
|
||||
**Solution**:
|
||||
- Ensure your application URL is properly configured in Supabase
|
||||
- Check that you're using the correct Supabase URL
|
||||
|
||||
## Step 8: Production Deployment
|
||||
|
||||
### 8.1 Update Redirect URI for Production
|
||||
|
||||
1. Go back to Azure Portal > App registrations
|
||||
2. Navigate to **Authentication**
|
||||
3. Add production redirect URI:
|
||||
```
|
||||
https://your-production-domain.com/
|
||||
```
|
||||
4. Ensure Supabase callback URI is still present
|
||||
|
||||
### 8.2 Set Production Environment Variables
|
||||
|
||||
Update your production environment with:
|
||||
```bash
|
||||
VITE_SUPABASE_URL=https://<your-project-ref>.supabase.co
|
||||
VITE_SUPABASE_ANON_KEY=<your-production-anon-key>
|
||||
VITE_ENABLE_MICROSOFT_LOGIN=true
|
||||
```
|
||||
|
||||
### 8.3 Security Best Practices
|
||||
|
||||
1. **Rotate Secrets Regularly**: Set calendar reminders before client secret expiration
|
||||
2. **Use Azure Key Vault**: Store secrets in Azure Key Vault for enhanced security
|
||||
3. **Monitor Sign-ins**: Use Azure AD sign-in logs to monitor authentication activity
|
||||
4. **Implement MFA**: Require multi-factor authentication for sensitive accounts
|
||||
5. **Review Permissions**: Regularly audit API permissions and remove unnecessary ones
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Multi-Tenant Support
|
||||
|
||||
If you want to support users from multiple Azure AD tenants:
|
||||
|
||||
1. In Azure App Registration > **Authentication**:
|
||||
- Set **Supported account types** to **Multitenant**
|
||||
|
||||
2. In Supabase Azure provider configuration:
|
||||
- Set **Azure Tenant** to `common`
|
||||
|
||||
### Custom Domain Configuration
|
||||
|
||||
If using a custom domain with Supabase:
|
||||
|
||||
1. Configure custom domain in Supabase dashboard
|
||||
2. Update redirect URI in Azure to use custom domain
|
||||
3. Update application environment variables
|
||||
|
||||
### User Attribute Mapping
|
||||
|
||||
To map Azure AD attributes to Supabase user metadata:
|
||||
|
||||
1. Use Supabase database triggers or functions
|
||||
2. Extract attributes from JWT token
|
||||
3. Update user metadata in `auth.users` table
|
||||
|
||||
Example attributes available:
|
||||
- `sub`: User's unique ID
|
||||
- `email`: Email address
|
||||
- `name`: Full name
|
||||
- `given_name`: First name
|
||||
- `family_name`: Last name
|
||||
- `preferred_username`: Username
|
||||
|
||||
## Integration with RBAC System
|
||||
|
||||
To integrate Microsoft Entra authentication with your existing RBAC system:
|
||||
|
||||
### Option 1: Manual Role Assignment
|
||||
|
||||
After user signs in via Microsoft:
|
||||
1. Admin assigns roles in the management dashboard
|
||||
2. Roles stored in your `user_roles` table
|
||||
3. User gets appropriate permissions on next login
|
||||
|
||||
### Option 2: Azure AD Group Mapping
|
||||
|
||||
Map Azure AD groups to application roles:
|
||||
1. Configure group claims in Azure token configuration
|
||||
2. Read groups from JWT token in Supabase
|
||||
3. Automatically assign roles based on group membership
|
||||
|
||||
### Option 3: Hybrid Approach
|
||||
|
||||
Support both Microsoft and email/password login:
|
||||
- Keep existing email/password authentication
|
||||
- Add Microsoft as an additional option
|
||||
- Users can link accounts or use either method
|
||||
|
||||
## Monitoring and Maintenance
|
||||
|
||||
### Azure AD Monitoring
|
||||
|
||||
- **Sign-in logs**: Monitor authentication attempts
|
||||
- **Audit logs**: Track configuration changes
|
||||
- **Usage analytics**: Understand authentication patterns
|
||||
|
||||
### Supabase Monitoring
|
||||
|
||||
- **Auth logs**: View authentication events
|
||||
- **User activity**: Track active users
|
||||
- **Error logs**: Identify authentication issues
|
||||
|
||||
### Regular Maintenance Tasks
|
||||
|
||||
- [ ] Rotate client secrets before expiration (set reminders)
|
||||
- [ ] Review and update API permissions quarterly
|
||||
- [ ] Audit user access and remove inactive users
|
||||
- [ ] Update token configuration as needed
|
||||
- [ ] Test authentication flow after any infrastructure changes
|
||||
|
||||
## Support and Resources
|
||||
|
||||
### Microsoft Documentation
|
||||
- [Microsoft identity platform documentation](https://docs.microsoft.com/azure/active-directory/develop/)
|
||||
- [Azure AD app registration](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app)
|
||||
- [OpenID Connect on Microsoft identity platform](https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc)
|
||||
|
||||
### Supabase Documentation
|
||||
- [Supabase Auth with Azure](https://supabase.com/docs/guides/auth/social-login/auth-azure)
|
||||
- [Supabase Auth API reference](https://supabase.com/docs/reference/javascript/auth-signinwithoauth)
|
||||
|
||||
### Troubleshooting Resources
|
||||
- Azure AD Error Codes: https://docs.microsoft.com/azure/active-directory/develop/reference-aadsts-error-codes
|
||||
- Supabase Discord Community: https://discord.supabase.com
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: January 2026
|
||||
**Maintained By**: USDA Vision System Team
|
||||
@@ -10,3 +10,10 @@ VITE_VISION_SYSTEM_REMOTE_URL=http://exp-dash:3002/assets/remoteEntry.js?v=$(dat
|
||||
# API URLs
|
||||
VITE_VISION_API_URL=http://exp-dash:8000
|
||||
VITE_MEDIA_API_URL=http://exp-dash:8090
|
||||
|
||||
# Supabase Configuration
|
||||
VITE_SUPABASE_URL=https://your-project-url.supabase.co
|
||||
VITE_SUPABASE_ANON_KEY=your-anon-key
|
||||
|
||||
# Microsoft Entra (Azure AD) OAuth Configuration
|
||||
VITE_ENABLE_MICROSOFT_LOGIN=true
|
||||
|
||||
@@ -14,7 +14,7 @@ function App() {
|
||||
checkAuthState()
|
||||
|
||||
// Listen for auth changes
|
||||
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
|
||||
const { data: { subscription } } = supabase.auth.onAuthStateChange((event: string, session: any) => {
|
||||
console.log('Auth state changed:', event, !!session)
|
||||
setIsAuthenticated(!!session)
|
||||
setLoading(false)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react'
|
||||
import { supabase } from '../lib/supabase'
|
||||
import { MicrosoftIcon } from './MicrosoftIcon'
|
||||
|
||||
interface LoginProps {
|
||||
onLoginSuccess: () => void
|
||||
@@ -10,6 +11,7 @@ export function Login({ onLoginSuccess }: LoginProps) {
|
||||
const [password, setPassword] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const enableMicrosoftLogin = import.meta.env.VITE_ENABLE_MICROSOFT_LOGIN === 'true'
|
||||
|
||||
const handleLogin = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
@@ -35,6 +37,32 @@ export function Login({ onLoginSuccess }: LoginProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const handleMicrosoftLogin = async () => {
|
||||
setLoading(true)
|
||||
setError(null)
|
||||
|
||||
try {
|
||||
const { error } = await supabase.auth.signInWithOAuth({
|
||||
provider: 'azure',
|
||||
options: {
|
||||
scopes: 'email openid profile',
|
||||
redirectTo: `${window.location.origin}/`,
|
||||
},
|
||||
})
|
||||
|
||||
if (error) {
|
||||
setError(error.message)
|
||||
setLoading(false)
|
||||
}
|
||||
// If successful, user will be redirected to Microsoft login
|
||||
// and then back to the app, so we don't stop loading here
|
||||
} catch (err) {
|
||||
setError('An unexpected error occurred during Microsoft login')
|
||||
console.error('Microsoft login error:', err)
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900">
|
||||
<div className="max-w-md w-full space-y-8">
|
||||
@@ -108,6 +136,33 @@ export function Login({ onLoginSuccess }: LoginProps) {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{enableMicrosoftLogin && (
|
||||
<>
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<div className="w-full border-t border-gray-300 dark:border-gray-700" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-sm">
|
||||
<span className="px-2 bg-gray-50 dark:bg-gray-900 text-gray-500 dark:text-gray-400">
|
||||
Or continue with
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleMicrosoftLogin}
|
||||
disabled={loading}
|
||||
className="w-full flex items-center justify-center gap-3 py-2 px-4 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm text-sm font-medium text-gray-700 dark:text-gray-300 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
<MicrosoftIcon className="w-5 h-5" />
|
||||
<span>Sign in with Microsoft</span>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
export function MicrosoftIcon({ className = "w-5 h-5" }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 23 23" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="#f3f3f3" d="M0 0h23v23H0z" />
|
||||
<path fill="#f35325" d="M1 1h10v10H1z" />
|
||||
<path fill="#81bc06" d="M12 1h10v10H12z" />
|
||||
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
||||
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ interface ImportMetaEnv {
|
||||
readonly VITE_SUPABASE_URL: string;
|
||||
readonly VITE_SUPABASE_ANON_KEY: string;
|
||||
readonly VITE_VISION_API_URL?: string; // optional; defaults to "/api" via vite proxy
|
||||
readonly VITE_ENABLE_MICROSOFT_LOGIN?: string; // optional; enable Microsoft Entra authentication
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
||||
61
package-lock.json
generated
Normal file
61
package-lock.json
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "usda-vision",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "19.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.3"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
package.json
Normal file
9
package.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.7"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user