|
| 1 | +<script lang="ts"> |
| 2 | + import { |
| 3 | + KeyRound, |
| 4 | + Shield, |
| 5 | + Lock, |
| 6 | + AppWindow, |
| 7 | + UserCheck, |
| 8 | + Search, |
| 9 | + } from "@lucide/svelte"; |
| 10 | +</script> |
| 11 | + |
| 12 | +<svelte:head> |
| 13 | + <title>Consumers Guide - API Manager</title> |
| 14 | +</svelte:head> |
| 15 | + |
| 16 | +<div class="container mx-auto px-4 py-8"> |
| 17 | + <nav class="breadcrumb mb-6"> |
| 18 | + <a href="/management-docs/consumers" class="breadcrumb-link">Management Docs</a> |
| 19 | + <span class="breadcrumb-separator">></span> |
| 20 | + <span class="breadcrumb-current">Consumers</span> |
| 21 | + </nav> |
| 22 | + |
| 23 | + <div class="panel"> |
| 24 | + <div class="panel-header"> |
| 25 | + <div class="header-content"> |
| 26 | + <div class="header-icon"> |
| 27 | + <AppWindow size={32} /> |
| 28 | + </div> |
| 29 | + <div> |
| 30 | + <h1 class="panel-title">Consumers</h1> |
| 31 | + <div class="panel-subtitle"> |
| 32 | + Understanding and managing API Consumers (Apps) |
| 33 | + </div> |
| 34 | + </div> |
| 35 | + </div> |
| 36 | + </div> |
| 37 | + |
| 38 | + <div class="panel-content"> |
| 39 | + <div class="intro-grid"> |
| 40 | + <section class="section"> |
| 41 | + <h2 class="section-title">What is a Consumer?</h2> |
| 42 | + <p class="section-text"> |
| 43 | + A Consumer is the "App" that calls the OBP API on behalf of an end user or system. |
| 44 | + It can be a web application, mobile app, or server-side service. Each Consumer has a |
| 45 | + <strong>consumer key</strong> and <strong>secret</strong> which allows it to authenticate |
| 46 | + securely with the API server. |
| 47 | + </p> |
| 48 | + <p class="section-text" style="margin-top: 0.75rem;"> |
| 49 | + Every Consumer is assigned a <strong>Consumer ID</strong> (a UUID) which appears in |
| 50 | + API metrics, logs, and messages to the backend. This makes it possible to track which |
| 51 | + application is making which API calls. |
| 52 | + </p> |
| 53 | + </section> |
| 54 | + |
| 55 | + <section class="section"> |
| 56 | + <h2 class="section-title">Key Concepts</h2> |
| 57 | + <div class="concepts-list"> |
| 58 | + <div class="concept-item"> |
| 59 | + <h3 class="concept-title">Consumer Key & Secret</h3> |
| 60 | + <p class="concept-text"> |
| 61 | + Credentials used by the App to authenticate with OBP via OAuth or Direct Login. |
| 62 | + The secret must be kept confidential. |
| 63 | + </p> |
| 64 | + </div> |
| 65 | + <div class="concept-item"> |
| 66 | + <h3 class="concept-title">Consumer ID</h3> |
| 67 | + <p class="concept-text"> |
| 68 | + A UUID that uniquely identifies the Consumer. Appears in metrics and can be used |
| 69 | + to filter API call logs. |
| 70 | + </p> |
| 71 | + </div> |
| 72 | + <div class="concept-item"> |
| 73 | + <h3 class="concept-title">mTLS Certificate Pinning</h3> |
| 74 | + <p class="concept-text"> |
| 75 | + A Consumer can be pinned to an mTLS certificate. After pinning, the App must |
| 76 | + present the certificate in all communication with the server. |
| 77 | + </p> |
| 78 | + </div> |
| 79 | + <div class="concept-item"> |
| 80 | + <h3 class="concept-title">Scopes & Rate Limits</h3> |
| 81 | + <p class="concept-text"> |
| 82 | + Consumers can have scopes (controlling which endpoints they can access) and |
| 83 | + rate limits (controlling how many calls they can make). |
| 84 | + </p> |
| 85 | + </div> |
| 86 | + </div> |
| 87 | + </section> |
| 88 | + </div> |
| 89 | + |
| 90 | + <section class="section workflow-section"> |
| 91 | + <h2 class="section-title">Common Tasks</h2> |
| 92 | + |
| 93 | + <div class="steps-grid"> |
| 94 | + <div class="step-card"> |
| 95 | + <div class="step-header"> |
| 96 | + <div class="step-number">1</div> |
| 97 | + <div class="step-icon"> |
| 98 | + <Search size={20} /> |
| 99 | + </div> |
| 100 | + </div> |
| 101 | + <div class="step-body"> |
| 102 | + <h3 class="step-title">Find a Consumer</h3> |
| 103 | + <p class="step-text"> |
| 104 | + Use the API Metrics page to identify a Consumer ID from API call logs. |
| 105 | + Filter by <code>consumer_id</code> to see all calls from a specific App. |
| 106 | + </p> |
| 107 | + <a href="/metrics" class="step-link"> |
| 108 | + Go to Metrics → |
| 109 | + </a> |
| 110 | + </div> |
| 111 | + </div> |
| 112 | + |
| 113 | + <div class="step-card"> |
| 114 | + <div class="step-header"> |
| 115 | + <div class="step-number">2</div> |
| 116 | + <div class="step-icon"> |
| 117 | + <UserCheck size={20} /> |
| 118 | + </div> |
| 119 | + </div> |
| 120 | + <div class="step-body"> |
| 121 | + <h3 class="step-title">Review Consumer Details</h3> |
| 122 | + <p class="step-text"> |
| 123 | + Check who registered the Consumer (developer email), what App name was given, |
| 124 | + and whether it has been enabled or is still pending approval. |
| 125 | + </p> |
| 126 | + </div> |
| 127 | + </div> |
| 128 | + |
| 129 | + <div class="step-card"> |
| 130 | + <div class="step-header"> |
| 131 | + <div class="step-number">3</div> |
| 132 | + <div class="step-icon"> |
| 133 | + <Shield size={20} /> |
| 134 | + </div> |
| 135 | + </div> |
| 136 | + <div class="step-body"> |
| 137 | + <h3 class="step-title">Manage Scopes</h3> |
| 138 | + <p class="step-text"> |
| 139 | + Control which API endpoints a Consumer can access by managing its scopes. |
| 140 | + This is separate from the user's Entitlements (Roles). |
| 141 | + </p> |
| 142 | + </div> |
| 143 | + </div> |
| 144 | + |
| 145 | + <div class="step-card"> |
| 146 | + <div class="step-header"> |
| 147 | + <div class="step-number">4</div> |
| 148 | + <div class="step-icon"> |
| 149 | + <Lock size={20} /> |
| 150 | + </div> |
| 151 | + </div> |
| 152 | + <div class="step-body"> |
| 153 | + <h3 class="step-title">Certificate Pinning</h3> |
| 154 | + <p class="step-text"> |
| 155 | + For PSD2 or high-security scenarios, pin the Consumer to an mTLS certificate. |
| 156 | + The certificate has a one-to-one relationship with the Consumer. |
| 157 | + </p> |
| 158 | + </div> |
| 159 | + </div> |
| 160 | + |
| 161 | + <div class="step-card"> |
| 162 | + <div class="step-header"> |
| 163 | + <div class="step-number">5</div> |
| 164 | + <div class="step-icon"> |
| 165 | + <KeyRound size={20} /> |
| 166 | + </div> |
| 167 | + </div> |
| 168 | + <div class="step-body"> |
| 169 | + <h3 class="step-title">Certificate Renewal</h3> |
| 170 | + <p class="step-text"> |
| 171 | + When a certificate expires, the TPP must register a new Consumer with the new certificate. |
| 172 | + Copy rate limits and scopes from the old Consumer to the new one. |
| 173 | + </p> |
| 174 | + </div> |
| 175 | + </div> |
| 176 | + </div> |
| 177 | + </section> |
| 178 | + |
| 179 | + <section class="section info-section"> |
| 180 | + <h2 class="section-title">Consumer vs User vs Entitlement</h2> |
| 181 | + <p class="section-text"> |
| 182 | + A <strong>Consumer</strong> represents the App. A <strong>User</strong> is the person |
| 183 | + using the App. An <strong>Entitlement</strong> is a Role granted to a User (optionally |
| 184 | + scoped to a specific bank). When an API call is made, OBP checks both the Consumer's |
| 185 | + scopes and the User's Entitlements to determine access. |
| 186 | + </p> |
| 187 | + </section> |
| 188 | + </div> |
| 189 | + </div> |
| 190 | +</div> |
| 191 | + |
| 192 | +<style> |
| 193 | + .container { max-width: 1200px; } |
| 194 | + .breadcrumb { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; } |
| 195 | + .breadcrumb-link { color: #3b82f6; text-decoration: none; } |
| 196 | + .breadcrumb-link:hover { text-decoration: underline; } |
| 197 | + :global([data-mode="dark"]) .breadcrumb-link { color: rgb(var(--color-primary-400)); } |
| 198 | + .breadcrumb-separator { color: #9ca3af; } |
| 199 | + :global([data-mode="dark"]) .breadcrumb-separator { color: var(--color-surface-500); } |
| 200 | + .breadcrumb-current { color: #6b7280; } |
| 201 | + :global([data-mode="dark"]) .breadcrumb-current { color: var(--color-surface-400); } |
| 202 | +
|
| 203 | + .panel { background: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); overflow: hidden; } |
| 204 | + :global([data-mode="dark"]) .panel { background: rgb(var(--color-surface-800)); } |
| 205 | + .panel-header { padding: 2rem; border-bottom: 1px solid #e5e7eb; } |
| 206 | + :global([data-mode="dark"]) .panel-header { border-bottom-color: rgb(var(--color-surface-700)); } |
| 207 | + .header-content { display: flex; align-items: center; gap: 1rem; } |
| 208 | + .header-icon { display: flex; align-items: center; justify-content: center; width: 64px; height: 64px; background: #eff6ff; color: #3b82f6; border-radius: 12px; flex-shrink: 0; } |
| 209 | + :global([data-mode="dark"]) .header-icon { background: rgba(59,130,246,0.2); color: rgb(var(--color-primary-400)); } |
| 210 | + .panel-title { font-size: 1.5rem; font-weight: 700; color: #111827; margin: 0; } |
| 211 | + :global([data-mode="dark"]) .panel-title { color: var(--color-surface-100); } |
| 212 | + .panel-subtitle { font-size: 0.875rem; color: #6b7280; margin-top: 0.25rem; } |
| 213 | + :global([data-mode="dark"]) .panel-subtitle { color: var(--color-surface-400); } |
| 214 | + .panel-content { padding: 2rem; } |
| 215 | +
|
| 216 | + .intro-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; margin-bottom: 2rem; } |
| 217 | + .section { margin-bottom: 0; } |
| 218 | + .workflow-section, .info-section { padding-top: 1.5rem; border-top: 1px solid #e5e7eb; } |
| 219 | + :global([data-mode="dark"]) .workflow-section, :global([data-mode="dark"]) .info-section { border-top-color: rgb(var(--color-surface-700)); } |
| 220 | + .info-section { margin-top: 1.5rem; } |
| 221 | + .section-title { font-size: 1.125rem; font-weight: 700; color: #111827; margin: 0 0 0.75rem 0; } |
| 222 | + :global([data-mode="dark"]) .section-title { color: var(--color-surface-100); } |
| 223 | + .section-text { font-size: 0.875rem; color: #4b5563; line-height: 1.6; margin: 0; } |
| 224 | + :global([data-mode="dark"]) .section-text { color: var(--color-surface-300); } |
| 225 | + .section-text code { background: #f3f4f6; padding: 0.125rem 0.375rem; border-radius: 4px; font-size: 0.8125rem; } |
| 226 | + :global([data-mode="dark"]) .section-text code { background: rgb(var(--color-surface-700)); color: var(--color-surface-200); } |
| 227 | +
|
| 228 | + .concepts-list { display: flex; flex-direction: column; gap: 0.75rem; } |
| 229 | + .concept-item { padding: 0.75rem; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 6px; } |
| 230 | + :global([data-mode="dark"]) .concept-item { background: rgb(var(--color-surface-700)); border-color: rgb(var(--color-surface-600)); } |
| 231 | + .concept-title { font-size: 0.8125rem; font-weight: 600; color: #111827; margin: 0 0 0.25rem 0; } |
| 232 | + :global([data-mode="dark"]) .concept-title { color: var(--color-surface-100); } |
| 233 | + .concept-text { font-size: 0.75rem; color: #4b5563; line-height: 1.4; margin: 0; } |
| 234 | + :global([data-mode="dark"]) .concept-text { color: var(--color-surface-300); } |
| 235 | +
|
| 236 | + .steps-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 1rem; } |
| 237 | + .step-card { display: flex; flex-direction: column; padding: 1rem; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 8px; } |
| 238 | + :global([data-mode="dark"]) .step-card { background: rgb(var(--color-surface-700)); border-color: rgb(var(--color-surface-600)); } |
| 239 | + .step-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; } |
| 240 | + .step-number { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; background: #3b82f6; color: white; border-radius: 50%; font-size: 0.75rem; font-weight: 700; flex-shrink: 0; } |
| 241 | + .step-icon { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: #eff6ff; color: #3b82f6; border-radius: 6px; flex-shrink: 0; } |
| 242 | + :global([data-mode="dark"]) .step-icon { background: rgba(59,130,246,0.2); color: rgb(var(--color-primary-400)); } |
| 243 | + .step-body { flex: 1; display: flex; flex-direction: column; } |
| 244 | + .step-title { font-size: 0.875rem; font-weight: 600; color: #111827; margin: 0 0 0.375rem 0; } |
| 245 | + :global([data-mode="dark"]) .step-title { color: var(--color-surface-100); } |
| 246 | + .step-text { font-size: 0.75rem; color: #4b5563; line-height: 1.5; margin: 0; flex: 1; } |
| 247 | + :global([data-mode="dark"]) .step-text { color: var(--color-surface-300); } |
| 248 | + .step-text code { background: #e5e7eb; padding: 0.0625rem 0.25rem; border-radius: 3px; font-size: 0.6875rem; } |
| 249 | + :global([data-mode="dark"]) .step-text code { background: rgb(var(--color-surface-600)); color: var(--color-surface-200); } |
| 250 | + .step-link { display: inline-block; margin-top: 0.5rem; font-size: 0.75rem; font-weight: 600; color: #3b82f6; text-decoration: none; } |
| 251 | + .step-link:hover { text-decoration: underline; } |
| 252 | + :global([data-mode="dark"]) .step-link { color: rgb(var(--color-primary-400)); } |
| 253 | +
|
| 254 | + @media (max-width: 1024px) { .steps-grid { grid-template-columns: repeat(3, 1fr); } } |
| 255 | + @media (max-width: 768px) { .intro-grid { grid-template-columns: 1fr; gap: 1.5rem; } .steps-grid { grid-template-columns: repeat(2, 1fr); } } |
| 256 | + @media (max-width: 640px) { .header-content { flex-direction: column; text-align: center; } .steps-grid { grid-template-columns: 1fr; } } |
| 257 | +</style> |
0 commit comments