Skip to content

Commit 9ac26c7

Browse files
authored
VIT-7699: BYOO Sharing Credentials guide draft (#277)
* VIT-7699: BYOO Sharing Credentials guide draft * Tweak * Note on JWT * Update docs to match current design * Update
1 parent 011fcbd commit 9ac26c7

File tree

3 files changed

+188
-2
lines changed

3 files changed

+188
-2
lines changed

docs/mint.json

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,14 @@
172172
"wearables/connecting-providers/launching_link",
173173
"wearables/connecting-providers/auth_types",
174174
"wearables/connecting-providers/errors",
175-
"wearables/connecting-providers/custom_widget",
176-
"wearables/connecting-providers/bring_your_own_oauth"
175+
"wearables/connecting-providers/custom_widget"
176+
]
177+
},
178+
{
179+
"group": "Bring Your Own OAuth",
180+
"pages": [
181+
"wearables/connecting-providers/bring-your-own-oauth/overview",
182+
"wearables/connecting-providers/bring-your-own-oauth/sharing-credentials"
177183
]
178184
},
179185
{
@@ -1038,6 +1044,10 @@
10381044
{
10391045
"source": "/api-reference/introspection/:subpaths*",
10401046
"destination": "/api-reference/data/introspection/:subpaths*"
1047+
},
1048+
{
1049+
"source": "/wearables/connecting-providers/bring_your_own_oauth",
1050+
"destination": "/wearables/connecting-providers/bring-your-own-oauth/overview"
10411051
}
10421052
]
10431053
}

docs/wearables/connecting-providers/bring_your_own_oauth.mdx renamed to docs/wearables/connecting-providers/bring-your-own-oauth/overview.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: "Bring Your Own OAuth"
3+
sidebarTitle: "Overview"
34
---
45

