Skip to content
Merged

Dpop #100

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions components/experimental-tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useState } from 'react'

interface ExperimentalTooltipProps {
placement?: 'top' | 'bottom' | 'left' | 'right'
}

export const ExperimentalTooltip: React.FC<ExperimentalTooltipProps> = ({
placement = 'top'
}) => {
const [isVisible, setIsVisible] = useState(false)

const getTooltipPosition = () => {
switch (placement) {
case 'bottom':
return 'top-full left-1/2 transform -translate-x-1/2 mt-1'
case 'left':
return 'right-full top-1/2 transform -translate-y-1/2 mr-1'
case 'right':
return 'left-full top-1/2 transform -translate-y-1/2 ml-1'
default: // top
return 'bottom-full left-1/2 transform -translate-x-1/2 mb-1'
}
}

const getArrowPosition = () => {
switch (placement) {
case 'bottom':
return 'bottom-full left-1/2 transform -translate-x-1/2 border-l-transparent border-r-transparent border-t-transparent border-b-gray-800'
case 'left':
return 'left-full top-1/2 transform -translate-y-1/2 border-t-transparent border-b-transparent border-r-transparent border-l-gray-800'
case 'right':
return 'right-full top-1/2 transform -translate-y-1/2 border-t-transparent border-b-transparent border-l-transparent border-r-gray-800'
default: // top
return 'top-full left-1/2 transform -translate-x-1/2 border-l-transparent border-r-transparent border-b-transparent border-t-gray-800'
}
}

return (
<span
className="relative inline-block"
onMouseEnter={() => setIsVisible(true)}
onMouseLeave={() => setIsVisible(false)}
aria-label="tooltip"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="-mt-3 inline h-3 w-3"
>
<path
fillRule="evenodd"
d="M10.5 3.798v5.02a3 3 0 0 1-.879 2.121l-2.377 2.377a9.845 9.845 0 0 1 5.091 1.013 8.315 8.315 0 0 0 5.713.636l.285-.071-3.954-3.955a3 3 0 0 1-.879-2.121v-5.02a23.614 23.614 0 0 0-3 0Zm4.5.138a.75.75 0 0 0 .093-1.495A24.837 24.837 0 0 0 12 2.25a25.048 25.048 0 0 0-3.093.191A.75.75 0 0 0 9 3.936v4.882a1.5 1.5 0 0 1-.44 1.06l-6.293 6.294c-1.62 1.621-.903 4.475 1.471 4.88 2.686.46 5.447.698 8.262.698 2.816 0 5.576-.239 8.262-.697 2.373-.406 3.092-3.26 1.47-4.881L15.44 9.879A1.5 1.5 0 0 1 15 8.818V3.936Z"
clipRule="evenodd"
/>
</svg>

{isVisible && (
<div
className={`absolute z-50 px-2 py-1 text-xs text-white bg-gray-800 rounded shadow-lg whitespace-nowrap ${getTooltipPosition()}`}
>
Experimental
<div
className={`absolute w-0 h-0 border-4 ${getArrowPosition()}`}
/>
</div>
)}
</span>
)
}
5 changes: 3 additions & 2 deletions linkinator.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"http://localhost:3000",
"https://blog.hello.dev/*",
"https://blog.hello.coop/*",
"https://github.com/*"
"https://github.com/*",
"https://cursor.com/*"
]
}
}
3 changes: 3 additions & 0 deletions pages/docs/oidc.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Cards, Card } from 'nextra/components'
import { AuthRequestIcon, AuthResponseIcon, IDTokenIcon, ConfigIcon, ErrorIcon, VerificationIcon } from 'components/icons'
import { ExperimentalTooltip } from 'components/experimental-tooltip'

# OpenID Connect

Expand All @@ -9,6 +10,8 @@ The section of the documentation describes Hellō implementation of OpenID Conne

The Hellō OpenID Configuration is at [https://issuer.hello.coop/.well-known/openid-configuration](https://issuer.hello.coop/.well-known/openid-configuration).

Hellō also supports [OpenID Connect Key Binding](https://github.com/dickhardt/openid-key-binding) <ExperimentalTooltip /> for cryptographically bound ID tokens using RFC 9449 DPoP.

NOTE: The Hellō Issuer is `https://issuer.hello.coop` and is NOT `https://wallet.hello.coop`. This simplifies a separation of concerns per the [Hellō Protocol]()

<Cards>
Expand Down
2 changes: 2 additions & 0 deletions pages/docs/oidc/request.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Callout } from 'nextra/components'
import { ExperimentalTooltip } from 'components/experimental-tooltip'

# Authentication Request

Expand Down Expand Up @@ -31,6 +32,7 @@ The **request URL** is `https://wallet.hello.coop/authorize` and a query with th
|`prompt`<br/>*optional*|A space delimited list. Accepted values include:|
| | - `login` will require the user to re-authenticate at their login provider|
| | - `consent` will require the user to review, and potentially change, released claims|
|`dpop_jkt` <ExperimentalTooltip />|JWK Thumbprint of the DPoP public key using SHA-256. Required when using `dpop` scope.|

### Hellō Parameters

Expand Down
41 changes: 23 additions & 18 deletions pages/docs/oidc/token.mdx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ExperimentalTooltip } from 'components/experimental-tooltip'

