Integrating Hellō

Now that you have registered your application at Hellō and added the button to your page, let's complete the integration.

  1. Connect the button click to creating a Request URL
  2. Create a Request URL
  3. Make the request by redirecting the user's browser to the Request URL
  4. Receive the response
  5. Validate the ID Token

At this point, you know which user you are interacting with, and have any of the claims you requested.

1. Respond to Button Click

The button to initiate registration / login is either charcoal (#303030) on white, or white on charcoal. Note that the Hellō logo ō is a o with a macronopen in new window. You can use the ō character if you have <meta charset="UTF-8"> in your page <head> element (best practice for HTML documents). For reference, the UTF-8 encoding is0xC5 0x8D and the HTML markup is &omacr;.

<button onclick="login(event)" class="hello-btn hello-btn-black-on-light"></button>

<script>
  async function login(event){
    event.target.classList.add('hello-btn-loader') // Show spinner
    event.target.disabled = true // Disable button
    const requestURL = await fetch()  // Fetch the request URL from your backend
    window.location.href = requestURL // See next step for creating request URL
  }
</script>

2. Create Request URL

The request URL is https://wallet.hello.coop/authorize and a query with the following parameters

ParameterDescription
client_idThe client_id for your app from console.hello.coopopen in new window
redirect_uriOne of the redirect_uri values you registered for your app
scopeThe openid scope and zero or more scopes listed at Hellō Claims
nonce
A unique string that will be included in the signed ID Token. This links the ID Token to your request
response_typeSet this to id_token.
While Hellō supports the code flow to be compatible with legacy platforms, the id_token flow is simpler as it does not require implementing PKCE - RFC7636open in new window
response_mode
(optional)
Either fragment or form_post. Defaults to fragment. This parameter tells Hellō how you would like to receive the response.
See 4. Receive Response for details
state
(optional)
A value representing the state of your application that will be returned as a parameter in the response

Here is the request used by the GreenfieldDemo app
(line feeds added for readability)

https://wallet.hello.coop/authorize
?client_id=3574f001-0874-4b20-bffd-8f3e37634274
&nonce=b957cea0-f159-4390-ba48-5c5d7e943ea4
&redirect_uri=https://greenfielddemo.com/
&response_mode=fragment
&response_type=id_token
&scope=name+nickname+email+picture+openid

There is no difference between a request to register the user, or log in the user. If the user has previously released the same requested scopes to your app, they will not be prompted to release it again. If you have changed with scopes you are requesting, or the profile_update is provided, the user will be prompted to select what to release.

Hellō supports response_type=id_tokenopen in new window and response_type=codeopen in new window.

You can let users update their profile at Hellō as well by setting the profile_update scope which will prompt the user to decide what information to change.

3. Make Request

Cause the user's browser to load the request URL you created in Step 2. Here are some examples:

  • Set window.location.href with JavaScript
window.location.href = "https://wallet.hello.coop/authorize?..."
  • An <a> tag with an href to the requestURL
<a href="https://wallet.hello.coop/authorize?..." /> ... </a>
  • HTTP 302 redirect from the server
HTTP/1.1 302 Found
Location: https://wallet.hello.coop/authorize?...

The user will then interact with Hellō, when finished, they will be redirected back to your application with either an ID Token, or an error response.

4. Receive Response

Your app will receive the response as either fragment query parameters to the provided redirect_uri if response_mode=fragment, or in application/x-www-form-urlencoded format in an HTTP POST to the provided redirect_uri if response_mode=form_post. If the user approved the request, the response will contain an id_token parameter, and a state parameter if provided. See Request Errors for unsuccessful responses.

Fragment Example (response_mode=fragment)

https://greenfielddemo.com/#id_token=eyJhbGciOiJSUzI1...rest_of_ID_Token

The following sample JavaScript will acquire the id_token from the fragment

const params = new URLSearchParams(window.location.hash.substring(1))
const id_token = params.get('id_token') // eyJhbGciOiJSUzI1...rest_of_ID_Token

Form Post Example (response_mode=form_post)

POST / HTTP/1.1
Host: greenfielddemo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: XX

id_token=eyJhbGciOiJSUzI1...rest_of_ID_Token

Note that a fragment response is limited to the maximum URL length supported by the user's browser. Using form_post does not have that constraint, and a larger ID Token can be returned to your application.

An ID Token is a JSON Web Token (JWT) RFC 7519open in new window that has claims per OpenID Connect §2open in new window.
In the following example of a raw ID Token:

  • purple is the header that describes the JWT;
  • yellow is the payload of the ID Token; and
  • green is the signature of the JWT.

Example ID Token

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJmZWQzOTBlLThkMmYtNDE3NC1iMTM2LTBhN2U1MmM5MWUxZSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5oZWxsby5jb29wIiwiYXVkIjoiMzU3NGYwMDEtMDg3NC00YjIwLWJmZmQtOGYzZTM3NjM0Mjc0Iiwibm9uY2UiOiJiOTU3Y2VhMC1mMTU5LTQzOTAtYmE0OC01YzVkN2U5NDNlYTQiLCJqdGkiOiI4YWQxNjdkMS1kMTcwLTQ2YzktYjNjNi00N2RkYTczNWE0ZTMiLCJzdWIiOiJmOWUyMWYwZi05ZjBlLTQxYjAtYTU4Yi1jMmQ2M2JjYzdiNGYiLCJzY29wZSI6WyJuYW1lIiwibmlja25hbWUiLCJwaWN0dXJlIiwiZW1haWwiLCJvcGVuaWQiXSwibmFtZSI6IkRpY2sgSGFyZHQiLCJuaWNrbmFtZSI6IkRpY2siLCJwaWN0dXJlIjoiaHR0cHM6Ly9jZG4uaGVsbG8uY29vcC9pbWFnZXMvZGVmYXVsdC1waWN0dXJlLnBuZyIsImVtYWlsIjoiZGljay5oYXJkdEBoZWxsby5jb29wIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlhdCI6MTY0NTY0MTI4NywiZXhwIjoxNjQ1NjQ0ODg3fQ.vppFPOM1kE6qs4s0DbWVGn80P0TOHmE4tmzg78RrJyz4732n5PH4aEgVIqQrKHkSYO8CptA1BhOBW1oRg8YrbWnJP2o8O__tLW8W1j8BzasW1td_Q_zuWqzz1XemqpLbPVKcS5MNZkYbJXLwXUAgmCOyiWgVlsXRV5D2bWhe-MesbmIaW-Rdnhf_WFuLBjNM0FO3HpdeHkJ4-wFuzGQhgyputw1-V9yeUWkyqt-9uW09fJCHN6oE3ATA0BA3uGWoFpPRaMb4JKxNdlQkR7OAkofIe_dCLnM9xR5_zDSdGA8j45ufGaIy1poqbq8PIg52thaWunpwuc8zo9-kiMYuZw

Decoded ID Token (Header & Payload)

{
    "header": {
        "alg": "RS256",
        "typ": "JWT",
        "kid": "bfed390e-8d2f-4174-b136-0a7e52c91e1e"
    },
    "payload": {
        "iss": "https://issuer.hello.coop",
        "aud": "3574f001-0874-4b20-bffd-8f3e37634274",
        "nonce": "b957cea0-f159-4390-ba48-5c5d7e943ea4",
        "jti": "8ad167d1-d170-46c9-b3c6-47dda735a4e3",
        "sub": "f9e21f0f-9f0e-41b0-a58b-c2d63bcc7b4f",
        "scope": [
            "name",
            "nickname",
            "picture",
            "email",
            "openid"
        ],
        "name": "Dick Hardt",
        "nickname": "Dick",
        "picture": "https://cdn.hello.coop/images/default-picture.png",
        "email": "dick.hardt@hello.coop",
        "email_verified": true,
        "iat": 1669399110,
        "exp": 1669399410
    }
}

Payload Explanation

ClaimDescription
issIssuer of ID Token. Will always be https://issuer.hello.coop
audAudience of ID Token. Will be your client_id
nonceThe nonce that you optionally included in your request
jtiA unique identifier for this ID Token generated by Hellō
subThe subject of the ID Token. A unique identifier for the user. We recommend you use this to identify your users. See FAQ 10 for details.
scopeThe scopes returned by Hellō. See FAQ 11 for details.
nameThe user's full name or legal name.
nicknameThe user's preferred name, nickname, or username.
pictureA user's profile picture URL. See FAQ 12 for details.
emailThe user's email address.
email_verifiedIndicates email was verified. Will always be true from Hellō
iatThe time the ID Token was issued in Epoch timeopen in new window
expThe time the ID Token expires.
Hellō sets the expiry to be 5 minutes (300 seconds) after iat

Your application now has an ID Token for the user, but before using it, you need to ensure it is valid, and not an ID Token an attacker has passed to your application. The ID Token header and signature are part of the validation procedure.

5. Validate ID Token

You can validate the id_token by:

  1. Sending it back to the Hellō introspection API; or
  2. Perform validation yourself per OpenID Connect 3.1.3.7open in new window

5.1 Introspection

Hellō provides an introspection API per RFC 7662open in new window athttps://wallet.hello.coop/oauth/introspect that will examine the token, ensure it was from Hellō, has not expired, and return the payload.

No authentication is required to call the introspection endpoint. You MUST pass your client_id, and if you provided a nonce in the request URL, you MUST provide the nonce. The token, client_id, and optional nonce are sent as JSON.

Example Introspection JSON for earlier ID Token

{
  "token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImJmZWQzOTBlLThkMmYtNDE3NC1iMTM2LTBhN2U1MmM5MWUxZSJ9.eyJpc3MiOiJodHRwczovL2lzc3Vlci5oZWxsby5jb29wIiwiYXVkIjoiMzU3NGYwMDEtMDg3NC00YjIwLWJmZmQtOGYzZTM3NjM0Mjc0Iiwibm9uY2UiOiJiOTU3Y2VhMC1mMTU5LTQzOTAtYmE0OC01YzVkN2U5NDNlYTQiLCJqdGkiOiI4YWQxNjdkMS1kMTcwLTQ2YzktYjNjNi00N2RkYTczNWE0ZTMiLCJzdWIiOiJmOWUyMWYwZi05ZjBlLTQxYjAtYTU4Yi1jMmQ2M2JjYzdiNGYiLCJzY29wZSI6WyJuYW1lIiwibmlja25hbWUiLCJwaWN0dXJlIiwiZW1haWwiLCJvcGVuaWQiXSwibmFtZSI6IkRpY2sgSGFyZHQiLCJuaWNrbmFtZSI6IkRpY2siLCJwaWN0dXJlIjoiaHR0cHM6Ly9jZG4uaGVsbG8uY29vcC9pbWFnZXMvZGVmYXVsdC1waWN0dXJlLnBuZyIsImVtYWlsIjoiZGljay5oYXJkdEBoZWxsby5jb29wIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlhdCI6MTY0NTY0MTI4NywiZXhwIjoxNjQ1NjQ0ODg3fQ.vppFPOM1kE6qs4s0DbWVGn80P0TOHmE4tmzg78RrJyz4732n5PH4aEgVIqQrKHkSYO8CptA1BhOBW1oRg8YrbWnJP2o8O__tLW8W1j8BzasW1td_Q_zuWqzz1XemqpLbPVKcS5MNZkYbJXLwXUAgmCOyiWgVlsXRV5D2bWhe-MesbmIaW-Rdnhf_WFuLBjNM0FO3HpdeHkJ4-wFuzGQhgyputw1-V9yeUWkyqt-9uW09fJCHN6oE3ATA0BA3uGWoFpPRaMb4JKxNdlQkR7OAkofIe_dCLnM9xR5_zDSdGA8j45ufGaIy1poqbq8PIg52thaWunpwuc8zo9-kiMYuZw",
  "client_id":"3574f001-0874-4b20-bffd-8f3e37634274",
  "nonce":"b957cea0-f159-4390-ba48-5c5d7e943ea4"
}

Sample code to make API call

const id_token      // the ID Token received
const client_id     // your apps client_id
const nonce         // the nonce sent in the request

const url = 'https://wallet.hello.coop/oauth/introspect'
const params = {
  token: id_token,
  client_id: client_id,
  nonce: nonce
}
const options = {
    method: 'POST',
    mode: 'cors',
    cache: 'no-cache',
    headers: {'Content-type': 'application/x-www-form-urlencoded'},
    body: new URLSearchParams(params).toString()
}
const response = await fetch(url, options)
const json = await response.json()

Response JSON

If successfully validated, you will receive the ID Token payload with active:true to indicate it is an active token. If unsuccessful, you will receive an Introspection Error.

Sample Introspection Response

{
  "iss": "https://issuer.hello.coop",
  "aud": "3574f001-0874-4b20-bffd-8f3e37634274",
  "nonce": "b957cea0-f159-4390-ba48-5c5d7e943ea4",
  "jti": "8ad167d1-d170-46c9-b3c6-47dda735a4e3",
  "sub": "f9e21f0f-9f0e-41b0-a58b-c2d63bcc7b4f",
  "scope": [
      "name",
      "nickname",
      "picture",
      "email",
      "openid"
  ],
  "name": "Dick Hardt",
  "nickname": "Dick",
  "picture": "https://cdn.hello.coop/images/default-picture.png",
  "email": "dick.hardt@hello.coop",
  "email_verified": true,
  "iat": 1669399110,
  "exp": 1669399410,
  "active": true
}

5.2 Self Validation

There are many OpenID Connect libraries that include ID Token validation. The OpenID Foundation maintains a list hereopen in new window. Getting security right is HARD. We recommend you use a proven library and NOT write your own validation. We include the information below for reference.

Signature Verification Keys

Hellō provides OpenId Provider configuration information per OpenID Connect Discoveryopen in new window at:

https://issuer.hello.coop/.well-known/openid-configurationopen in new window

The jwks_uri property in the configuration file contains the URI for a JSON file containing the public keys in JSON Web Key format (RFC 7517open in new window) for verifying the signature per step (6) above.

Signature Verification Steps

Following are details for each ID Token validation step per OpenID Connect 3.1.3.7open in new window

  1. N/A - The ID Token is not encrypted
  2. The iss value MUST be https://issuer.hello.coop
  3. The aud value MUST be the client_id value provided in the request
  4. N/A - The ID Token will not contain multiple audiences
  5. There will not be an azp claim
  6. The ID Token is signed per JWS. The certificates are XXX
  7. The alg value will be RS256
  8. N/A - the alg is always RS256
  9. The current time must be before exp. Note the time is seconds since the Epoch, not milliseconds. ID Tokens expire after one hour.
  10. The iat may be used by the client if the one hour expiry is longer than is desirable by the client.
  11. The nonce is included if provided in the request.
  12. The acr Claim is not supported at this time.
  13. The auth_time Claim is not supported at this time.