SDK Authorization Requests Guide

This document explains how developers can use the miri-react-native-sdk to make authorization requests during the token exchange process.

Overview

The miri-react-native-sdk supports authorization requests as part of the token exchange flow. When a developer exchanges an SSO token for a Firebase token, they can simultaneously request authorization for external users to access the system.

Security Implementation

Authorization requests are validated at the provider level rather than being processed directly from client input. This prevents client-side tampering and ensures that:

  • Only authenticated users can make authorization requests
  • Authorization requests are validated against the user's actual permissions
  • External user IDs are verified to be accessible by the requesting user
  • All authorization decisions are audited and logged

Important: Only custom providers support authorization requests. Standard providers (Firebase, Google, Apple) will reject requests containing authorization requests with a 400 Bad Request error.

How Authorization Requests Work

1. Token Exchange with Authorization

During token exchange, developers can include an authorization_request in the configuration. The system:

  • Validates the SSO token for authentication
  • Validates the authorization request at the provider level (custom providers only)
  • Prevents client-side tampering of authorization data
  • Ensures proper access controls are enforced

2. Provider-Level Validation

The backend delegates authorization validation to the SSO provider:

  • Firebase/Google/Apple: Do not support authorization requests (rejected with 400 error)
  • Custom Providers: Full validation of authorization requests against your user database
  • Audit Trail: All authorization decisions are logged for security compliance

3. Backend Processing

After provider validation, the backend automatically:

  • Uses default permissions (PERMISSIONS_MEMBER_ADMIN)
  • Sets expiration to 1 hour from the request time
  • Creates authorization records for each external user
  • Associates the authorization with the organization

SDK Implementation

Basic Structure

The SDK supports authorization requests through the ConfigBase interface:

export interface ConfigBase {
api_key?: string;
authorization_request?: {
entries: {
external_uid: string;
}[];
};
}

Important: The authorization_request only includes external_uid values. The system automatically sets default permissions and expiration times.

Supported Providers

Authorization requests are only supported by custom providers:

  • Firebase: FirebaseConfig - No authorization request support
  • Google: GoogleConfig - No authorization request support
  • Apple: AppleConfig - No authorization request support
  • Custom: CustomConfig - Full authorization request support and validation

Note: If you include an authorization_request with Firebase, Google, or Apple providers, the request will be rejected with a 400 Bad Request error.

Usage Examples

Custom Provider with Authorization (Only Supported Provider)

import { MiriAppProvider, AuthProvider } from '@miri-ai/miri-react-native';

const miriAuth = {
token: "custom-sso-token",
provider: "custom",
config: {
token_validation_url: "https://your-domain.com/validate",
api_key: "your-api-key",
authorization_request: {
entries: [
{ external_uid: "user123" },
{ external_uid: "user456" }
]
}
}
};

function App() {
return (
<MiriAppProvider
apiKey="your-api-key"
env="production"
>
<AuthProvider miriAuth={miriAuth}>
{/* Your app components */}
</AuthProvider>
</MiriAppProvider>
);
}

Important: Only custom providers support authorization requests. If you try to use authorization requests with Firebase, Google, or Apple providers, your request will be rejected.

Standard Providers (No Authorization Support)

For Firebase, Google, and Apple providers, you can only perform basic token exchange without authorization requests:

// Firebase Provider (No Authorization)
const miriAuth = {
token: "firebase-sso-token",
provider: "firebase",
config: {
project_id: "your-firebase-project",
api_key: "your-api-key"
// No authorization_request - will be rejected if included
}
};

// Google Provider (No Authorization)
const miriAuth = {
token: "google-sso-token",
provider: "google",
config: {
client_id: "your-google-client-id",
issuer_url: "https://accounts.google.com",
api_key: "your-api-key"
// No authorization_request - will be rejected if included
}
};

// Apple Provider (No Authorization)
const miriAuth = {
token: "apple-sso-token",
provider: "apple",
config: {
team_id: "your-apple-team-id",
key_id: "your-apple-key-id",
issuer_url: "https://appleid.apple.com",
api_key: "your-api-key"
// No authorization_request - will be rejected if included
}
};

Authorization Request Structure

SDK Input (Simplified)

The SDK only requires the external_uid for each authorization entry:

authorization_request: {
entries: [
{ external_uid: "user123" },
{ external_uid: "user456" }
]
}

Backend Processing (Automatic)

The backend automatically adds:

# Default permissions
permissions: List[Permissions] = PERMISSIONS_MEMBER_ADMIN

# Default expiration (1 hour from now)
expires_at: datetime = get_utc_now() + timedelta(hours=1)

Complete Flow

1. Developer Setup

// Configure authorization request
const authorizationRequest = {
entries: [
{ external_uid: "external-user-1" },
{ external_uid: "external-user-2" }
]
};

// Include in token exchange config (custom provider required for authorization)
const miriAuth = {
token: "sso-token",
provider: "custom",
config: {
token_validation_url: "https://your-domain.com/validate",
api_key: "your-api-key",
authorization_request: authorizationRequest
}
};

2. SDK Processing

// SDK sends request to backend
const response = await exchangeToken(miriAuth);
// POST /api/v2.0/auth/token-exchange

3. Backend Processing

# Backend validates token AND authorization request at provider level
external_uid, token_data, validated_authorization = validator.validate_token_with_authorization(
token,
authorization_request
)

# Backend creates care seeker
care_seeker = create_or_get_care_seeker(external_uid)