56
import BYOO from '/snippets/byoo.mdx';
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
---
2+
title: "Sharing Credentials"
3+
version: "beta"
4+
---
5+
6+
## Audience
7+
8+
This guide is dedicated to Vital customers looking to share the usage of their OAuth Client Credentials
9+
between Vital [Bring Your Own OAuth](/wearables/connecting-providers/bring-your-own-oauth/overview) and their
10+
existing production systems.
11+
12+
This guide is not applicable if you:
13+
14+
* do not have existing OAuth Client Credentials; or
15+
* can configure your OAuth Client Credentials to point exclusively at Vital.
16+
17+
18+
## Background
19+
20+
Many providers use OAuth 2.0, in which each partner entity is registered as a confidential application.
21+
Each application is issued one set of OAuth client credentials (client ID + secret).
22+
23+
As a Cross-Site Request Forgery (CSRF) mitigation, they also typically require every application to pre-register
24+
a Redirect URI. The `/authorize` flow would then validate inbound requests against the Redirect URI on record.
25+
26+
Most providers allow exactly one Redirect URI registration per application, which means the Redirect URI
27+
must be one of:
28+
29+
* your existing OAuth callback endpoint — under a domain you control; or
30+
* the Vital OAuth callback endpoint.
31+
32+
It cannot be both.
33+
34+
To avoid disruption to your production systems, we recommend sticking with your existing OAuth callback endpoint.
35+
36+
<Info>
37+
Some providers, like Google Fit, also require domain verification. So it further restricts
38+
the Redirect URI to point at a domain you control.
39+
</Info>
40+
41+
## Challenge
42+
43+
Because of the Redirect URI restriction as described above, you must take some extra steps if you intend to
44+
share your OAuth Client Credentials between Vital [Bring Your Own OAuth](/wearables/connecting-providers/bring-your-own-oauth/overview) and your
45+
existing production systems.
46+
47+
48+
## Solution
49+
50+
Vital recommends
51+
52+
```mermaid
53+
sequenceDiagram
54+
participant Vital Link
55+
participant Your API
56+
participant BYOO Provider
57+
actor User Agent
58+
autonumber
59+
Vital Link-->>User Agent: OAuth 2.0 Authorization Request URL
60+
User Agent->>BYOO Provider: Navigate to URL (1)
61+
BYOO Provider-->>User Agent: Prompt
62+
User Agent-->>BYOO Provider: Approve or Deny
63+
BYOO Provider->>Your API: Redirect
64+
Your API->>Vital Link: Redirect
65+
```
66+
67+
68+
<Steps>
69+
70+
<Step title="Keep your current OAuth application settings">
71+
72+
The Redirect URI in your OAuth application settings should continue to point at your
73+
existing OAuth callback endpoint.
74+
75+
</Step>
76+
77+
<Step title="Extend your existing OAuth callback endpoint with Vital awareness">
78+
79+
Your OAuth callback endpoints can rely on the `state` query parameter to differentiate the request
80+
origin, i.e., whether it is from Vital or from your own production systems.
81+
82+
OAuth requests originated from Vital would have the **Vital Link Token** as the `state` query parameter.
83+
Vital Link Token is a JSON Web Token (JWT), so you can use the _unverified claims_ of the JWT as a discriminator.
84+
85+
When you detect a valid Vital Link Token, perform a `307 Temporary Redirect`
86+
to the [Vital OAuth callback endpoint](#vital-oauth-callback-endpoint-url) and passing on _all_ the URL query parameters.
87+
88+
The exact JWT structure of the Vital Link Token is as follows:
89+
90+
91+
<AccordionGroup>
92+
<Accordion title="Encoding" defaultOpen>
93+
A JSON Web Token (JWT).
94+
95+
<Warning>
96+
You need not verify the signature of this JWT.
97+
98+
To prevent Cross-Site Request Forgery attacks, you must still check that the `aud` claim matches the
99+
expected [Vital Link API Base URL](#vital-link-api-base-url).
100+
</Warning>
101+
102+
</Accordion>
103+
<Accordion title="Claim payload schema" defaultOpen>
104+
| Key | Value |
105+
| ----------------------- | ----------------------------------------------- |
106+
| `aud` | Vital Link API Base URL |
107+
| `sub` | Vital Link Session ID |
108+
| `team_id` | Vital Team ID |
109+
| `user_id` | Vital User ID |
110+
</Accordion>
111+
<Accordion title="Vital Link API Base URL" defaultOpen>
112+
| Environment | Base URL |
113+
| ----------------------- | -------- |
114+
| Production US | `https://api.tryvital.io/v2/link`
115+
| Production EU | `https://api.eu.tryvital.io/v2/link`
116+
| Sandbox US | `https://api.sandbox.tryvital.io/v2/link`
117+
| Sandbox EU | `https://api.sandbox.eu.tryvital.io/v2/link`
118+
</Accordion>
119+
<Accordion title="Vital OAuth callback endpoint URL" defaultOpen>
120+
| Environment | Base URL |
121+
| ----------------------- | -------- |
122+
| Production US | `https://api.tryvital.io/v2/link/connect/{PROVIDER}`
123+
| Production EU | `https://api.eu.tryvital.io/v2/link/connect/{PROVIDER}`
124+
| Sandbox US | `https://api.sandbox.tryvital.io/v2/link/connect/{PROVIDER}`
125+
| Sandbox EU | `https://api.sandbox.eu.tryvital.io/v2/link/connect/{PROVIDER}`
126+
</Accordion>
127+
<Accordion title="Example" defaultOpen>
128+
```python Python (FastAPI)
129+
import fastapi
130+
from urllib.parse import urlencode
131+
132+
VITAL_LINK_BASE_URL = "https://api.tryvital.io/v2/link"
133+
134+
@router.get("/oauth_callback/fitbit")
135+
def handle_oauth_callback(
136+
request: fastapi.Request,
137+
state: Annotated[str, fastapi.Query()],
138+
...,
139+
) -> fastapi.Response:
140+
state_string = base64.b64decode(state)
141+
142+
# Test if this is a JWT.
143+
# If so, try to extract the unverified claim payload, and see if this is
144+
# a Vital Link JWT.
145+
if (
146+
state_string.startswith('{"')
147+
and (state_parts := state_string.split(".", maxsplit=3))
148+
and len(state_parts) == 3
149+
and (unverified_claims := json.loads(state_parts[1]))
150+
and unverified_claims.get("aud") == VITAL_LINK_BASE_URL
151+
):
152+
query = urlencode(request.query_params)
153+
154+
return fastapi.RedirectResponse(f"{VITAL_LINK_BASE_URL}/connect/fitbit?{query}")
155+
156+
157+
# Not a Vital Link JWT. Fallback to existing logic
158+
return process_oauth_callback(...)
159+
160+
```
161+
</Accordion>
162+
</AccordionGroup>
163+
164+
</Step>
165+
166+
<Step title="Register your OAuth callback endpoint with Vital">
167+
168+
When you set your OAuth Client Credential through the [Set Team Custom Credentials](api-reference/org-management/team-custom-credentials/upsert-team-custom-credentials)
169+
endpoint, you must specify a Redirect URI override that points at your your OAuth callback endpoint.
170+
171+
When a Redirect URI override is present, Vital uses the override value you provided to initiate the OAuth authorization flow.
172+
173+
</Step>
174+
175+
</Steps>

0 commit comments

Comments
 (0)