Bygg inn merkeverifisering på nettsiden din (uten iframe og uten SDK)

Legg til en liten JavaScript-snutt (eller et server-side-kall) på nettstedet ditt som verifiserer ethvert Open Badge mot et offentlig JSON-LD-endepunkt. Ingen iframe, ingen sporer fra tredjepart.

Nacho Coll Av Oppdatert 10 min lesing
Legg til en liten JavaScript-snutt (eller et server-side-kall) på nettstedet ditt som verifiserer ethvert Open Badge mot et offentlig JSON-LD-endepunkt. Ingen iframe, ingen sporer fra tredjepart.

Hvis du utsteder digitale bevis, er det før eller siden noen som spør: «hvordan vet jeg at dette merket er ekte?» Det ærlige svaret bør aldri være «stol på PNG-filen.» Open Badge v2.0 løser dette med et offentlig, maskinlesbart verifiseringsendepunkt, og en «Verifisert»-widget på ditt eget nettsted tar omtrent ti linjer kode — ikke en iframe, ikke et embed-skript fra tredjepart og ikke en SDK.

Dette innlegget viser nøyaktig hvordan du kaller endepunktet og viser resultatet, i vanlig JavaScript og på serveren i Node og Python. Det tar også for seg hva «verifisering» faktisk sjekker, hvordan endepunktet passer sammen med sidene for mennesker som badges.ninja allerede gir mottakerne, og feilene som får en verifiseringswidget til å se ferdig ut mens den i stillhet ikke beviser noe som helst.

Hva «verifisert» egentlig betyr

En Open Badge v2.0-assertion er et JSON-LD-dokument med en fast struktur: selve assertionen (hvem som mottok den, og når), en referanse til BadgeClass (hva det er, og hvem som definerer kriteriene) og en referanse til utstederprofilen (hvem som står inne for den). Når du «verifiserer» et merke, sjekker du egentlig tre forskjellige ting:

  1. Finnes assertionen, og lar den seg slå opp. Award-ID-en er ekte, ikke gjettet eller manipulert.
  2. Er den trukket tilbake. En utsteder kan trekke tilbake et merke i etterkant — et bevis utstedt ved en feil, et brudd på retningslinjer, en sertifisering som har gått ut — og en korrekt verifikator må vise det, ikke bare bekrefte at posten finnes.
  3. Henger kjeden sammen. Assertionens referanser til merke og utsteder peker faktisk på ekte, samsvarende poster, ikke på foreldreløse eller ikke-samsvarende ID-er.

En verifiseringswidget som bare pinger en URL og sjekker for statuskode 200, overser punkt 2 fullstendig. En tilbakekalt assertion lar seg fortsatt slå opp uten problemer — den har bare et tilbakekallingsflagg i payloaden. Hvis widgeten din bare sjekker «lyktes forespørselen», vil et tilbakekalt bevis vises som verifisert, og det er verre enn å ikke ha noen widget i det hele tatt.

Den offentlige siden for mennesker vs. API-endepunktet

Hver award som utstedes på https://badges.ninja, får en offentlig URL som mottakerne kan dele direkte, uten at man trenger å registrere seg for å se den:

Offentlig bevisside

Den siden er det de fleste mottakere kommer til å lenke til fra LinkedIn, en CV eller en e-postsignatur — den er laget for mennesker, viser merkebildet, utstederen og utstedelsesdatoen, og trenger ingenting fra deg for å fungere. API-endepunktet nedenfor returnerer den samme underliggende assertionen som strukturert JSON-LD, og det er det du vil ha når du bygger ditt eget grensesnitt i stedet for bare å lenke ut til vårt.

Endepunktet

GET https://api.badges.ninja/certify-badge/award/{guid}

Ingen auth-header nødvendig — dette er bevisst offentlig, fordi hele poenget med Open Badges er at alle (en arbeidsgiver, en rekrutterer, et godkjenningsorgan) kan verifisere et bevis uten en konto. Alle detaljer om kontrakten, inkludert de nøyaktige feltnavnene i den returnerte assertionen, finner du i verifiseringsdokumentasjonen.

