---
title: "Multi-Flow Configuration"
description: "The OIDC Bridge supports four different credential presentation methods, each optimized for different user scenarios. You can enable/disable flows individually, customize button labels, and configure flow-specific…"
stack: "Enterprise Stack (commercial) — version 0.21.0"
stack_version: "0.21.0"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/enterprise-stack/services/oidc-bridge-service/multi-flow-config
generated: 2026-07-20
---
# Multi-Flow Configuration

The OIDC Bridge supports four different credential presentation methods, each optimized for different user scenarios. You can enable/disable flows individually, customize button labels, and configure flow-specific verification settings.

## Overview

When users are redirected to the OIDC Bridge during login, they see a presentation selection page with buttons for each enabled flow:

![OIDC Bridge Presentation UI](https://docs.walt.id/img/enterprise-stack/services/OIDC-Bridge-Credential-Presentation-UI.png)

**Available flows:**

| Flow | Description | User Experience | Device | Browser Support |
|------|-------------|-----------------|--------|-----------------|
| **QR Code** | Cross-device presentation | Scan QR with mobile wallet | Any device with camera | All browsers |
| **DC API** | Browser-native credential API | Browser shows credential picker | Same device | Chrome 128+, Edge |
| **Deep Link** | Direct wallet launch | Opens mobile wallet app | Same device (mobile) | All mobile browsers |
| **Web Wallet** | Browser-based wallet | Redirects to web wallet | Same device | All browsers |

## Configuration Structure

Flows are configured in the `flows` object when creating an OIDC Bridge service:

```json
{
  "type": "oidc-bridge",
  "issuerUrl": "https://enterprise.example.com",
  "flows": {
    "qr": {
      "enabled": true,
      "buttonLabel": "Scan QR Code",
      "verificationSetup": { ... }
    },
    "dc_api": {
      "enabled": true,
      "buttonLabel": "Browser Wallet",
      "verificationSetup": { ... }
    },
    "deep_link": {
      "enabled": true,
      "buttonLabel": "Open Mobile Wallet",
      "verificationSetup": { ... }
    },
    "web_wallet": {
      "enabled": true,
      "buttonLabel": "Open Web Wallet",
      "targetUrl": "https://wallet.example.com",
      "verificationSetup": { ... }
    }
  }
}
```

### Common Flow Fields

| Field | Required | Description |
|-------|----------|-------------|
| `enabled` | Yes | Enable or disable this flow |
| `buttonLabel` | No | Text shown on the presentation button (default varies by flow) |
| `verificationSetup` | Yes* | The credential request (DCQL query) sent to the wallet for this flow. See [Which `flow_type` to use](#which-flow_type-to-use). |

\* Each enabled flow needs a `verificationSetup` unless a client-level or service-level setup covers it.

## Which `flow_type` to use

Each flow's `verificationSetup` is structure like a Verifier2 verification request including a `flow_type` field. **For the OIDC Bridge, always configure every flow with `flow_type: cross_device`** — including the DC API flow:

```json
"verificationSetup": {
  "flow_type": "cross_device",
  "core_flow": {
    "dcql_query": { ... }
  }
}
```

## Flow 1: QR Code (Cross-Device)

The QR code flow enables users to scan a QR code with their mobile wallet and present credentials from their phone.

### How It Works

```mermaid
sequenceDiagram
    participant Desktop as Desktop Browser
    participant Bridge as OIDC Bridge
    participant Mobile as Mobile Wallet
    participant IAM as IAM System
    
    Desktop->>Bridge: 1. Click "Scan QR Code"
    Bridge->>Desktop: 2. Display QR code
    Mobile->>Bridge: 3. Scan QR & fetch request
    Mobile->>Mobile: 4. User approves credential
    Mobile->>Bridge: 5. Submit credential presentation
    Bridge->>Bridge: 6. Validate credential
    Desktop->>Bridge: 7. Poll for completion
    Bridge->>Desktop: 8. Redirect with auth code
    Desktop->>IAM: 9. Complete login
```

### Configuration

```json
{
  "flows": {
    "qr": {
      "enabled": true,
      "buttonLabel": "Scan QR Code with Mobile Wallet",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [{
              "id": "mdl",
              "format": "mso_mdoc",
              "meta": {
                "doctype_value": "org.iso.18013.5.1.mDL"
              },
              "claims": [
                { "path": ["org.iso.18013.5.1", "given_name"] },
                { "path": ["org.iso.18013.5.1", "family_name"] },
                { "path": ["org.iso.18013.5.1", "birth_date"] }
              ]
            }]
          }
        }
      }
    }
  }
}
```

### When to Use

- **Desktop users** who have credentials on their mobile device
- **Public kiosks** where users shouldn't log into their wallet
- **Cross-device security** — credentials never touch the login device

### User Experience

1. User clicks "Scan QR Code with Mobile Wallet"
2. QR code appears on screen
3. User opens their mobile wallet and scans the QR code
4. Wallet shows credential request and asks for approval
5. User approves and the credential is sent
6. Desktop browser automatically redirects to complete login

## Flow 2: DC API (Digital Credentials API)

The DC API flow uses the W3C Digital Credentials API (browser-native) for same-device credential presentation.

### How It Works

```mermaid
sequenceDiagram
    participant User
    participant Browser as Browser 
    participant DCAPI as Digital Credentials API
    participant Wallet as Wallet
    participant Bridge as OIDC Bridge
    
    User->>Browser: 1. Click "Use Browser Wallet"
    Browser->>DCAPI: 2. navigator.credentials.get()
    DCAPI->>Browser: 3. Show credential picker
    User->>Browser: 4. Select credential
    Browser->>Wallet: 5. Request credential
    Wallet->>Wallet: 6. User approves
    Wallet->>Browser: 7. Return credential
    Browser->>Bridge: 8. Submit presentation
    Bridge->>Bridge: 9. Validate credential
    Bridge->>Browser: 10. Redirect with auth code
```

### Configuration

```json
{
  "flows": {
    "dc_api": {
      "enabled": true,
      "buttonLabel": "Use Browser Wallet",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [{
              "id": "mdl",
              "format": "mso_mdoc",
              "meta": {
                "doctype_value": "org.iso.18013.5.1.mDL"
              },
              "claims": [
                { "path": ["org.iso.18013.5.1", "given_name"] },
                { "path": ["org.iso.18013.5.1", "family_name"] }
              ]
            }]
          }
        },
        "expectedOrigins": ["https://enterprise.example.com"]
      }
    }
  }
}
```

### Important: Expected Origins

The `expectedOrigins` field is **required** for DC API flows. It specifies which origins are allowed to receive the credential presentation:

```json
{
  "expectedOrigins": [
    "https://enterprise.example.com",
    "https://iam.example.com"
  ]
}
```

**warning:**

The DC API **requires HTTPS**. Localhost HTTP URLs are automatically converted to HTTPS by the OIDC Bridge for testing.

### When to Use

- **Modern browsers** (Chrome 128+)
- **Same-device login** where the credential is stored in a system wallet
- **Streamlined UX** — no QR scanning needed
- **High security** — credentials managed by the OS

### User Experience

1. User clicks "Use Browser Wallet"
2. Browser shows native credential picker UI
3. User selects credential from system wallet (Google Wallet, Apple Wallet, etc.)
4. Browser automatically submits the credential
5. User is logged in

### Testing DC API

To test DC API support:

```bash
# Check browser support
open https://digital-credentials.walt.id/

# Test with your OIDC Bridge
# 1. Ensure HTTPS is enabled
# 2. Configure expectedOrigins
# 3. Use a browser that supports the DC API eg. Chrome 128+
# 4. Have matching credentials Wallet
```

## Flow 3: Deep Link (Mobile Same-Device)

The deep link flow uses the `openid4vp://` URL scheme to launch the mobile wallet app directly.

### How It Works

```mermaid
sequenceDiagram
    participant User
    participant Browser as Mobile Browser
    participant OS as Mobile OS
    participant Wallet as Wallet App
    participant Bridge as OIDC Bridge
    
    User->>Browser: 1. Click "Open Mobile Wallet"
    Browser->>OS: 2. openid4vp:// deep link
    OS->>OS: 3. Show app picker (if multiple wallets)
    User->>OS: 4. Select wallet app
    OS->>Wallet: 5. Launch with request
    Wallet->>Wallet: 6. User approves credential
    Wallet->>Bridge: 7. Submit presentation
    Bridge->>Bridge: 8. Validate credential
    Wallet->>Browser: 9. Reopen browser with result
    Browser->>Browser: 10. Complete login
```

### Configuration

```json
{
  "flows": {
    "deep_link": {
      "enabled": true,
      "buttonLabel": "Open Mobile Wallet App",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [{
              "id": "identity",
              "format": "dc+sd-jwt",
              "meta": {
                "vct_values": ["IdentityCredential"]
              },
              "claims": [
                { "path": ["given_name"] },
                { "path": ["family_name"] },
                { "path": ["email"] }
              ]
            }]
          }
        }
      }
    }
  }
}
```

### When to Use

- **Mobile browsers** where users have wallet apps installed
- **Native app integration** — wallet apps can handle `openid4vp://` scheme
- **Same-device login** without browser-native API support

### User Experience

1. User clicks "Open Mobile Wallet App" on their phone
2. OS shows app picker (if multiple wallets installed)
3. Wallet app opens with credential request
4. User approves presentation
5. Browser automatically reopens and completes login

## Flow 4: Web Wallet

The web wallet flow redirects users to a browser-based wallet interface.

### How It Works

```mermaid
sequenceDiagram
    participant User
    participant Bridge as OIDC Bridge
    participant WebWallet as Web Wallet
    participant IAM as IAM System
    
    User->>Bridge: 1. Click "Use Web Wallet"
    Bridge->>WebWallet: 2. Redirect with request_uri
    WebWallet->>WebWallet: 3. Fetch credentials
    WebWallet->>User: 4. Show credential selection
    User->>WebWallet: 5. Approve presentation
    WebWallet->>Bridge: 6. Submit presentation
    Bridge->>Bridge: 7. Validate credential
    Bridge->>User: 8. Redirect with auth code
    User->>IAM: 9. Complete login
```

### Configuration

```json
{
  "flows": {
    "web_wallet": {
      "enabled": true,
      "buttonLabel": "Use Web Wallet",
      "targetUrl": "https://wallet.example.com/present",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [{
              "id": "identity",
              "format": "dc+sd-jwt",
              "meta": {
                "vct_values": ["IdentityCredential"]
              },
              "claims": [
                { "path": ["given_name"] },
                { "path": ["family_name"] }
              ]
            }]
          }
        }
      }
    }
  },
  "uiConfig": {
    "webWalletBaseUrl": "https://wallet.example.com"
  }
}
```

### Required Fields

| Field | Description |
|-------|-------------|
| `targetUrl` | Full URL to redirect to (overrides `webWalletBaseUrl`) |
| `uiConfig.webWalletBaseUrl` | Base URL for web wallet (used if `targetUrl` not specified) |

The OIDC Bridge constructs the redirect URL with query parameters:
```
https://wallet.example.com/present?request_uri={verifier2_request_uri}
```

### When to Use

- **Enterprise web wallets** deployed alongside the Enterprise Stack
- **Browser-only environments** (no mobile wallet)
- **Managed credentials** stored in web wallet
- **Consistent branding** — wallet UI matches enterprise theme

### User Experience

1. User clicks "Use Web Wallet"
2. Browser redirects to web wallet page
3. Web wallet shows credentials and asks for approval
4. User approves presentation
5. Web wallet redirects back to OIDC Bridge
6. User is logged in

### Integration with Enterprise UI

If using the walt.id Enterprise UI web wallet:

```json
{
  "flows": {
    "web_wallet": {
      "enabled": true,
      "buttonLabel": "Open walt.id Web Wallet",
      "targetUrl": "https://enterprise-ui.example.com/present"
    }
  },
  "uiConfig": {
    "webWalletBaseUrl": "https://enterprise-ui.example.com"
  }
}
```

## Per-Flow Verification Setup

Each flow can have its own DCQL query. This is useful when:

- **QR flow** accepts mDL (mobile driver's license)
- **DC API flow** accepts SD-JWT VC (browser-stored)
- **Web wallet flow** accepts any credential type

### Example: Different Credentials Per Flow

```json
{
  "flows": {
    "qr": {
      "enabled": true,
      "buttonLabel": "Scan mDL with Phone",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [{
              "id": "mdl",
              "format": "mso_mdoc",
              "meta": { "doctype_value": "org.iso.18013.5.1.mDL" },
              "claims": [
                { "path": ["org.iso.18013.5.1", "given_name"] },
                { "path": ["org.iso.18013.5.1", "family_name"] }
              ]
            }]
          }
        }
      }
    },
    "dc_api": {
      "enabled": true,
      "buttonLabel": "Browser Credential",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [{
              "id": "identity",
              "format": "dc+sd-jwt",
              "meta": { "vct_values": ["IdentityCredential"] },
              "claims": [
                { "path": ["given_name"] },
                { "path": ["family_name"] }
              ]
            }]
          }
        }
      }
    },
    "web_wallet": {
      "enabled": true,
      "buttonLabel": "Web Wallet (Any Type)",
      "targetUrl": "https://wallet.example.com/present",
      "verificationSetup": {
        "flow_type": "cross_device",
        "core_flow": {
          "dcql_query": {
            "credentials": [
              {
                "id": "option-mdl",
                "format": "mso_mdoc",
                "meta": { "doctype_value": "org.iso.18013.5.1.mDL" },
                "claims": [
                  { "path": ["org.iso.18013.5.1", "given_name"] },
                  { "path": ["org.iso.18013.5.1", "family_name"] }
                ]
              },
              {
                "id": "option-vc",
                "format": "dc+sd-jwt",
                "meta": { "vct_values": ["IdentityCredential"] },
                "claims": [
                  { "path": ["given_name"] },
                  { "path": ["family_name"] }
                ]
              }
            ],
            "credential_sets": [{
              "options": [["option-mdl"], ["option-vc"]],
              "required": true
            }]
          }
        }
      }
    }
  }
}
```

**info:**

If no per-flow `verificationSetup` is provided, the OIDC Bridge uses `defaultVerificationSetup` from the service configuration.

## UI Customization

Customize the presentation selection page appearance:

```json
{
  "uiConfig": {
    "brandName": "Acme Corporation",
    "primaryColor": "#3B82F6",
    "logoUrl": "https://example.com/logo.png",
    "webWalletBaseUrl": "https://wallet.example.com"
  }
}
```

### UI Configuration Fields

| Field | Description | Example |
|-------|-------------|---------|
| `brandName` | Organization name shown at top of page | `"Acme Corp"` |
| `primaryColor` | Hex color for buttons and accents | `"#3B82F6"` |
| `logoUrl` | URL to organization logo (shown above brand name) | `"https://example.com/logo.png"` |
| `webWalletBaseUrl` | Default base URL for web wallet redirects | `"https://wallet.example.com"` |

## Recommended Configurations

### Configuration 1: Mobile-First (QR + Deep Link)

For scenarios where most users will present from mobile wallets:

```json
{
  "flows": {
    "qr": {
      "enabled": true,
      "buttonLabel": "Scan with Mobile Wallet"
    },
    "deep_link": {
      "enabled": true,
      "buttonLabel": "Open Wallet App"
    },
    "dc_api": {
      "enabled": false
    },
    "web_wallet": {
      "enabled": false
    }
  }
}
```

### Configuration 2: Modern Browser (DC API + Web Wallet)

For controlled environments with modern browsers:

```json
{
  "flows": {
    "qr": {
      "enabled": false
    },
    "deep_link": {
      "enabled": false
    },
    "dc_api": {
      "enabled": true,
      "buttonLabel": "Use System Wallet"
    },
    "web_wallet": {
      "enabled": true,
      "buttonLabel": "Use Web Wallet",
      "targetUrl": "https://wallet.example.com/present"
    }
  }
}
```

### Configuration 3: All Options (Maximum Flexibility)

Enable all flows to support all user scenarios:

```json
{
  "flows": {
    "qr": {
      "enabled": true,
      "buttonLabel": "Scan QR Code"
    },
    "deep_link": {
      "enabled": true,
      "buttonLabel": "Open Mobile Wallet"
    },
    "dc_api": {
      "enabled": true,
      "buttonLabel": "Browser Wallet"
    },
    "web_wallet": {
      "enabled": true,
      "buttonLabel": "Web Wallet"
    }
  }
}
```

## Next Steps

- [Claim Mappings](https://docs.walt.id/enterprise-stack/services/oidc-bridge-service/claim-mappings.md) — Configure credential-to-claim mappings
- [Setup](https://docs.walt.id/enterprise-stack/services/oidc-bridge-service/setup.md) — Create your OIDC Bridge service
- [Keycloak Integration](https://docs.walt.id/enterprise-stack/services/oidc-bridge-service/iam-integrations/keycloak.md) — See multi-flow in action