# ID Token

An ID Token is a JSON Web Token (JWT) [RFC 7519](https://www.rfc-editor.org/rfc/rfc7519.html) that has claims per [OpenID Connect §2](https://openid.net/specs/openid-connect-core-1_0.html#IDToken).<br/>In the following example of a raw ID Token:
Expand All @@ -8,39 +10,41 @@ An ID Token is a JSON Web Token (JWT) [RFC 7519](https://www.rfc-editor.org/rfc/
### Compact Format

```ansi
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjIwMjQtMDctMDRUMjI6MjA6MzkuMjg2Wl8xZTAYTIzIn00.ey
Jpc3MiOiJodHRwczovL2lzc3Vlci5oZWxsby5jb29wIiwiYXVkIjoiYXBwX0hlbGxvRGV2ZWxvcGVyUGxheWdyb3VuZF9Jc
TIiLCJub25jZSI6IjE4OTM4Nzc4ODk0MjMyMzE5NTEiLCJqdGkiOiJqdGlfd0ZHdWdpQXp1WVBxTkh2ajJuUnI2enhvX0lq
biIsInN1YiI6IjI2NWE1NmEzLWFjMDQtNDcxYy04MzJlLTVlMTZhNzRlYjFmMSIsIm5hbWUiOiJEaWNrIEhhcmR0IiwicGl
jdHVyZSI6Imh0dHBzOi8vcGljdHVyZXMuaGVsbG8uY29vcC9yLzdjOWFlMTkyLTM2M2MtNDA5ZS05NDVhLWYyNWU1ODMzZT
M3NS5qcGVnIiwiZW1haWwiOiJkaWNrLmhhcmR0QGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpYXQiOjE3M
jk3MDkwNjcsImV4cCI6MTcyOTcwOTM2N30.NT8d0wSuHqmcaUbiKPYAusalMYJcGj8w726pE8WvfYwlDtms3tMovj7U9eGTwqQykf_tlbz
IrJ4m6KofsriScGrm_2RAiaZTfk3srbWu21WhaLxqHhkbqu0lntNzkgVCjROv_CQ5YcsXh4L0aAJmKpkL3lVATMQSMxBUY0
bnmDT5jKO2ldxse4WAGSYssSUy1O6YzsjcvRpL3shuTYNkx2NMrqBO2kdTEuFL3IeH8cRFI6x52w7TJKJXs0n8qRVdaul64
URRrQrhTidVfCdFwswdrUZ3pdyhiTLlhC9Kn9Dtk5F3KVd0SEuzcb9cBJzNvV-vO-j7b-siqUJV4du3Q
eyJhbGciOiJSUzI1NiIsInR5cCI6ImRwb3AraWRfdG9rZW4iLCJraWQiOiIyMDI1LTAxLTE1VDE2OjU2OjQ5LjY2OFpfNzM1LTFjNSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5oZWxsby5jb29wIiwiYXVkIjoiYXBwX0hlbGxvRGV2ZWxvcGVyUGxheWdyb3VuZF9JcTIiLCJub25jZSI6ImZhMzI5NGY4LTIyMmEtNDcwMS04YmUyLWY1Y2YwZDY1NThmZSIsImp0aSI6Imp0aV9wdXNLQjFZcjhRUk9qQ0FqbGVoNU1yZDFfWmZSIiwic3ViIjoiMjY1YTU2YTMtYWMwNC00NzFjLTgzMmUtNWUxNmE3NGViMWYxIiwidGVuYW50IjoicGVyc29uYWwiLCJuYW1lIjoiRGljayBIYXJkdCIsInBpY3R1cmUiOiJodHRwczovL3BpY3R1cmVzLmhlbGxvLmNvb3AvYXZhdGFyLzFjOGNlMzZlMDczNWFhY2ViYmUyZDUxNjk0ODJjODY3P3M9MjU2LGQ9aWRlbnRpY29uIiwiZW1haWwiOiJkaWNrLmhhcmR0QGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJpYXQiOjE3NTUyNDkzMTQsImV4cCI6MTc1NTI0OTYxNCwiY25mIjp7Imp3ayI6eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6IkxBT25iQU1FRWROYS16UzFoeG9WWTVIZkp5aWFLRlNIVjVfRWJBY0lBdDQiLCJ5IjoiUDh1QkliNmYxX2VQUU13QjcwS0lVaEowV2pXdjJQQ1BLcjJwVlhpTndROCJ9fX0.NT8d0wSuHqmlpvNCaNaQRSH-XSXg_YDKwJfprtpkr7L2DanDUhXRZ8uAlDyOdDXJm6weEXrHiq9UQC8WGatmQ8V__jeTntPe8njID3MrfSY5jtS3AATfACC8oOqt_NPExW3noKBMjzLP50aa8JPBdu39YBnfOA78tL4K0GcCNDk9ctKf8dJktb4URnl4n7yYpJ_VCFp44bujpoxyr-SXBzZn8Zo2PY0oOApnAICiLs0iS9KhAegEP55Vo4m9Y2uER7YtIGA2S1iUwBbgx0XoFeIn4jQtMNydaksmbPqZFtAFNUKUM85KFnKAx_OMrhqEU0b3lc4kbR1Na_orr4Ucm1e-_pYk_UlOg
```

### Decoded ID Token

Note: The following example includes the `cnf` claim that appears when the `dpop` scope is requested:

```json
{
"header": {
"alg":"RS256",
"typ":"JWT",
"kid":"2024-07-04T22:20:39.286Z_1e0-a23"
"alg": "RS256",
"typ": "dpop+id_token",
"kid": "2025-01-15T16:56:49.668Z_735-1c5"
},
"payload": {
"iss": "https://issuer.hello.coop",
"aud": "app_HelloDeveloperPlayground_Iq2",
"nonce": "1893877889423231951",
"jti": "jti_wFGugiAzuYPqNHvj2nRr6zxo_Ijn",
"nonce": "fa3294f8-222a-4701-8be2-f5cf0d6558fe",
"jti": "jti_pusKB1Yr8QROjCAjleh5Mrd1_ZfR",
"sub": "265a56a3-ac04-471c-832e-5e16a74eb1f1",
"tenant": "personal",
"name": "Dick Hardt",
"picture": "https://pictures.hello.coop/r/7c9ae192-363c-409e-945a-f25e5833e375.jpeg",
"picture": "https://pictures.hello.coop/avatar/1c8ce36e0735aacebbe2d5169482c867?s=256,d=identicon",
"email": "dick.hardt@gmail.com",
"email_verified": true,
"iat": 1729709067,
"exp": 1729709367
"iat": 1755249314,
"exp": 1755249614,
"cnf": {
"jwk": {
"kty": "EC",
"crv": "P-256",
"x": "LAOnbAMEEdNa-zS1hxoVY5HfJyiaKFSHV5_EbAcIAt4",
"y": "P8uBIb6f1_ePQMwB70KIUhJ0WjWv2PCPKr2pVXiNwQ8"
}
}
}
}
```
Expand Down Expand Up @@ -87,3 +91,4 @@ URRrQrhTidVfCdFwswdrUZ3pdyhiTLlhC9Kn9Dtk5F3KVd0SEuzcb9cBJzNvV-vO-j7b-siqUJV4du3Q
|`iat`|The time the ID Token was issued in [Epoch time](https://en.wikipedia.org/wiki/Unix_time)|
|`exp`|The time the ID Token expires.<br/>Hellō sets the expiry to be 5 minutes (300 seconds) after `iat`|
|`tenant`|The Hellō identifier for the organization. Similar to `sub`, use this to identify the organization. Set to `personal` for personal accounts.|
|`cnf` <ExperimentalTooltip />|Confirmation claim containing the public key bound to the ID token when using `dpop` scope.|
3 changes: 3 additions & 0 deletions pages/docs/scopes.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Callout } from 'nextra/components'
import { ExperimentalTooltip } from 'components/experimental-tooltip'

# Hellō Scopes

Expand Down Expand Up @@ -35,6 +36,8 @@ Following are the scopes currently supported by Hellō. At the top are the stand
|`phone`|A verified `phone_number` claim. <br/>`phone_number_verified=true` will always be returned. <br/>*see note below*|
|`picture`|A URL to a profile picture. [See FAQ 13](/faqs/#13-what-can-i-do-with-the-picture-url-i-receive) for details|
|`profile`|equivalent to `name`, `email`, and `picture`|
|**Experimental**|**The following scopes are currently experimental**|
|`dpop` <ExperimentalTooltip/>|Enables key binding for ID tokens using RFC 9449 DPoP.|

*NOTE: We previously returned `phone` and `phone_verified` claims and now return `phone_number` and `phone_number_verified` claims per [OIDC Standard Claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims)*

Expand Down
52 changes: 26 additions & 26 deletions public/ai-sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,157 +6,157 @@

<url>
<loc>https://www.hello.dev/markdown/docs/docs.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>1.0</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/admin-mcp.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/apis/admin.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/apis/invite.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/apis/quickstart.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/apis/wallet.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/apis/web-client.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/buttons.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/getting-started.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.9</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/quickstarts.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.9</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/quickstarts/express.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/quickstarts/fastify.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/quickstarts/nextjs.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/quickstarts/wordpress.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/scopes.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.8</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/config.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/environment.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/express.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/faqs.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/fastify.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/helper.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/nextjs.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/quickstart.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/react.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/svelte.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

<url>
<loc>https://www.hello.dev/markdown/docs/docs/sdks/vue.md</loc>
<lastmod>2025-08-04T17:39:20.481Z</lastmod>
<lastmod>2025-08-15T09:26:48.888Z</lastmod>
<priority>0.7</priority>
</url>

Expand Down
Loading