Oppgi awardens GUID, som du enten har fra dine egne utstedelsesregistre eller kan hente ut fra en badges.ninja/awards/<guid>-lenke som en mottaker har delt med deg.

Vanilla JS: hent og vis

Dette er hele widgeten. Ingen byggesteg, ingen npm-pakke — slipp den rett inn på en hvilken som helst side:

<div id="badge-verify"></div>
<script>
  async function renderBadgeVerification(awardId, mountId) {
    const el = document.getElementById(mountId);
    el.textContent = "Checking badge status";
    try {
      const res = await fetch(
        `https://api.badges.ninja/certify-badge/award/${awardId}`
      );
      if (!res.ok) {
        el.textContent = "Credential not found.";
        return;
      }
      const assertion = await res.json();
      // —— revocation check first, a resolvable assertion isn't enough on its own
      if (assertion.revoked) {
        el.textContent = `Revoked: ${assertion.revocationReason || "no reason given"}`;
        return;
      }
      el.textContent = `Verified, issued ${new Date(assertion.issuedOn).toLocaleDateString()}`;
    } catch (err) {
      el.textContent = "Verification check failed.";
    }
  }
  renderBadgeVerification("REPLACE_WITH_AWARD_ID", "badge-verify");
</script>

Bytt ut REPLACE_WITH_AWARD_ID med en ekte award-GUID. Det er hele klientintegrasjonen: ingen iframe-grense du må slåss mot i CSS, og ingen tredjepartsskript som drar med seg egen analyse eller sporingspiksler sammen med verifiseringssjekken.

Server-side: Node

Hvis du heller vil verifisere på backend — for eksempel før du viser et «Verifisert partner»-merke på en profilside du kontrollerer, eller før du godtar et bevis som dokumentasjon i en onboarding-flyt — er kallet identisk, bare uten DOM-delen:

async function verifyAward(awardId) {
  const res = await fetch(
    `https://api.badges.ninja/certify-badge/award/${awardId}`
  );
  if (!res.ok) return { verified: false, reason: "not_found" };
  const assertion = await res.json();
  if (assertion.revoked) {
    return { verified: false, reason: assertion.revocationReason || "revoked" };
  }
  return { verified: true, issuedOn: assertion.issuedOn, badge: assertion.badge };
}

Server-side: Python

import requests
# —— resolve the assertion, then check revocation before trusting it
def verify_award(award_id):
    res = requests.get(f"https://api.badges.ninja/certify-badge/award/{award_id}")
    if res.status_code != 200:
        return {"verified": False, "reason": "not_found"}
    assertion = res.json()
    if assertion.get("revoked"):
        return {"verified": False, "reason": assertion.get("revocationReason", "revoked")}
    return {"verified": True, "issued_on": assertion.get("issuedOn"), "badge": assertion.get("badge")}

Begge eksemplene behandler et svar som ikke er 200, som «ikke funnet» i stedet for å kaste en feil. En ødelagt eller gjettet award-ID er en forventet inndata til et offentlig verifiseringsendepunkt, ikke en uvanlig en, så håndter den som en vanlig gren heller enn en fanget feil.

Style resultatet i stedet for å bygge inn andres grensesnitt

Fordi widgeten ovenfor bare er et fetch-kall inn i ditt eget DOM, eier du hver eneste piksel. Et vanlig mønster er tre visuelle tilstander som utledes direkte av svaret:

  • Verifisert — en grønn hake pluss «Verifisert» og utstedelsesdatoen, stylet så det passer med nettstedets merke-/tagg-komponenter.
  • Tilbakekalt — en dempet eller rød tilstand som viser årsaken til tilbakekallingen i stedet for å skjule den. Både mottakere og tredjeparter har nytte av et ærlig «hvorfor», ikke en taus feil.
  • Ikke funnet — behandle dette visuelt likt som «tilbakekalt» (ikke vis en falsk suksesstilstand), men med annen tekst, siden en ugyldig ID og en bevisst tilbakekalling er to ulike situasjoner for den som leser siden.

