CINXE.COM
IIIF Authentication API 1.0 — IIIF | International Image Interoperability Framework
<!DOCTYPE html> <html lang='en'><head> <meta charset="utf-8"> <title> IIIF Authentication API 1.0 — IIIF | International Image Interoperability Framework </title> <meta name="description" content="IIIF is a set of open standards for delivering high-quality digital objects online at scale. It’s also the international community that makes it all work."> <link rel="shortcut icon" href="/api/assets/favicon.ico"> <link rel="apple-touch-icon" sizes="180x180" href="/api/assets/apple-touch-icon.png"> <link rel="icon" type="image/png" sizes="32x32" href="/api/assets/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="16x16" href="/api/assets/favicon-16x16.png"> <link rel="manifest" href="/api/assets/site.webmanifest"> <link rel="mask-icon" href="/api/assets/safari-pinned-tab.svg" color="#E82334"> <meta name="msapplication-TileColor" content="#da532c"> <meta name="theme-color" content="#ffffff"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/api/assets/css/style.css"> <link rel="canonical" href="/api/auth/1.0/" /> <!-- Google tag (gtag.js) --> <script async src="https://www.googletagmanager.com/gtag/js?id=G-ZW5W9QRPH6"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-ZW5W9QRPH6'); </script> <link rel="preload" as="image" href="/api"> <!-- Begin Jekyll SEO tag v2.8.0 --> <meta name="generator" content="Jekyll v4.1.1" /> <meta property="og:title" content="IIIF Authentication API 1.0" /> <meta property="og:locale" content="en_US" /> <link rel="canonical" href="/api/auth/1.0/" /> <meta property="og:url" content="/api/auth/1.0/" /> <meta property="og:type" content="website" /> <meta name="twitter:card" content="summary" /> <meta property="twitter:title" content="IIIF Authentication API 1.0" /> <meta name="twitter:site" content="@iiif_io" /> <script type="application/ld+json"> {"@context":"https://schema.org","@type":"WebPage","headline":"IIIF Authentication API 1.0","publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"/api/assets/favicon.ico"}},"url":"/api/auth/1.0/"}</script> <!-- End Jekyll SEO tag --> <!-- add for Mastodon verification --> <link rel="me" href="https://glammr.us/@iiif"> </head> <body> <section class="hero is-primary" style="background-image: linear-gradient(to bottom, rgba(0, 25, 39, 0.68), rgba(0, 25, 39, 0.68)), url('/api'); background-size: cover; background-position: bottom center; background-attachment: fixed; "> <div class="hero-head"> <nav id="navbar" class="navbar is-transparent is-spaced"> <div class="container"> <div class="navbar-brand"> <a class="navbar-item" href="https://iiif.io/"> <img src="/api/assets/images/logos/logo-sm.png" alt="IIIF logo" height="28"> <span class="brand-title">International Image Interoperability Framework</span> </a> <div class="navbar-burger" data-target="navbar" onclick="document.querySelector('.navbar-menu').classList.toggle('is-active');"> <span></span> <span></span> <span></span> </div> </div> <div class="navbar-menu"> <div class="navbar-end"> <a class="navbar-item" href="https://iiif.io/">Home</a> <a class="navbar-item" href="https://iiif.io/demos">Demos</a> <a class="navbar-item" href="https://iiif.io/news-and-events">News & Events</a> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link" href="https://iiif.io/get-involved"> Get Involved </a> <div class="navbar-dropdown is-boxed is-active"> <a class="navbar-item" href="https://iiif.io/community/">Community</a> <a class="navbar-item" href="https://iiif.io/community/consortium">Consortium</a> <a class="navbar-item" href="https://iiif.io/newsletter">Join Newsletter</a> <a class="navbar-item" href="https://iiif.io/get-involved/outreach-materials">Outreach Materials</a> </div> </div> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link" href="https://iiif.io/get-started"> Get Started </a> <div class="navbar-dropdown is-boxed is-active"> <a class="navbar-item" href="https://iiif.io/get-started/how-iiif-works">How IIIF Works</a> <a class="navbar-item" href="https://iiif.io/community/ambassadors/">IIIF Ambassadors</a> <a class="navbar-item" href="https://iiif.io/guides">Guides</a> <a class="navbar-item" href="/api">APIs & Documentation</a> <a class="navbar-item" href="https://iiif.io/get-started/cookbook">Cookbooks</a> <a class="navbar-item" href="https://iiif.io/get-started/training">Training</a> </div> </div> </div> </div> </div> </nav> </div> <div class="hero-body container"> <nav class="breadcrumb is-centered" aria-label="breadcrumbs"> <ul> <li><a href="https://iiif.io/get-started">Get Started</a></li> <li><a href="/api/">APIs & Documentation</a></li> </ul> </nav> <div class="container has-text-centered"> <h1 class="title is-size-2 is-size-3-mobile is-size-desktop is-size-1-widescreen">IIIF Authentication API 1.0</h1> <p class="subtitle is-size-5"></p> </div> </div> </section> <section id="main"> <div class="container-block no-padding is-max-desktop"> <div class="columns is-max-desktop"> <aside class="column is-one-quarter api-sidebar-container" markdown="1"> <div class="toc-sidebar sticky"> <ul class="menu" id="toc-menu"><li><a href="#introduction">1. Introduction</a><ul class="menu-list toc-submenu-2"><li><a href="#terminology">1.1. Terminology</a></li><li><a href="#authentication-for-content-resources">1.2. Authentication for Content Resources</a></li><li><a href="#authentication-for-description-resources">1.3. Authentication for Description Resources</a></li><li><a href="#security">1.4. Security</a></li></ul></li><li><a href="#authentication-services">2. Authentication Services</a><ul class="menu-list toc-submenu-2"><li><a href="#access-cookie-service">2.1. Access Cookie Service</a></li><li><a href="#access-token-service">2.2. Access Token Service</a></li><li><a href="#logout-service">2.3. Logout Service</a></li><li><a href="#example-description-resource-with-authentication-services">2.4. Example Description Resource with Authentication Services</a></li></ul></li><li><a href="#interaction-with-access-controlled-resources">3. Interaction with Access-Controlled Resources</a><ul class="menu-list toc-submenu-2"><li><a href="#all-or-nothing-access">3.1. All or Nothing Access</a></li><li><a href="#tiered-access">3.2. Tiered Access</a></li></ul></li><li><a href="#workflow-from-the-browser-client-perspective">4. Workflow from the Browser Client Perspective</a></li><li><a href="#appendices">Appendices</a><ul class="menu-list toc-submenu-2"><li><a href="#a-implementation-notes">A. Implementation Notes</a></li><li><a href="#b-versioning">B. Versioning</a></li><li><a href="#c-acknowledgments">C. Acknowledgments</a></li><li><a href="#d-change-log">D. Change Log</a></li></ul></li></ul> </div> </aside> <div class="column is-three-quarters content api-content" markdown="1"> <h2 class="no_toc" id="status-of-this-document"> Status of this Document <a href="#status-of-this-document" class="anchorClass"></a> </h2> <p><strong>This Version:</strong> 1.0.0</p> <p><strong>Latest Stable Version:</strong> <a href="/api/auth/2.0/" title="Stable Version">2.0.0</a></p> <p><strong>Previous Version:</strong> <a href="/api/auth/0.9/" title="Previous Version">0.9.4</a></p> <p><strong>Editors:</strong></p> <ul> <li> <p><strong><a href="https://orcid.org/0000-0002-1266-298X">Michael Appleby</a></strong>, Yale University</p> </li> <li> <p><strong><a href="https://orcid.org/0000-0003-1881-243X">Tom Crane</a></strong>, Digirati</p> </li> <li> <p><strong><a href="https://orcid.org/0000-0003-4441-6852">Robert Sanderson</a></strong>, J. Paul Getty Trust</p> </li> <li> <p><strong><a href="https://orcid.org/0000-0002-0367-1243">Jon Stroop</a></strong>, Princeton University Library</p> </li> <li> <p><strong><a href="https://orcid.org/0000-0002-7970-7855">Simeon Warner</a></strong>, Cornell University</p> </li> </ul> <p><em>Copyright © 2015-2024 Editors and contributors. Published by the <abbr title="International Image Interoperability Framework">IIIF</abbr> Consortium under the <a href="http://creativecommons.org/licenses/by/4.0/" title="Creative Commons — Attribution 4.0 International">CC-BY</a> license, see <a href="/api/annex/notes/disclaimer/">disclaimer</a>.</em></p><hr /> <p class="alert"><strong>Warning</strong><br /> Recent developments in the browser community to discontinue support for third-party cookies have meant that <abbr title="International Image Interoperability Framework">IIIF</abbr> Authentication <abbr title="Application Programming Interface">API</abbr> 1.0 workflows that rely on third-party cookies are now, or will soon be, obsolete in most browsers. The <a href="https://iiif.io/community/groups/auth-tsg/"><abbr title="International Image Interoperability Framework">IIIF</abbr> Authentication TSG</a> is currently working on the next iteration of the Auth specification, which should address the third-party cookies issue. Workflows relying on first-party cookies remain unaffected by these developments. For a more detailed discussion of the issues, see <a href="https://tom-crane.medium.com/what-happens-if-there-are-no-third-party-cookies-5ee5edb84d75">What happens if there are no third-party cookies?</a>.</p> <h2 id="introduction"> 1. Introduction <a href="#introduction" class="anchorClass"></a> </h2> <p>The <abbr title="International Image Interoperability Framework">IIIF</abbr> (pronounced “Triple-Eye-Eff”) specifications are designed to support uniform and rich access to resources hosted around the world. Open access to content is desirable, but internal policies, legal regulations, business models, and other constraints can require users to authenticate and be authorized to interact with some resources. The authentication process could range from a simple restriction by <abbr title="Internet Procotol">IP</abbr> address or a click-through agreement, to a multi-factor scheme with a secure identity provider.</p> <p>Content providers that need to restrict access to their resources may offer tiered access to alternative versions that go beyond a simple all-or-nothing proposition. These alternative versions could be degraded based on resolution, watermarking, or compression, for example, but are often better than no access at all.</p> <p>Providing interoperable access to restricted content through client applications running in a web browser poses many challenges:</p> <ul> <li>A single <abbr title="International Image Interoperability Framework">IIIF</abbr> Presentation <abbr title="Application Programming Interface">API</abbr> manifest can reference content resources at multiple institutions and hence from multiple domains.</li> <li>Each version of a resource must have a distinct URI to prevent web caches from providing the wrong version.</li> <li>Institutions have different existing access control systems.</li> <li>Most <abbr title="International Image Interoperability Framework">IIIF</abbr> viewers are client-side JavaScript applications, and may be served from a domain that is different from, and thus untrusted by, the image services that it is required to load.</li> <li>Similarly, the domain of the authentication services may be different from that of a viewer or the <abbr title="International Image Interoperability Framework">IIIF</abbr>-based content. Therefore, the authorizing server must not require any prior knowledge of the domain hosting the viewer.</li> </ul> <p>Additionally, the <abbr title="International Image Interoperability Framework">IIIF</abbr> community has the following goals for this specification:</p> <ul> <li>A <abbr title="International Image Interoperability Framework">IIIF</abbr> client should not authenticate the user itself; the server hosting the content must be responsible for capturing credentials from a user and the <abbr title="International Image Interoperability Framework">IIIF</abbr> viewer needs no knowledge of or access to this exchange.</li> <li>A browser-based <abbr title="International Image Interoperability Framework">IIIF</abbr> client must be able to maintain its own internal state during an authentication flow.</li> <li>A registry of trusted domains should not be required; anyone should be able to create any kind of viewer and run it from anywhere.</li> <li>Institutions should be able to use their existing authentication systems without modification.</li> </ul> <p>To meet these challenges and goals, the <abbr title="International Image Interoperability Framework">IIIF</abbr> Authentication specification describes a set of workflows for guiding the user through an <em>existing</em> access control system. The process of authenticating the user is mostly outside the scope of the specification and may involve a round-trip to a <abbr title="Central Authentication Service">CAS</abbr> server, or an OAuth2 provider, or a bespoke login system. In this sense, <abbr title="International Image Interoperability Framework">IIIF</abbr> Authentication is not the same as a protocol like <abbr title="Central Authentication Service">CAS</abbr>; it is a pattern for interacting with arbitrary third party protocols.</p> <p><abbr title="International Image Interoperability Framework">IIIF</abbr> Authentication provides a link to a user interface for logging in, and services that provide credentials, modeled after elements of the OAuth2 workflow. Together they act as a bridge to the access control system in use on the server, without the client requiring knowledge of that system.</p> <p>In summary, the specification describes how to:</p> <ul> <li>From within a viewer, initiate an interaction with an access control system so that a user can acquire the credentials they need to view restricted content.</li> <li>Give the client just enough knowledge of the user’s state with respect to the content provider to ensure a good user experience.</li> </ul> <p>Please send feedback to <a href="mailto:iiif-discuss@googlegroups.com" title="Email Discussion List">iiif-discuss@googlegroups.com</a>.</p> <h3 id="terminology"> 1.1. Terminology <a href="#terminology" class="anchorClass"></a> </h3> <p>This specification distinguishes between <strong>Content Resources</strong>, such as images or videos, and <strong>Description Resources</strong> which conform to <abbr title="International Image Interoperability Framework">IIIF</abbr> specifications, such as <a href="/api/image/">Image <abbr title="Application Programming Interface">API</abbr></a> image information (info.json) and <a href="/api/presentation/">Presentation <abbr title="Application Programming Interface">API</abbr></a> collection or manifest resources. From the point of view of a browser-based application, Content Resources are loaded indirectly via browser interpretation of <abbr title="HyperText Markup Language">HTML</abbr> elements, whereas Description Resources are typically loaded directly by JavaScript using the <code class="language-plaintext highlighter-rouge">XMLHttpRequest</code> interface. The <a href="http://www.w3.org/TR/cors/" title="Cross-Origin Resource Sharing">Cross Origin Resource Sharing</a> (<abbr title="Cross-Origin Resource Sharing">CORS</abbr>) specification implemented in modern browsers describes the different security rules that apply to the interactions with these two types of resource.</p> <p>Two additional concepts, the <strong>access cookie</strong> and <strong>access token</strong>, are described below.</p> <p>The key words <em class="rfc">must</em>, <em class="rfc">must not</em>, <em class="rfc">required</em>, <em class="rfc">shall</em>, <em class="rfc">shall not</em>, <em class="rfc">should</em>, <em class="rfc">should not</em>, <em class="rfc">recommended</em>, <em class="rfc">may</em>, and <em class="rfc">optional</em> in this document are to be interpreted as described in <a href="https://datatracker.ietf.org/doc/html/rfc2119" title="Key words for use in RFCs to Indicate Requirement Levels"><abbr title="Request for Comments">RFC</abbr> 2119</a>.</p> <h3 id="authentication-for-content-resources"> 1.2. Authentication for Content Resources <a href="#authentication-for-content-resources" class="anchorClass"></a> </h3> <p>Content Resources, such as images, are generally secondary resources embedded in a web page or application. In the case of web pages, images might be included via the <abbr title="HyperText Markup Language">HTML</abbr> <code class="language-plaintext highlighter-rouge">img</code> tag, and retrieved via additional <abbr title="Hypertext Transfer Protocol">HTTP</abbr> requests by the browser. When a user is not authorized to load a web page, the server can redirect the user to another page and offer the opportunity to authenticate. This redirection is not possible for embedded Content Resources, and the user is simply presented with a broken image icon. If the image is access controlled, the browser must avoid broken images by sending a cookie that the server can accept as a credential that grants access to the image. This specification describes the process by which the user acquires this <strong>access cookie</strong>.</p> <h3 id="authentication-for-description-resources"> 1.3. Authentication for Description Resources <a href="#authentication-for-description-resources" class="anchorClass"></a> </h3> <p>Description Resources, such as a Presentation <abbr title="Application Programming Interface">API</abbr> manifest or an Image <abbr title="Application Programming Interface">API</abbr> information document (info.json), give the client application the information it needs to have the browser request the Content Resources. A Description Resource must be on the same domain as the Content Resource it describes, but there is no requirement that the executing client code is also hosted on this domain.</p> <p>A browser running JavaScript retrieved from one domain cannot use <code class="language-plaintext highlighter-rouge">XMLHttpRequest</code> to load a Description Resource from another domain and include that domain’s cookies in the request, without violating the requirement introduced above that the client must work when <em>untrusted</em>. Instead, the client sends an <strong>access token</strong>, technically a type of <a href="https://tools.ietf.org/html/rfc6750#section-1.2" title="OAuth2 Bearer Tokens">bearer token</a>, as a proxy for the access cookie. This specification describes how, once the browser has acquired the access cookie for the Content Resources, the client acquires the access token to use when making direct requests for Description Resources.</p> <p>The server on the Resource Domain treats the access token as a representation of, or proxy for, the cookie that gains access to the Content Resources. When the client makes requests for the Description Resources and presents the access token, the responses tell the client what will happen when the browser requests the corresponding content resources with the access cookie the access token represents. These responses let the client decide what user interface and/or Content Resources to show to the user.</p> <h3 id="security"> 1.4. Security <a href="#security" class="anchorClass"></a> </h3> <p>The purpose of this specification to support access-control for <abbr title="International Image Interoperability Framework">IIIF</abbr> resources and hence security is a core concern. To prevent misuse, cookies and bearer tokens described in this specification need to be protected from disclosure in storage and in transport. Implementations <em class="rfc">should</em> use <a href="https://tools.ietf.org/html/rfc2818" title="HTTP Over TLS"><abbr title="Hypertext Transfer Protocol">HTTP</abbr> over <abbr title="Transport Layer Security">TLS</abbr></a>, commonly known as <abbr title="Hypertext Transfer Protocol (Secure)">HTTPS</abbr>, for all communication. Furthermore, all <abbr title="International Image Interoperability Framework">IIIF</abbr> clients that interact with access-controlled resources <em class="rfc">should</em> also be run from pages served via <abbr title="Hypertext Transfer Protocol (Secure)">HTTPS</abbr>. All references to <abbr title="Hypertext Transfer Protocol">HTTP</abbr> in this specification should be read assuming the use of <abbr title="Hypertext Transfer Protocol (Secure)">HTTPS</abbr>.</p> <p>This specification protects Content Resources such as images by making the access token value available to the script of the client application, for use in requesting Description Resources. Knowledge of the access token is of no value to a malicious client, because the access <em>cookie</em> (which the client cannot see) is the only credential accepted for Content Resources, and a Description Resource is of no value on its own. However, the interaction patterns introduced in this specification will in future versions be extended to write operations on <abbr title="International Image Interoperability Framework">IIIF</abbr> resources, for example creating annotations in an annotation server, or modifying the <code class="language-plaintext highlighter-rouge">structures</code> element in a manifest. For these kinds of operations, the access token <em>is</em> the credential, and the flow introduced below may require one or more additional steps to establish trust between client and server. However, it is anticipated that these changes will be backwards compatible with version 1.0.</p> <p>Further discussion of security considerations can be found in the <a href="implementation/" title="IIIF Authentication: Implementation Notes">Implementation Notes</a>.</p> <h2 id="authentication-services"> 2. Authentication Services <a href="#authentication-services" class="anchorClass"></a> </h2> <p>Authentication services follow the pattern described in the <abbr title="International Image Interoperability Framework">IIIF</abbr> <a href="/api/annex/services/">Linking to External Services</a> note, and are referenced in one or more <code class="language-plaintext highlighter-rouge">service</code> blocks from the descriptions of the resources that are protected. There is a primary login service profile for authenticating users, and it has related services nested within its description. The related services include a mandatory access token service, and an optional logout service.</p> <h3 id="access-cookie-service"> 2.1. Access Cookie Service <a href="#access-cookie-service" class="anchorClass"></a> </h3> <p>The client uses this service to obtain a cookie that will be used when interacting with content such as images, and with the access token service. There are several different interaction patterns in which the client will use this service, based on the user interface that must be rendered for the user, indicated by a profile URI. The client obtains the link to the access cookie service from a service block in a description of the protected resource.</p> <p>The purpose of the access cookie service is to set a cookie during the user’s interaction with the content server, so that when the client then makes image requests to the content server, the requests will succeed. The client has no knowledge of what happens at the login service, and it cannot see any cookies set for the content domain during the user’s interaction with the login service. The browser may be redirected one or more times but this is invisible to the client application. The final response in the opened tab <em class="rfc">should</em> contain JavaScript that will attempt to close the tab, in order to trigger the next step in the workflow.</p> <h4 id="service-description"> 2.1.1. Service Description <a href="#service-description" class="anchorClass"></a> </h4> <p>There are four interaction patterns by which the client can obtain an access cookie, each identified by a profile URI. These patterns are described in more detail in the following sections.</p> <table class="api-table first-col-normal"> <thead> <tr> <th>Pattern</th> <th>Profile URI</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>Login</td> <td><code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/login</code></td> <td>The user will be required to log in using a separate window with a UI provided by an external authentication system.</td> </tr> <tr> <td>Clickthrough</td> <td><code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/clickthrough</code></td> <td>The user will be required to click a button within the client using content provided in the service description.</td> </tr> <tr> <td>Kiosk</td> <td><code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/kiosk</code></td> <td>The user will not be required to interact with an authentication system, the client is expected to use the access cookie service automatically.</td> </tr> <tr> <td>External</td> <td><code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/external</code></td> <td>The user is expected to have already acquired the appropriate cookie, and the access cookie service will not be used at all.</td> </tr> </tbody> </table> <p>The service description is included in the Description Resource and has the following properties:</p> <table class="api-table"> <thead> <tr> <th>Property</th> <th>Required?</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>@context</td> <td><em class="rfc">required</em></td> <td>The context document that describes the <abbr title="International Image Interoperability Framework">IIIF</abbr> Authentication <abbr title="Application Programming Interface">API</abbr>. The value <em class="rfc">must</em> be <code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/context.json</code>.</td> </tr> <tr> <td>@id</td> <td><em>see description</em></td> <td>It is <em class="rfc">required</em> with the Login, Clickthrough, or Kiosk patterns, in which the client opens the URI in order to obtain an access cookie. It is <em class="rfc">optional</em> with the External pattern, as the user is expected to have obtained the cookie by other means and any value provided is ignored.</td> </tr> <tr> <td>profile</td> <td><em class="rfc">required</em></td> <td>The profile for the service <em class="rfc">must</em> be one of the profile URIs from the table above.</td> </tr> <tr> <td>label</td> <td><em class="rfc">required</em></td> <td>The text to be shown to the user to initiate the loading of the authentication service when there are multiple services required. The value <em class="rfc">must</em> include the domain or institution to which the user is authenticating.</td> </tr> <tr> <td>confirmLabel</td> <td><em class="rfc">recommended</em></td> <td>The text to be shown to the user on the button or element that triggers opening of the access cookie service. If not present, the client supplies text appropriate to the interaction pattern if needed.</td> </tr> <tr> <td>header</td> <td><em class="rfc">recommended</em></td> <td>A short text that, if present, <em class="rfc">must</em> be shown to the user as a header for the description, or alone if no description is given.</td> </tr> <tr> <td>description</td> <td><em class="rfc">recommended</em></td> <td>Text that, if present, <em class="rfc">must</em> be shown to the user before opening the access cookie service.</td> </tr> <tr> <td>failureHeader</td> <td><em class="rfc">optional</em></td> <td>A short text that, if present, <em class="rfc">may</em> be shown to the user as a header after failing to receive a token, or using the token results in an error.</td> </tr> <tr> <td>failureDescription</td> <td><em class="rfc">optional</em></td> <td>Text that, if present, <em class="rfc">may</em> be shown to the user after failing to receive a token, or using the token results in an error.</td> </tr> <tr> <td>service</td> <td><em class="rfc">required</em></td> <td>References to access token and other related services, described below.</td> </tr> </tbody> </table> <h4 id="interaction-with-the-access-cookie-service"> 2.1.2. Interaction with the Access Cookie Service <a href="#interaction-with-the-access-cookie-service" class="anchorClass"></a> </h4> <p>The client <em class="rfc">must</em> append the following query parameter to all requests to an access cookie service URI, regardless of the interaction pattern, and open this URI in a new window or tab.</p> <table class="api-table"> <thead> <tr> <th>Parameter</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>origin</td> <td>A string containing the origin of the page in the window, consisting of a protocol, hostname and optionally port number, as described in the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" title="window.postMessage">postMessage <abbr title="Application Programming Interface">API</abbr></a> specification.</td> </tr> </tbody> </table> <p>For example, given an access cookie service URI of <code class="language-plaintext highlighter-rouge">https://authentication.example.org/login</code>, a client instantiated by the page <code class="language-plaintext highlighter-rouge">https://client.example.com/viewer/index.html</code> would make its request to:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://authentication.example.org/login?origin=https://client.example.com/ </code></pre></div></div> <p>The server <em class="rfc">may</em> use this information to validate the origin supplied in subsequent requests to the access token service, for example by encoding it in the cookie returned.</p> <h4 id="login-interaction-pattern"> 2.1.3. Login Interaction Pattern <a href="#login-interaction-pattern" class="anchorClass"></a> </h4> <p>In order to have the client prompt the user to log in, it must display part of the content provider’s user interface. For the Login interaction pattern, the value of the <code class="language-plaintext highlighter-rouge">@id</code> property is the URI of that user interface.</p> <p>The interaction has the following steps:</p> <ul> <li>If the <code class="language-plaintext highlighter-rouge">header</code> and/or <code class="language-plaintext highlighter-rouge">description</code> properties are present, before opening the provider’s authentication interface, the client <em class="rfc">should</em> display the values of the properties to the user. The properties will describe what is about to happen when they click the element with the <code class="language-plaintext highlighter-rouge">confirmLabel</code>.</li> <li>When the <code class="language-plaintext highlighter-rouge">confirmLabel</code> element is activated, the client <em class="rfc">must</em> then open the URI from <code class="language-plaintext highlighter-rouge">@id</code> with the added <code class="language-plaintext highlighter-rouge">origin</code> query parameter. This <em class="rfc">must</em> be done in a new window or tab to help prevent spoofing attacks. Browser security rules prevent the client from knowing what is happening in the new tab, therefore the client can only wait for and detect the closing of the opened tab.</li> <li>After the opened tab is closed, the client <em class="rfc">must</em> then use the related access token service, as described below.</li> </ul> <p>With out-of-band knowledge, authorized non-user-driven clients <em class="rfc">may</em> use POST to send the pre-authenticated user’s information to the service. As the information required depends on authorization logic, the details are not specified by this <abbr title="Application Programming Interface">API</abbr>.</p> <p>An example service description for the Login interaction pattern:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="c1">// ...</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Login to Example Institution"</span><span class="p">,</span><span class="w"> </span><span class="nl">"header"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Please Log In"</span><span class="p">,</span><span class="w"> </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Example Institution requires that you log in with your example account to view this content."</span><span class="p">,</span><span class="w"> </span><span class="nl">"confirmLabel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureHeader"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Authentication Failed"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureDescription"</span><span class="p">:</span><span class="w"> </span><span class="s2">"<a href=</span><span class="se">\"</span><span class="s2">http://example.org/policy</span><span class="se">\"</span><span class="s2">>Access Policy</a>"</span><span class="p">,</span><span class="w"> </span><span class="nl">"service"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="c1">// Access token and Logout services ...</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h4 id="clickthrough-interaction-pattern"> 2.1.4. Clickthrough Interaction Pattern <a href="#clickthrough-interaction-pattern" class="anchorClass"></a> </h4> <p>For the Clickthrough interaction pattern, the value of the <code class="language-plaintext highlighter-rouge">@id</code> property is the URI of a service that <em class="rfc">must</em> set an access cookie and then immediately close its window or tab without user interaction. The interaction has the following steps:</p> <ul> <li>If the <code class="language-plaintext highlighter-rouge">header</code> and/or <code class="language-plaintext highlighter-rouge">description</code> properties are present, before opening the service, the client <em class="rfc">must</em> display the values of the properties to the user. The properties will describe the agreement implied by clicking the element with the <code class="language-plaintext highlighter-rouge">confirmLabel</code>.</li> <li>When the <code class="language-plaintext highlighter-rouge">confirmLabel</code> element is activated, the client <em class="rfc">must</em> then open the URI from <code class="language-plaintext highlighter-rouge">@id</code> with the added <code class="language-plaintext highlighter-rouge">origin</code> query parameter. This <em class="rfc">should</em> be done in a new window or tab. Browser security rules prevent the client from knowing what is happening in the new tab, therefore the client can only wait for and detect the closing of the opened window or tab or iframe.</li> <li>After the opened tab is closed, the client <em class="rfc">must</em> then use the related access token service, as described below.</li> </ul> <p>Non-user-driven clients <em class="rfc">must</em> not use access cookie services with the Clickthrough interaction pattern, and instead halt.</p> <p>An example service description for the Clickthrough interaction pattern:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="c1">// ...</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/clickthrough"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/clickthrough"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Terms of Use for Example Institution"</span><span class="p">,</span><span class="w"> </span><span class="nl">"header"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Restricted Material with Terms of Use"</span><span class="p">,</span><span class="w"> </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"<span>... terms of use ... </span>"</span><span class="p">,</span><span class="w"> </span><span class="nl">"confirmLabel"</span><span class="p">:</span><span class="w"> </span><span class="s2">"I Agree"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureHeader"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Terms of Use Not Accepted"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureDescription"</span><span class="p">:</span><span class="w"> </span><span class="s2">"You must accept the terms of use to see the content."</span><span class="p">,</span><span class="w"> </span><span class="nl">"service"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// Access token service ...</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h4 id="kiosk-interaction-pattern"> 2.1.5. Kiosk Interaction Pattern <a href="#kiosk-interaction-pattern" class="anchorClass"></a> </h4> <p>For the Kiosk interaction pattern, the value of the <code class="language-plaintext highlighter-rouge">@id</code> property is the URI of a service that <em class="rfc">must</em> set an access cookie and then immediately close its window or tab without user interaction. The interaction has the following steps:</p> <ul> <li>There is no user interaction before opening the access cookie service URI, and therefore any of the <code class="language-plaintext highlighter-rouge">label</code>, <code class="language-plaintext highlighter-rouge">header</code>, <code class="language-plaintext highlighter-rouge">description</code> and <code class="language-plaintext highlighter-rouge">confirmLabel</code> properties are ignored if present.</li> <li>The client <em class="rfc">must</em> immediately open the URI from <code class="language-plaintext highlighter-rouge">@id</code> with the added <code class="language-plaintext highlighter-rouge">origin</code> query parameter. This <em class="rfc">should</em> be done in a new window or tab. Browser security rules prevent the client from knowing what is happening in the new tab, therefore the client can only wait for and detect the closing of the opened window or tab or frame.</li> <li>After the opened tab is closed, the client <em class="rfc">must</em> then use the related access token service, as described below.</li> </ul> <p>Non-user-driven clients simply access the URI from <code class="language-plaintext highlighter-rouge">@id</code> to obtain the access cookie, and then use the related access token service, as described below.</p> <p>An example service description for the Kiosk interaction pattern:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="c1">// ...</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/cookiebaker"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/kiosk"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Internal cookie granting service"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureHeader"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Ooops!"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureDescription"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Call Bob at ext. 1234 to reboot the cookie server"</span><span class="p">,</span><span class="w"> </span><span class="nl">"service"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// Access token service ...</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h4 id="external-interaction-pattern"> 2.1.6. External Interaction Pattern <a href="#external-interaction-pattern" class="anchorClass"></a> </h4> <p>For the External interaction pattern, the user is required to have acquired the access cookie by out of band means. If the access cookie is not present, the user will receive the failure messages. The interaction has the following steps:</p> <ul> <li>There is no user interaction before opening the <strong>access token</strong> service URI, and therefore any of the <code class="language-plaintext highlighter-rouge">label</code>, <code class="language-plaintext highlighter-rouge">header</code>, <code class="language-plaintext highlighter-rouge">description</code> and <code class="language-plaintext highlighter-rouge">confirmLabel</code> properties are ignored if present.</li> <li>There is no access cookie service. Any URI specified in the <code class="language-plaintext highlighter-rouge">@id</code> property <em class="rfc">must</em> be ignored.</li> <li>The client <em class="rfc">must</em> immediately use the related access token service, as described below.</li> </ul> <p>Non-user-driven clients simply use the related access token service with a previously acquired access cookie, as described below.</p> <p>An example service description for the External interaction pattern:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="c1">// ...</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/external"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"External Authentication Required"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureHeader"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Restricted Material"</span><span class="p">,</span><span class="w"> </span><span class="nl">"failureDescription"</span><span class="p">:</span><span class="w"> </span><span class="s2">"This material is not viewable without prior agreement"</span><span class="p">,</span><span class="w"> </span><span class="nl">"service"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// Access token service ...</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h3 id="access-token-service"> 2.2. Access Token Service <a href="#access-token-service" class="anchorClass"></a> </h3> <p>The client uses this service to obtain an access token which it then uses when requesting Description Resources. A request to the access token service must include any cookies for the content domain acquired from the user’s interaction with the corresponding access cookie service, so that the server can issue the access token.</p> <h4 id="service-description-1"> 2.2.1. Service Description <a href="#service-description-1" class="anchorClass"></a> </h4> <p>The access cookie service description <em class="rfc">must</em> include an access token service description following the template below:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="c1">// Access Cookie Service</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Login to Example Institution"</span><span class="p">,</span><span class="w"> </span><span class="c1">// Access Token Service</span><span class="w"> </span><span class="nl">"service"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/token"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/token"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">@id</code> property of the access token service <em class="rfc">must</em> be present, and its value <em class="rfc">must</em> be the URI from which the client can obtain the access token. The <code class="language-plaintext highlighter-rouge">profile</code> property <em class="rfc">must</em> be present and its value <em class="rfc">must</em> be <code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/token</code> to distinguish it from other services. There is no requirement to repeat the <code class="language-plaintext highlighter-rouge">@context</code> property included in the enclosing access cookie service description, and there are no other properties for this service.</p> <h4 id="the-json-access-token-response"> 2.2.2. The <abbr title="JavaScript Object Notation">JSON</abbr> Access Token Response <a href="#the-json-access-token-response" class="anchorClass"></a> </h4> <p>If the request has a valid cookie that the server recognises as having been issued by the access cookie service, the access token service response <em class="rfc">must</em> include a <abbr title="JavaScript Object Notation">JSON</abbr> (not <abbr title="JSON for Linking Data">JSON-LD</abbr>) object with the following structure:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"accessToken"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TOKEN_HERE"</span><span class="p">,</span><span class="w"> </span><span class="nl">"expiresIn"</span><span class="p">:</span><span class="w"> </span><span class="mi">3600</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">accessToken</code> property is <em class="rfc">required</em>, and its value is the access token to be passed back in future requests. The <code class="language-plaintext highlighter-rouge">expiresIn</code> property is <em class="rfc">optional</em> and, if present, the value is the number of seconds in which the access token will cease to be valid.</p> <p>Once obtained, the access token <em class="rfc">must</em> be passed back to the server on all future requests for Description Resources by adding an <code class="language-plaintext highlighter-rouge">Authorization</code> request header, with the value <code class="language-plaintext highlighter-rouge">Bearer</code> followed by a space and the access token, such as:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Authorization: Bearer TOKEN_HERE </code></pre></div></div> <p>This authorization header <em class="rfc">should</em> be added to all requests for resources from the same domain and subdomains that have a reference to the service, regardless of which <abbr title="Application Programming Interface">API</abbr> is being interacted with. It <em class="rfc">must not</em> be sent to other domains.</p> <h4 id="interaction-for-non-browser-client-applications"> 2.2.3. Interaction for Non-Browser Client Applications <a href="#interaction-for-non-browser-client-applications" class="anchorClass"></a> </h4> <p>The simplest access token request comes from a non-browser client that can send cookies across domains, where the <abbr title="Cross-Origin Resource Sharing">CORS</abbr> restrictions do not apply. An example URL:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-plaintext urltemplate highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://authentication.example.org/token </code></pre></div></div> <p>Would result in the <abbr title="Hypertext Transfer Protocol">HTTP</abbr> Request:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-plaintext urltemplate highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /token HTTP/1.1 Cookie: <cookie-acquired-during-login> </code></pre></div></div> <p>The response is the <abbr title="JavaScript Object Notation">JSON</abbr> access token object with the media type <code class="language-plaintext highlighter-rouge">application/json</code>:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"accessToken"</span><span class="p">:</span><span class="w"> </span><span class="s2">"TOKEN_HERE"</span><span class="p">,</span><span class="w"> </span><span class="nl">"expiresIn"</span><span class="p">:</span><span class="w"> </span><span class="mi">3600</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h4 id="interaction-for-browser-based-client-applications"> 2.2.4. Interaction for Browser-Based Client Applications <a href="#interaction-for-browser-based-client-applications" class="anchorClass"></a> </h4> <p>If the client is a JavaScript application running in a web browser, it needs to make a direct request for the access token and store the result. The client can’t use <code class="language-plaintext highlighter-rouge">XMLHttpRequest</code> because it can’t include the access cookie in a cross-domain request. Instead, the client <em class="rfc">must</em> open the access token service in a frame using an <code class="language-plaintext highlighter-rouge">iframe</code> element and be ready to receive a message posted by script in that frame using the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" title="window.postMessage">postMessage <abbr title="Application Programming Interface">API</abbr></a>. To trigger this behavior, the client <em class="rfc">must</em> append the following query parameters to the access token service URI, and open this new URI in the frame.</p> <table class="api-table"> <thead> <tr> <th>Parameter</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>messageId</td> <td>A string that both prompts the server to respond with a web page instead of <abbr title="JavaScript Object Notation">JSON</abbr>, and allows the client to match access token service requests with the messages received. If a client has no need to interact with multiple token services, it can use a dummy value for the parameter, e.g., <code class="language-plaintext highlighter-rouge">messageId=1</code>.</td> </tr> <tr> <td>origin</td> <td>A string containing the origin of the page in the window, consisting of a protocol, hostname and optionally port number, as described in the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage" title="window.postMessage">postMessage <abbr title="Application Programming Interface">API</abbr></a> specification.</td> </tr> </tbody> </table> <p>For example, a client instantiated by the page at <code class="language-plaintext highlighter-rouge">https://client.example.com/viewer/index.html</code> would request:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>https://authentication.example.org/token?messageId=1&origin=https://client.example.com/ </code></pre></div></div> <p>When the server receives a request for the access token service with the <code class="language-plaintext highlighter-rouge">messageId</code> parameter, it <em class="rfc">must</em> respond with an <abbr title="HyperText Markup Language">HTML</abbr> web page rather than raw <abbr title="JavaScript Object Notation">JSON</abbr>. The web page <em class="rfc">must</em> contain script that sends a message to the opening page using the postMessage <abbr title="Application Programming Interface">API</abbr>. The message body is the <abbr title="JavaScript Object Notation">JSON</abbr> access token object, with the value of the supplied <code class="language-plaintext highlighter-rouge">messageId</code> as an extra property, as shown in the examples in the next section.</p> <p>The server <em class="rfc">may</em> use the origin information for further authorization logic, even though the user is already authenticated. For example, the server may trust only specific domains for certain actions like creating or deleting resources compared to simply reading them. If the client sends an incorrect value, it will not receive the posted response, as the postMessage <abbr title="Application Programming Interface">API</abbr> will not dispatch the event. The <code class="language-plaintext highlighter-rouge">targetOrigin</code> parameter of the <code class="language-plaintext highlighter-rouge">postMessage()</code> function call <em class="rfc">must</em> be the origin provided in the request.</p> <p>The frame <em class="rfc">should not</em> be shown to the user. It is a mechanism for cross-domain messaging. The client <em class="rfc">must</em> register an event listener to receive the message that the token service page in the frame will send. The client can reuse the same listener and frame for multiple calls to the access token service, or it can create new ones for each invocation.</p> <p>The exact implementation will vary but <em class="rfc">must</em> include features equivalent to the following steps.</p> <p>The client must first register an event listener to receive a cross domain message:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">window</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">"</span><span class="s2">message</span><span class="dl">"</span><span class="p">,</span> <span class="nx">receive_message</span><span class="p">);</span> <span class="kd">function</span> <span class="nx">receive_message</span><span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span> <span class="nx">data</span> <span class="o">=</span> <span class="nx">event</span><span class="p">.</span><span class="nx">data</span><span class="p">;</span> <span class="kd">var</span> <span class="nx">token</span><span class="p">,</span> <span class="nx">error</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">(</span><span class="dl">'</span><span class="s1">accessToken</span><span class="dl">'</span><span class="p">))</span> <span class="p">{</span> <span class="nx">token</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">accessToken</span><span class="p">;</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// handle error condition</span> <span class="p">}</span> <span class="c1">// ...</span> <span class="p">}</span> </code></pre></div></div> <p>It can then open the access token service in a frame:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">'</span><span class="s1">messageFrame</span><span class="dl">'</span><span class="p">).</span><span class="nx">src</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">https://authentication.example.org/token?messageId=1234&origin=https://client.example.com/</span><span class="dl">'</span><span class="p">;</span> </code></pre></div></div> <p>The server response will then be a web page with a media type of <code class="language-plaintext highlighter-rouge">text/html</code> that can post a message to the registered listener:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><html></span> <span class="nt"><body></span> <span class="nt"><script></span> <span class="nb">window</span><span class="p">.</span><span class="nx">parent</span><span class="p">.</span><span class="nx">postMessage</span><span class="p">(</span> <span class="p">{</span> <span class="dl">"</span><span class="s2">messageId</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">1234</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">accessToken</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">TOKEN_HERE</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">expiresIn</span><span class="dl">"</span><span class="p">:</span> <span class="mi">3600</span> <span class="p">},</span> <span class="dl">'</span><span class="s1">https://client.example.com/</span><span class="dl">'</span> <span class="p">);</span> <span class="nt"></script></span> <span class="nt"></body></span> <span class="nt"></html></span> </code></pre></div></div> <h4 id="using-the-access-token"> 2.2.5. Using the Access Token <a href="#using-the-access-token" class="anchorClass"></a> </h4> <p>The access token is sent on all subsequent requests for Description Resources. For example, a request for the image information in the Image <abbr title="Application Programming Interface">API</abbr> would look like:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-plaintext urltemplate highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET /iiif/identifier/info.json HTTP/1.1 Authorization: Bearer TOKEN_HERE </code></pre></div></div> <h4 id="access-token-error-conditions"> 2.2.6. Access Token Error Conditions <a href="#access-token-error-conditions" class="anchorClass"></a> </h4> <p>The response from the access token service may be an error. The error <em class="rfc">must</em> be supplied as <abbr title="JavaScript Object Notation">JSON</abbr> with the following template. For browser-based clients using the postMessage <abbr title="Application Programming Interface">API</abbr>, the error object must be sent to the client via JavaScript, in the same way the access token is sent. For direct requests the response body is the raw <abbr title="JavaScript Object Notation">JSON</abbr>.</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"error"</span><span class="p">:</span><span class="w"> </span><span class="s2">"ERROR_TYPE_HERE"</span><span class="p">,</span><span class="w"> </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"..."</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>The value of the <code class="language-plaintext highlighter-rouge">error</code> property <em class="rfc">must</em> be one of the types in the following table:</p> <table class="api-table"> <thead> <tr> <th>Type</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><code class="language-plaintext highlighter-rouge">invalidRequest</code></td> <td>The service could not process the information sent in the body of the request.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">missingCredentials</code></td> <td>The request did not have the credentials required.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">invalidCredentials</code></td> <td>The request had credentials that are not valid for the service.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">invalidOrigin</code></td> <td>The request came from a different origin than that specified in the access cookie service request, or an origin that the server rejects for other reasons.</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">unavailable</code></td> <td>The request could not be fulfilled for reasons other than those listed above, such as scheduled maintenance.</td> </tr> </tbody> </table> <p>The <code class="language-plaintext highlighter-rouge">description</code> property is <em class="rfc">optional</em> and may give additional human-readable information about the error.</p> <p>When returning <abbr title="JavaScript Object Notation">JSON</abbr> directly, the service <em class="rfc">must</em> use the appropriate <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status code for the response to describe the error (for example 400, 401 or 503). The postMessage web page response <em class="rfc">must</em> use the 200 <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status code to ensure that the body is received by the client correctly.</p> <h3 id="logout-service"> 2.3. Logout Service <a href="#logout-service" class="anchorClass"></a> </h3> <p>In the case of the Login interaction pattern, the client will need to know if and where the user can go to log out. For example, the user may wish to close their session on a public terminal, or to log in again with a different account.</p> <h4 id="service-description-2"> 2.3.1. Service Description <a href="#service-description-2" class="anchorClass"></a> </h4> <p>If the authentication system supports users intentionally logging out, there <em class="rfc">should</em> be a logout service associated with the access cookie service following the template below:</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="c1">// ...</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Login to Example Institution"</span><span class="p">,</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/token"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/token"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/logout"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/logout"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Logout from Example Institution"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>The value of the <code class="language-plaintext highlighter-rouge">profile</code> property <em class="rfc">must</em> be <code class="language-plaintext highlighter-rouge">http://iiif.io/api/auth/1/logout</code>.</p> <h4 id="interaction"> 2.3.2. Interaction <a href="#interaction" class="anchorClass"></a> </h4> <p>The client <em class="rfc">should</em> present the results of an <abbr title="Hypertext Transfer Protocol">HTTP</abbr> <code class="language-plaintext highlighter-rouge">GET</code> request on the service’s URI in a separate tab or window with a URL bar. At the same time, the client <em class="rfc">should</em> discard any access token that it has received from the corresponding service. The server <em class="rfc">should</em> reset the user’s logged in status when this request is made and delete the access cookie.</p> <h3 id="example-description-resource-with-authentication-services"> 2.4. Example Description Resource with Authentication Services <a href="#example-description-resource-with-authentication-services" class="anchorClass"></a> </h3> <p>The example below is a complete image information response for an example image with all of the authentication services.</p> <script src="/api/assets/js/copyCodeBlock.js"></script> <div class="code-header"> <button class="copy-button button is-small is-primary" aria-label="Copy code to clipboard"></button> </div> <div class="language-json-doc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/image/2/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"https://www.example.org/images/image1"</span><span class="p">,</span><span class="w"> </span><span class="nl">"protocol"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/image"</span><span class="p">,</span><span class="w"> </span><span class="nl">"width"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">600</span><span class="p">,</span><span class="w"> </span><span class="nl">"height"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">400</span><span class="p">,</span><span class="w"> </span><span class="nl">"sizes"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="nl">"width"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">150</span><span class="p">,</span><span class="w"> </span><span class="nl">"height"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">100</span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="nl">"width"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">600</span><span class="p">,</span><span class="w"> </span><span class="nl">"height"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">400</span><span class="p">}</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"profile"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"http://iiif.io/api/image/2/level2.json"</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"formats"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"gif"</span><span class="p">,</span><span class="w"> </span><span class="s2">"pdf"</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"qualities"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"color"</span><span class="p">,</span><span class="w"> </span><span class="s2">"gray"</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"supports"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"canonicalLinkHeader"</span><span class="p">,</span><span class="w"> </span><span class="s2">"rotationArbitrary"</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">],</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/context.json"</span><span class="p">,</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/login"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Login to Example Institution"</span><span class="p">,</span><span class="w"> </span><span class="nl">"service"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/token"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/token"</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://authentication.example.org/logout"</span><span class="p">,</span><span class="w"> </span><span class="nl">"profile"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://iiif.io/api/auth/1/logout"</span><span class="p">,</span><span class="w"> </span><span class="nl">"label"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Logout from Example Institution"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h2 id="interaction-with-access-controlled-resources"> 3. Interaction with Access-Controlled Resources <a href="#interaction-with-access-controlled-resources" class="anchorClass"></a> </h2> <p>This section describes how clients use the services above when interacting with Content Resources and Description Resources.</p> <p>These interactions rely on requests for Description Resources returning <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status codes <code class="language-plaintext highlighter-rouge">200</code>, <code class="language-plaintext highlighter-rouge">302</code>, and <code class="language-plaintext highlighter-rouge">401</code> in different circumstances. In cases other than <code class="language-plaintext highlighter-rouge">302</code>, the body of the response <em class="rfc">must</em> be a valid Description Resource because the client needs to see the Authentication service descriptions in order to follow the appropriate workflow. Any response with a <code class="language-plaintext highlighter-rouge">302</code> status code will never be seen by browser-based client script interacting via the <code class="language-plaintext highlighter-rouge">XMLHttpRequest</code> <abbr title="Application Programming Interface">API</abbr>. The reported response will be the final one in the chain, and therefore the body of redirection responses is not required to be the Description Resource’s representation.</p> <h3 id="all-or-nothing-access"> 3.1. All or Nothing Access <a href="#all-or-nothing-access" class="anchorClass"></a> </h3> <p>If the server does not support multiple tiers of access to a Content Resource, and the user is not authorized to access it, then the server <em class="rfc">must</em> return a response with a <code class="language-plaintext highlighter-rouge">401</code> (Unauthorized) <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status code for the corresponding Description Resource.</p> <p>If the user is authorized for a Description Resource, the client can assume that requests for the described Content Resources will also be authorized. Requests for the Content Resources rely on the access cookie to convey the authorization state.</p> <h3 id="tiered-access"> 3.2. Tiered Access <a href="#tiered-access" class="anchorClass"></a> </h3> <p>If a server supports multiple tiers of access, then it <em class="rfc">must</em> use a different identifier for each Description Resource and its corresponding Content Resource(s). For example, there <em class="rfc">must</em> be different Image Information documents (<code class="language-plaintext highlighter-rouge">/info.json</code>) at different URIs for each tier. When refering to Description Resources that have multiple tiers of access, systems <em class="rfc">should</em> use the identifier of the version that an appropriated authorized user should see. For example, when refering to an Image service from a Manifest, the reference would normally be to the highest quality image version rather than a degraded version.</p> <p>When a Description Resource is requested and the user is not authorized to access it and there are lower tiers available, the server <em class="rfc">must</em> issue a <code class="language-plaintext highlighter-rouge">302</code> (Found) <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status response to redirect to the Description Resource of a lower tier.</p> <p>When there are no lower tiers and the user is not authorized to access the current Description Resource, the server <em class="rfc">must</em> issue a <code class="language-plaintext highlighter-rouge">401</code> (Unauthorized) response. The client <em class="rfc">should</em> present information about the Login and/or Clickthrough services included in the Description Resource to allow the user to attempt to authenticate.</p> <h2 id="workflow-from-the-browser-client-perspective"> 4. Workflow from the Browser Client Perspective <a href="#workflow-from-the-browser-client-perspective" class="anchorClass"></a> </h2> <table class="ex_table"> <tbody> <tr> <td> <img style="max-width: 1000px" src="img/auth-flow-client.png" alt="Server Authentication Flow" class="fullPct" /> <p><strong>1</strong> Client Authentication Workflow</p> </td> </tr> </tbody> </table> <p>Browser-based clients will perform the following workflow in order to access access controlled resources:</p> <ul> <li>The client requests the Description Resource and checks the status code of the response.</li> <li>If the response is a 200, <ul> <li>The client checks whether the <code class="language-plaintext highlighter-rouge">@id</code> property in the response is the same URI as was requested.</li> <li>If it is, then the client can proceed to request the Content Resource.</li> <li>If the URIs are different, then the resource is from a different tier from the requested one. The 200 status implies that the resource is available to be used, and the client can therefore render the resource. At the same time, the client checks for authentication services in the <abbr title="JavaScript Object Notation">JSON</abbr> received.</li> </ul> </li> <li>If the response is a 401, <ul> <li>The client does not have access to the Content Resource, and thus the client checks for authentication services in the <abbr title="JavaScript Object Notation">JSON</abbr> received.</li> </ul> </li> <li> <p>If the response is neither 200 nor 401, the client must handle other <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status codes</p> </li> <li>When the client checks for authentication services, it first checks the authentication services: <ul> <li>First it looks for a External interaction pattern as this does not require any user interaction. If present, it opens the Access Token service to see if the cookie has already been obtained.</li> <li>If not, it checks for a Kiosk interaction pattern as it does not involve user interaction. If present, it opens the Access Cookie service in a separate window.</li> <li>If not, it checks for a Clickthrough interaction pattern. If present, it renders the description of the service and a confirmation button to prompt for the user to click through. Once the user has clicked the confirmation, it opens the Access Cookie service in a separate window.</li> <li>If not, it presents any Login interaction patterns available and prompts the user to login with one of them. When the user selects the realm to log in at, which takes the Access Cookie service role, it opens that realm’s user interface in a separate window.</li> <li>When the Access Cookie service window closes, either automatically or by the user, the client Opens the Access Token Service.</li> </ul> </li> <li>After the Access Token service has been requested, if the client receives a token, it tries again to read the Description Resource with the newly acquired credentials. <ul> <li>If the client instead receives an error, it returns to look for further authentication services to interact with.</li> <li>If there are no further authentication services, then the user does not have the credentials to interact with any of the Content Resource versions, and the client cannot display anything.</li> </ul> </li> </ul> <p>Please note that the server implementation involves providing <code class="language-plaintext highlighter-rouge">302</code> status responses to redirect the client from the requested tier to another tier if the user is not yet authorized to see the resource. The browser-based client does not see these responses, and hence tests whether the identifier of the resource is the same as the one requested, rather than for the <abbr title="Hypertext Transfer Protocol">HTTP</abbr> status code.</p> <h2 id="appendices"> Appendices <a href="#appendices" class="anchorClass"></a> </h2> <h3 id="a-implementation-notes"> A. Implementation Notes <a href="#a-implementation-notes" class="anchorClass"></a> </h3> <p>Guidance for implementers is provided in a separate <a href="implementation/" title="IIIF Authentication: Implementation Notes">Implementation Notes</a> document. The notes cover many details relating to implementation of this specification in browser-based JavaScript applications, and additional security considerations.</p> <h3 id="b-versioning"> B. Versioning <a href="#b-versioning" class="anchorClass"></a> </h3> <p>Starting with version 0.9.0, this specification follows <a href="http://semver.org/spec/v2.0.0.html" title="Semantic Versioning 2.0.0">Semantic Versioning</a>. See the note <a href="/api/annex/notes/semver/" title="Versioning of APIs">Versioning of APIs</a> for details regarding how this is implemented.</p> <h3 id="c-acknowledgments"> C. Acknowledgments <a href="#c-acknowledgments" class="anchorClass"></a> </h3> <p>The production of this document was generously supported by a grant from the <a href="http://www.mellon.org/" title="The Andrew W. Mellon Foundation">Andrew W. Mellon Foundation</a>.</p> <p>Many thanks to the members of the <a href="https://iiif.io/community/" title="IIIF Community"><abbr title="International Image Interoperability Framework">IIIF</abbr> Community</a> for their continuous engagement, innovative ideas and feedback.</p> <h3 id="d-change-log"> D. Change Log <a href="#d-change-log" class="anchorClass"></a> </h3> <table class="api-table first-col-normal"> <thead> <tr> <th>Date</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td>2017-01-19</td> <td>Version 1.0 (Alchemical Key)</td> </tr> <tr> <td>2016-10-05</td> <td>Version 0.9.4 (Incrementing Integer) add to security notes</td> </tr> <tr> <td>2016-08-22</td> <td>Version 0.9.3 (Wasabi KitKat) separate profiles, remove client identity service, add query parameters</td> </tr> <tr> <td>(unreleased)</td> <td>Version 0.9.2 (unnamed) postMessage instead of <abbr title="JavaScript Object Notation with Padding">JSONP</abbr></td> </tr> <tr> <td>2015-10-30</td> <td>Version 0.9.1 (Table Flip) add missing @context, clarifications</td> </tr> <tr> <td>2015-07-28</td> <td>Version 0.9.0 (unnamed) draft</td> </tr> </tbody> </table> </div> </div> </div> </section> <footer id="footer" class="footer"> <div class="container"> <div class="columns"> <div class="navbar-brand column is-half"> <a class="navbar-item" href="/api/"> <img src="/api/assets/images/logos/logo-sm.png" alt="IIIF logo" height="28"> <span class="brand-title blue-text">International Image Interoperability Framework</span> </a> <p>IIIF is a set of open standards for delivering high-quality, attributed digital objects online at scale. It’s also an international community developing and implementing the IIIF APIs. IIIF is backed by a consortium of leading cultural institutions.</p> </div> <div class="column"></div> <div class="column menu-column"> <h4>About</h4> <ul> <li> <a href="https://iiif.io/get-started/how-iiif-works">How IIIF Works</a> </li> <li> <a href="/api">APIs & Documentation</a> </li> <li> <a href="https://iiif.io/demos">Demos</a> </li> <li> <a href="https://iiif.io/guides">Tutorials & Guides</a> </li> <li> <a href="https://iiif.io/privacy">Privacy policy</a> </li> </ul> </div> <div class="column menu-column"> <h4>Stay Connected</h4> <ul> <li> <a href="https://iiif.io/news-and-events">News & Events</a> </li> <li> <a href="https://iiif.io/newsletter">Join Newsletter</a> </li> <li> <a href="https://iiif.io/community/groups">Community Groups</a> </li> <li> <a href="https://iiif.io/community/consortium">Consortium</a> </li> <li> <a href="https://iiif.io/contact">Contact Us</a> </li> </ul> </div> </div> </div> </footer><script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script> <script type="text/javascript" src="//cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js"></script> <script type="text/javascript" src="/api/assets/js/carouselInit.js"></script> <!-- Read the Formbutton docs at formspree.io/formbutton/docs. See more examples at codepen.io/formspree --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.css" /> <script src="https://formspree.io/js/formbutton-v1.min.js" defer></script> <script> /* paste this line in verbatim */ window.formbutton=window.formbutton||function(){(formbutton.q=formbutton.q||[]).push(arguments)}; /* customize formbutton below*/ formbutton("create", { action: "https://formspree.io/f/xbjwjlbn", title: "Feedback", fields: [ { type: "radio", name: "feedback_type", value: "Comment", label: "Comment", style: { display: "inline-block", "padding-right": "10px" } }, { type: "radio", name: "feedback_type", value: "Correction", label: "Correction", style: { display: "inline-block", "padding-right": "10px" } }, { type: "radio", name: "feedback_type", value: "Bug", label: "Bug", style: { display: "inline-block", "padding-right": "10px" } }, { type: "email", label: "Email:", name: "Email", required: true, placeholder: "your@email.com" }, { type: "textarea", label: "Message:", name: "Message", placeholder: "We want to hear from you! Enter your feedback here.", }, { type: "submit", value: "Submit" }, { type: "hidden", name: "Page", value: window.location.pathname.replaceAll('/','|'), style: { display: "none" } } ], buttonImg: "<i class='fas fa-comment' style='font-size:24px'/>", styles: { title: { backgroundColor: "#0d232d" }, button: { backgroundColor: "#0d232d" } } }); </script> </body> </html>