# Backend processes ONLY validated authorization request
if validated_authorization:
authorization_records = authorization_service.process_authorization_request(
admin_care_seeker=care_seeker,
authorization_entries=validated_authorization.entries, # ← NOW VALIDATED!
organization_id=organization_id
)

4. Result

  • Firebase token is returned for the admin user
  • Authorization records are created for external users
  • External users can now access the system with their external_uid

Security Benefits

Current Security Features

  • Authorization requests validated at provider level
  • User permissions verified before processing
  • External user IDs validated against user's access scope
  • Complete audit trail of all authorization decisions
  • Prevention of privilege escalation attacks

Use Cases

External System Integration (Custom Provider Only)

// When integrating with external patient management systems
// Note: This requires a custom provider for authorization support
const miriAuth = {
token: "admin-sso-token",
provider: "custom", // Custom provider required for authorization
config: {
token_validation_url: "https://your-domain.com/validate",
api_key: "your-api-key",
authorization_request: {
entries: [
{ external_uid: "patient-123" }, // Patient from external system
{ external_uid: "patient-456" } // Another patient
]
}
}
};

Multi-User Onboarding (Custom Provider Only)

// When onboarding multiple users at once
// Note: This requires a custom provider for authorization support
const miriAuth = {
token: "admin-sso-token",
provider: "custom", // Custom provider required for authorization
config: {
token_validation_url: "https://your-domain.com/validate",
api_key: "your-api-key",
authorization_request: {
entries: [
{ external_uid: "new-user-1" },
{ external_uid: "new-user-2" },
{ external_uid: "new-user-3" }
]
}
}
};

Standard Provider Usage (No Authorization)

// For Firebase, Google, and Apple providers, you can only perform basic authentication
const miriAuth = {
token: "sso-token",
provider: "firebase", // or "google", "apple"
config: {
project_id: "your-project", // or client_id/issuer_url for Google/Apple
api_key: "your-api-key"
// No authorization_request possible with standard providers
}
};

Error Handling

Missing External UID

// ❌ Invalid - missing external_uid
authorization_request: {
entries: [
{} // This will cause validation errors
]
}

Empty Entries Array

// ❌ Invalid - empty entries array
authorization_request: {
entries: [] // Backend requires at least one entry
}

Valid Request

// ✅ Valid - proper structure
authorization_request: {
entries: [
{ external_uid: "user123" }
]
}

Best Practices

1. Use Custom Provider for Maximum Security

// ✅ Best - Full validation at your endpoint
provider: "custom",
config: {
token_validation_url: "https://your-domain.com/validate"
}

// ⚠️ Good - Basic validation by Miri
provider: "firebase",
config: {
project_id: "your-project"
}

2. Use Meaningful External UIDs

// ✅ Good - descriptive external UIDs
{ external_uid: "patient-john-doe-123" }
{ external_uid: "user-email@example.com" }

// ❌ Avoid - generic or unclear UIDs
{ external_uid: "user1" }
{ external_uid: "temp-123" }

3. Batch Authorization Requests

// ✅ Efficient - batch multiple users in one request
authorization_request: {
entries: [
{ external_uid: "user1" },
{ external_uid: "user2" },
{ external_uid: "user3" }
]
}

4. Handle Errors Gracefully

try {
const response = await exchangeToken(miriAuth);
// Authorization request processed successfully
} catch (error) {
// Handle authorization or token exchange errors
console.error('Authorization request failed:', error);
}

Limitations

Current SDK Limitations

  • Permissions: Cannot specify custom permissions (uses backend defaults)
  • Expiration: Cannot specify custom expiration (uses 1-hour default)
  • Validation: Limited validation on the client side

Backend Defaults

  • Permissions: PERMISSIONS_MEMBER_ADMIN
  • Expiration: 1 hour from request time
  • Validation: Provider-level validation (varies by provider)

Security Considerations

Provider Security Levels

  1. Custom Provider (Authorization Support)
  • Full authorization request support
  • Full authorization validation at your endpoint
  • Access to your user database for validation
  • Custom business logic for permission checks
  • Complete audit trail
  1. Standard Providers (No Authorization Support)
  • No authorization request support
  • Basic token-based authentication only
  • Authorization requests are rejected with 400 error
  • Limited to single-user authentication

Provider Limitations

| Provider | Authorization Support | Use Case ||----------|---------------------|----------|| Custom | ✅ Full Support | Multi-user onboarding, external system integration || Firebase | ❌ Not Supported | Single-user authentication only || Google | ❌ Not Supported | Single-user authentication only || Apple | ❌ Not Supported | Single-user authentication only |

Recommendations

  • Use custom providers for any scenario requiring authorization requests
  • Use standard providers only for basic single-user authentication
  • Implement proper rate limiting on your custom validation endpoints
  • Log all authorization requests for audit purposes
  • Regularly review authorization patterns for anomalies
  • Monitor for unauthorized access attempts

Current Implementation

The system provides:

  1. Custom Provider Authorization: Full support for authorization requests with provider-level validation
  2. Standard Provider Limitations: Firebase, Google, and Apple providers do not support authorization requests
  3. Provider-Level Security: Authorization requests are validated at the provider level (custom providers only)
  4. Audit Trail: All authorization decisions are logged (custom providers only)
  5. Error Handling: Clear error messages when authorization requests are not supported

Note: If you need authorization request functionality, you must use a custom provider as standard providers do not support this feature.

Related Documentation