Ingenting av dette krever et komponentbibliotek. En switch på verified / revoked / not_found og tre CSS-klasser dekker det.

Caching, så du ikke hamrer løs på endepunktet

Verifiseringsendepunktet er offentlig og uten autentisering, noe som også betyr at det ikke er noen kredittkostnad per forespørsel å bekymre seg for — men det er likevel en nettverksrunde ved hver sideinnlasting hvis du kaller det på klientsiden uten caching. For en side som viser det samme merket til alle besøkende (for eksempel et «Verifisert partner»-merke i bunnteksten), bør du bufre resultatet på serveren med en kort TTL — fem til femten minutter er mer enn nok, siden tilbakekallinger ikke er et raskt skiftende signal — i stedet for å hente det på nytt ved hver forespørsel:

const cache = new Map();
async function verifyAwardCached(awardId, ttlMs = 10 * 60 * 1000) {
  const hit = cache.get(awardId);
  if (hit && Date.now() - hit.at < ttlMs) return hit.result;
  const result = await verifyAward(awardId);
  cache.set(awardId, { result, at: Date.now() });
  return result;
}

For en widget per besøkende (en mottaker som bygger inn sitt eget bevis på en personlig side) kan du hoppe over cachen og bare kalle endepunktet friskt ved sideinnlasting — den ekstra forespørselen er ubetydelig i den skalaen.

Hva badges.ninja allerede gir mottakerne

Før du bygger en helt skreddersydd innbygging, er det verdt å vite hva som allerede er tilgjengelig ut av boksen. Hver awards offentlige side har ferdige del- og innbyggingssnutter som mottakerne kan kopiere direkte, uten at de må skrive kode selv:

Offentlig delingsside med sosiale knapper og innbyggingssnutter

Hvis behovet ditt er «la en mottaker vise at merket deres er ekte», er det ofte enklere å lenke til badges.ninja/awards/<guid>-siden deres enn å bygge en egendefinert widget — det er siden for mennesker vi viste tidligere, og den håndterer allerede forskjellen på verifisert og tilbakekalt for deg. Bygg den egendefinerte widgeten fra dette innlegget når du trenger å vise verifiseringsstatusen inne i ditt eget produkts grensesnitt — et partnerregister, et internt revisjonsdashbord, et rekrutteringsverktøy som sjekker en kandidats oppgitte sertifiseringer — der det ikke er riktig brukeropplevelse å lenke ut til et annet nettsted.

Hvorfor ikke en iframe eller en leverandørwidget?

Noen plattformer gir deg en snutt som <iframe src="https://vendor.example.com/verify-widget"> for å bygge inn verifiseringsstatus. Det fungerer, men det har reelle kostnader: du kan ikke style innholdet så det passer nettstedet ditt (du sitter fast med den CSS-en leverandøren leverte), det introduserer et cross-origin-dokument som Content-Security-Policy-en din eksplisitt må tillate, og hver sideinnlasting sender en forespørsel til en tredjeparts iframe-vert uansett om den besøkende bryr seg om verifiseringsstatus i det hele tatt. En fetch-widget med to kall unngår alle tre — det er ditt DOM, din styling, og den kjører bare når du bestemmer deg for å kalle den.

Gå gjennom hele verifiseringskjeden

Hvis du bygger noe grundigere enn en statuswidget — et revisjonsverktøy som sjekker en rekke bevis, eller en samsvarsrapport — bør du gå gjennom hele kjeden i stedet for å stoppe ved assertionen. Assertionen refererer til en badge-URL (BadgeClass: navn, beskrivelse, kriterier), og BadgeClass refererer igjen til en issuer-URL (organisasjonsprofilen). En grundig verifikator slår opp alle tre og bekrefter at de er innbyrdes konsistente — at merket virkelig tilhører utstederen det hevder, og at assertionen virkelig refererer til merket den hevder — ikke bare at assertionen på toppnivå returnerer 200. Det er mer dybde enn en statuswidget for ett enkelt bevis trenger, men det er greit å kjenne strukturen hvis en partner eller revisor noen gang spør: «hvor dypt går verifiseringen deres egentlig?»

