Add Ocapi to a website

Requirements

  • Your website needs to be able to make a private HTTP request towards our service to validate the user response. This cannot be done by a pure Javascript frontend nor a static website.
  • As OCAPI displays images from public institutions, we need to validate the websites using this service. To include Ocapi in your website, please contact us through our contact form.

Workflow

You can learn more about the Ocapi usage workflow here

Workflow

API documentation

The OpenAPI documentation is available here.

Setup on your website

Information needed from Teklia

You'll need 4 information from Teklia:

  • The API base url to use for requests (it's currently https://ocapi.teklia.com)
  • The Javascript payload URL (it should be something like https://assets.teklia.com/ocapi/X.Y.Z/ocapi-X.Y.Z.js )
  • The credentials for your account on our backend:

  • a public id that will be used by your users

  • a private id that will only be used by your website to validate users

Current releases

Stable versions

  • Version 0.4.2 is the new stable version, maintained on https://ocapi.teklia.com/v2
  • Javascript payload
  • Integrity key is: +d6Pio4OPpZPYjbsMRIvD3gBOEgfVDpHCsf3kUJ4x0Kkp2fDc5V0eKm99K+RKqcn

You can use that version with the following tag on your website:

<script type="text/javascript" src="https://assets.teklia.com/ocapi/0.4.2/ocapi-0.4.2.js" integrity="sha384-+d6Pio4OPpZPYjbsMRIvD3gBOEgfVDpHCsf3kUJ4x0Kkp2fDc5V0eKm99K+RKqcn" crossorigin="anonymous"></script>
  • Version 0.3.2 is still maintained on https://ocapi.teklia.com/v1
  • Javascript payload
  • Integrity key is: JAI/JIuGPO6SWugsKs3nAWV8y8crq008SfxgJU5oLX1HPqAa08OLEDHeameEzj+t

You can use that version with the following tag on your website:

<script type="text/javascript" src="https://assets.teklia.com/ocapi/0.3.2/ocapi-0.3.2.js" integrity="sha384-JAI/JIuGPO6SWugsKs3nAWV8y8crq008SfxgJU5oLX1HPqAa08OLEDHeameEzj+t" crossorigin="anonymous"></script>

Old Stable versions

  • Version 0.3.1
  • Javascript payload
  • Integrity key is: 2/rlHeJ9ZjwSj+GtTzqopMMJSrkjwZWVmQDQuNzaeoIld+2G7gLBMGoMqOkIb8wj

You can use that version with the following tag on your website:

<script type="text/javascript" src="https://assets.teklia.com/ocapi/0.3.1/ocapi-0.3.1.js" integrity="sha384-2/rlHeJ9ZjwSj+GtTzqopMMJSrkjwZWVmQDQuNzaeoIld+2G7gLBMGoMqOkIb8wj" crossorigin="anonymous"></script>
  • Version 0.3.0
  • Javascript payload
  • Integrity key is: qGnt9bIFK/YpDlqH7dViACryhf0VZwPd9UE0wlKx+Zhf0F/Jyjx9vQ+H3R4fJuvZ

You can use that version with the following tag on your website:

<script type="text/javascript" src="https://assets.teklia.com/captchan/0.3.0/captchan-0.3.0.js" integrity="sha384-qGnt9bIFK/YpDlqH7dViACryhf0VZwPd9UE0wlKx+Zhf0F/Jyjx9vQ+H3R4fJuvZ" crossorigin="anonymous"></script>

This version does not support audio fallbacks.

Legacy version

  • Version 0.2.1
  • Javascript payload
  • Integrity key is: YQKwIw45el29YcGdymv07mSNmYnFNQjaVp70nRSuHePFKeuE8OvB7n9ep2Q0LSl2

You can use that version with the following tag on your website:

<script type="text/javascript" src="https://assets.teklia.com/captchan/0.2.1/captchan-0.2.1.js" integrity="sha384-YQKwIw45el29YcGdymv07mSNmYnFNQjaVp70nRSuHePFKeuE8OvB7n9ep2Q0LSl2" crossorigin="anonymous"></script>

This version is compatible with the legacy server

Adding the challenge to a form

Once you've picked a form on your website, you can easily add our captcha:

  1. Include our Javascript payload on your page, as referenced above in the Current releases section.
  2. Add a placeholder <div> element where you want the challenge to appear on your page
<div
  id="ocapi-challenge"
  data-ocapi-client="ocapiPublicID"
  data-ocapi-base-url="ocapiAPIUrl"
></div>

This element needs the ocapi-challenge (or captchan-challenge) identifier, and the provided public id as data-ocapi-client (or data-captchan-client) attribute.

The captchan-challenge identifier and the data-captchan-* attributes are deprecated.

Below are the IDS and attributes available for each version:

ID 0.2.1 0.3.0 0.3.1 0.3.2 0.4.0+
captchan-challenge yes yes yes yes yes
ocapi-challenge - - - yes yes
Attribute 0.2.1 0.3.0 0.3.1 0.3.2 0.4.0+
data-captchan-client yes yes yes yes yes
data-captchan-base-url - yes yes yes yes
data-ocapi-client - - - yes yes
data-ocapi-base-url - - - yes yes
data-ocapi-game-mode - - - - yes

The data-ocapi-game-mode attribute activates the game mode. The user will have to fill in several captchas successively. At the end, the final score is displayed and the player can play again.

Please note that this element must be inside a <form> to be able to validate the user: an hidden <input> will be added.

⚠ Never include the private id on that page.

Validated challenge (only for version >= 0.3.2)

Each time a challenge is validated, the ocapi-challenge-validated event is sent to the document Javascript reference. Its detail contains a map including the ID of the validated challenge. Here is an example of the event detail in json:

{
  "challenge_id" : "aChallengeId"
}

And here is an example of a script that receives and uses the event:

<script type="text/javascript">
  document.addEventListener(
    "ocapi-challenge-validated",
    (evt) => {
      console.log("Challenge " + evt.detail.challenge_id + " has been validated")
    }
  )
  </script>

Validating a user

Once a user has replied to a challenge from your website, your form will include some fields. Note that the captchan-* fields are deprecated.

Below are the fields available for each version:

Field available 0.2.1 0.3.0 0.3.1 0.3.2 0.4.0+
captchan-challenge-id yes yes yes yes yes
captchan-client-id - - yes yes yes
ocapi-challenge-id - - - yes yes
ocapi-client-id - - - yes yes

Your website needs to use the unique challenge identifier (ocapi-challenge-id or captchan-challenge-id) in order to make an HTTP GET request on our service:

  • method GET
  • path: /state/<client_id>/<challenge_id>
  • <client_id> is your public id
  • <challenge_id> is the unique id included in your form
  • header: Authorization: <JWT>

The request must include a Json Web Token Authorization header configured as:

  • the hashing algorithm is HS512 (Sha 512)
  • the signing key is the secret key provided by us
  • the payload is a map including a public client id, explain below
Where to find the public client id 0.2.1 0.3.0 0.3.1 0.3.2 0.4.0+
your public id yes yes - - yes
captchan-client-id (included in your form) - - yes yes yes
ocapi-client-id (included in your form) - - - yes yes

If you can, use directly your public id. Otherwise prefer the ocapi-* fields because the captchan-* fields are deprecated.

Here is the payload in json:

{
  "client_id": "aPublicID"
}

This endpoint may give several response code:

  • 404 when the requested client in the url is not found
  • 403 when the Authorization header is missing or invalid
  • 404 when the requested challenge is not found
  • 200 when the challenge is available

When the challenge is found, you'll get a really simple JSON response payload with a state key. It can either be: - validated if the user has correctly replied to the challenge - rejected if the user provided an invalid answer. You need to reject the user in that case. - created if the user did not answer the question. You need to reject the user in that case.

Demo implementation in PHP

You can view the source code of a demonstration implementation in PHP on https://gitlab.teklia.com/teklia/captchan-demo

<?php
  # Configure the service
  define("BACKEND_URL", "https://ocapi.teklia.com/v2/");
  define("FRONTEND_URL", "https://assets.teklia.com/captchan/X.Y.Z.js");
  define("CLIENT_ID", "somePublicID");
  define("SECRET_KEY", "someSecretKey");

  $display_form = true;
  $error = false;

  if ($_POST) {
    if ($_POST["email"] && $_POST["password"]) {
      $challenge_id = $_POST["captchan-challenge-id"];
      $client_id = CLIENT_ID;
      # ⚠ Replace the previous line by this one **only** if you use a version >= 0.3.1
      # $client_id = $_POST["captchan-client-id"];

      $api_url = BACKEND_URL."state/".CLIENT_ID."/".$challenge_id;

      # Create JWT
      $payload = [
        "client_id" => $client_id,
      ];
      $authorization = create_jwt($payload, SECRET_KEY);

      # Send request
      $curl = create_curl($api_url, $authorization);
      $data = curl_exec($curl);

      # Check response
      $data = json_decode($data, true);
      if (curl_getinfo($curl , CURLINFO_HTTP_CODE) === 200) {
        if ($data["state"] === "validated") {
          $display_form = false;
        } else {
          $error = "Captcha not validated";
        }
      } else if (curl_getinfo($curl , CURLINFO_HTTP_CODE) === 403) {
        $error = "Authorization error";
      } else if (curl_getinfo($curl , CURLINFO_HTTP_CODE) === 404) {
        $error = "Challenge not found";
      } else {
        $error = curl_error($curl);
      }

      if ($error) error_log($error.": ".var_export($data, true));

      curl_close($curl);

    } else {
      $error = "Invalid POST request";
    }
  }
?>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="signin.css">
    <title>Ocapi by Teklia</title>
    <script type="text/javascript" src="<?= FRONTEND_URL ?>"></script>
    <script type="text/javascript">
      document.addEventListener("ocapi-challenge-validated", (evt) => { console.log("Challenge " + evt.detail.challenge_id + " has been validated") })
    </script>
  </head>
  <body class="text-center">
    <?php if($display_form): ?>
      <?php if($error): ?>
        <div class="error h4 mb-3 font-weight-normal"><?= $error ?></div>
      <?php endif; ?>
      <form action="" method="post" class="form-signin">
        <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
        <div>
          <label class="sr-only" for="email">Email address</label>
          <input class="form-control" type="email" id="email" name="email" required placeholder="Email address">
        </div>

        <div class="field">
          <label class="sr-only" for="password">Password</label>
          <input class="form-control" type="password" id="password" name="password" required placeholder="Password">
        </div>

        <div class="captcha">
          <!-- The challenge will be displayed here -->
          <div
            id="ocapi-challenge"
            data-ocapi-client="<?= CLIENT_ID ?>"
            data-ocapi-base-url="<?= BACKEND_URL ?>"
          ></div>
        </div>

        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
      </form>

    <?php else: ?>
      <div class="h3 mb-3 font-weight-normal">Hello <?= $_POST["email"] ?></div>
    <?php endif; ?>
  </body>
</html>