Vanlige feil du bør unngå

  • Å sjekke bare HTTP-status. Som nevnt ovenfor lar en tilbakekalt assertion seg fortsatt slå opp. Les alltid assertion.revoked, og ikke utled verifisering av statuskoden alene.
  • Å hardkode award-ID-en i en delt komponent. Hvis widgeten skal kunne gjenbrukes på mange mottakeres sider, ta award-ID-en som parameter (et data-attributt, en query string, en prop) i stedet for en konstant skrevet inn i skriptet.
  • Å svelge nettverksfeil i stillhet. En try/catch som ikke logger noe og viser den samme «ikke funnet»-teksten som for et merke som faktisk mangler, gjør feilsøking vanskelig senere. Skill mellom «nettverkskallet feilet» og «API-et sa nei» i feilgrenene dine, i det minste i loggene.
  • Å verifisere på nytt ved hver rendering i en klientapp. Hvis widgeten ligger i en React- eller Vue-komponent som rendres ofte, verifiser én gang per mount (eller én gang per bufret TTL-vindu, som i caching-avsnittet ovenfor), ikke ved hver gjen-rendering.

Koster dette kreditter, og fungerer det på gratisplanen?

Nei. Verifiseringsendepunktet ligger bevisst utenfor kreditsystemet som styrer utstedelse — det koster ikke utstederen noe å sjekke om et merke er gyldig, og den besøkende som kaller det, trenger verken en konto, en API-nøkkel eller noe abonnement i det hele tatt. Det gjelder uansett om merket ble utstedt på en Free-, Starter- eller Pro-plan: verifisering er en egenskap ved selve beviset, ikke en funksjon som ligger bak utstederens abonnement. Det er også grunnen til at du trygt kan sette widgeten på en offentlig side med uforutsigbar trafikk (en karrieresiden, et partnerregister) uten å bekymre deg for rate limits knyttet til kontoen din — du kaller et skrivebeskyttet, offentlig endepunkt, ikke en autentisert API-rute.

Én ting er verdt å si eksplisitt: assertion-JSON-en som endepunktet returnerer, inneholder ikke mottakerens rå e-postadresse. Mottakerens e-post lagres hashet i backend nettopp for at et offentlig verifiseringssvar ikke skal kunne skrapes for personlig kontaktinformasjon — det du får tilbake, er nok til å bekrefte beviset (merke, utsteder, datoer, tilbakekallingsstatus) uten å gjøre endepunktet til et verktøy for leadgenerering for alle som itererer over award-ID-er.

Klar til å utstede ditt første verifiserbare bevis?

Kom i gang gratis på badges.ninja — visuell designer, offentlig verifiseringsside, PDF-sertifikat, Open Badge v2.0-utdata. Ikke noe kredittkort nødvendig.

For den fullstendige kommenterte strukturen til hvert felt i en assertion, se JSON-LD-feltreferansen. Og hvis du utsteder bevis programmatisk i stedet for bare å verifisere dem, dekker API-hurtigstarten autentisering og kallet for å opprette awards som dette endepunktets utdata kommer fra.

Nacho Coll

Om forfatteren

Founder & Engineer at Badges Ninja

Nacho founded Badges Ninja to make issuing verifiable digital credentials as simple as a single API call — Open Badge v2.0 badges and certificates, minted, hosted, and verifiable without standing up your own issuer infrastructure. Writes about the Open Badges spec, credential verification, and running a credentialing platform serverless on AWS, from the operator side of the wire.

Tilbake til bloggen

Relaterte artikler