RapiDocv11.0
Interactive Authentication Tutorial

Setting up OAuth 2.0
in RapiDoc

A clear, step-by-step tutorial to configure OAuth 2.0 and OpenID Connect in your API documentation. Connect to any Identity Provider (Auth0, Okta, Azure AD, Keycloak, Duende), authenticate via secure popups, and execute live API calls with zero backend relay code.

2 Files
Zero-Config Setup
Just index.html and oauth-receiver.html. No custom JavaScript or backend proxy needed.
PKCE RFC 7636
Bulletproof Security
Native PKCE support removes the need to expose client secrets in browser documentation.
100% Automatic
Bearer Token Injection
Acquired tokens are stored in memory and automatically attached to interactive TRY calls.
Any IdP
Universal Compatibility
Works with Auth0, Okta, Azure AD / Entra ID, Keycloak, Duende IdentityServer, AWS Cognito, etc.
Fast Track

The 30-Second Summary

Setting up OAuth 2.0 in RapiDoc requires only 3 simple steps:

1

Register Client with Identity Provider

In your IdP console (Auth0, Okta, Azure AD, etc.), create a public client and register your redirect URI:
https://your-domain.com/oauth-receiver.html

2

Create index.html

Add the <rapi-doc> element pointing to your OpenAPI spec. RapiDoc automatically manages the popup lifecycle.

3

Create oauth-receiver.html

Create a file named oauth-receiver.html containing <oauth-receiver> in the same folder.

✨
You're All Set!
Developers can click "Authorize" in your docs, sign in via a popup window, and immediately execute authenticated API calls!
How It Works

Architecture & Authorization Code Flow

When a user initiates authentication, RapiDoc coordinates between the documentation window, a secure popup window, and your authorization server.

OAuth 2.0 Authorization Code Flow Diagram: Showing step-by-step communication between index.html with rapi-doc, oauth-receiver.html popup, and the Authorization Server token and authorize endpoints.
Figure 1: RapiDoc OAuth 2.0 Authorization Code flow with <oauth-receiver> popup relay and PKCE token exchange.
1

User Clicks "Authorize"

The developer clicks "Authorize" on an endpoint or the top security modal. <rapi-doc> opens a lightweight browser popup pointing to oauth-receiver.html.

2

Redirect to Identity Provider

<oauth-receiver> immediately constructs the authorization URL with client_id, redirect_uri, requested scopes, state, and PKCE code challenge, then redirects the popup to your IdP.

3

User Consent & Login

The developer authenticates directly on the Identity Provider login page and grants consent to requested scopes.

4

Callback to Receiver Popup

Upon success, the IdP redirects the popup back to your registered redirect URI: oauth-receiver.html?code=AUTH_CODE&state=STATE.

5

Local Relay & Popup Closure

The <oauth-receiver> custom element extracts the code, securely transmits it to <rapi-doc> in the parent window via window.postMessage(), and automatically closes itself.

6

Token Exchange & Automatic Header Injection

<rapi-doc> calls your IdP tokenUrl to exchange the authorization code for an Access Token, stores it in memory, and attaches Authorization: Bearer <token> to all interactive TRY calls.

Step-by-Step Tutorial

Complete Implementation Guide

Follow these detailed steps to set up OAuth 2.0 authentication from scratch.

Step 1

Register Your Application with your Identity Provider

Before configuring RapiDoc, register your documentation portal as a client application in your Identity Provider (IdP). Examples include Auth0, Okta, Microsoft Entra ID (Azure AD), Keycloak, or Duende IdentityServer.

Key Registration Requirements:

  • Application Type: Single Page Application (SPA) or Public Native Client.
  • Allowed Grant Types:Authorization Code with PKCE.
  • Redirect URI: The exact URL where your receiver page is served. For example:
    http://localhost:8080/oauth-receiver.html (for local testing)
    https://api.yourcompany.com/docs/oauth-receiver.html (for production)
  • Allowed Origins / CORS: Ensure your documentation origin is permitted on the token and authorize endpoints.
💡
Testing with our Pre-Configured Demo Server
For this tutorial and instant testing, you can use Duende IdentityServer's public demo instance:
Auth URL:https://demo.duendesoftware.com/connect/authorize
Token URL:https://demo.identityserver.io/connect/token
Public Client ID:interactive.public (PKCE enabled, no secret required)
Confidential Client ID:interactive.confidential.short (Secret: secret)
Step 2

Create your Main Documentation Page (index.html)

Create your primary documentation HTML file. Import RapiDoc from a CDN or local bundle and add the <rapi-doc> element pointing to your OpenAPI specification.

index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>API Documentation</title>
    <!-- 1. Load RapiDoc Web Component from CDN -->
    <script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
  </head>
  <body>
    <!-- 2. Embed <rapi-doc> pointing to your OpenAPI spec -->
    <rapi-doc 
      spec-url="https://mrin9.github.io/RapiDoc/specs/oauth.yaml"
      render-style="focused"
      allow-try="true"
    > </rapi-doc>
  </body>
</html>
📂
Custom Receiver Path (Optional)
By default, RapiDoc looks for oauth-receiver.html in the current folder. If your receiver file is in a custom subfolder, supply the oauth-receiver attribute:
custom-path.html
<!-- If oauth-receiver.html is hosted in a different path or subdirectory: -->
<rapi-doc 
  spec-url="/specs/api.yaml"
  oauth-receiver="/auth/oauth-receiver.html"
> </rapi-doc>
Step 3

Create the OAuth Receiver Callback Page (oauth-receiver.html)

Create a second HTML file named oauth-receiver.html in the same directory. This file contains RapiDoc's companion <oauth-receiver> element.

oauth-receiver.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>OAuth Receiver</title>
    <!-- Load the same RapiDoc script -->
    <script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
  </head>
  <body>
    <!-- The companion custom element that relays auth codes and closes the popup -->
    <oauth-receiver> </oauth-receiver>
  </body>
</html>

What does <oauth-receiver> do automatically?

  • Zero Custom JavaScript: You do NOT need to write query string parsers, state verifiers, or window messaging code.
  • Extracts Auth Code: Reads the authorization code (?code=...) or implicit token (#access_token=...) from the URL.
  • Relays to Main Window: Sends the credentials to <rapi-doc> in the parent window via window.postMessage() (with an automatic fallback to sessionStorage).
  • Auto-Closes Popup: Closes the popup window immediately after successful transmission.
Step 4

Configure OAuth 2.0 in your OpenAPI Specification

In your OpenAPI 3.0 or 3.1 specification, declare your OAuth 2.0 security scheme under components.securitySchemes, and protect relevant endpoints by referencing it under security:

openapi.yaml
openapi: 3.0.3
info:
  title: Protected API Service
  version: "1.0.0"
servers:
  - url: https://demo.duendesoftware.com

paths:
  /api/test:
    get:
      summary: Test Authenticated Endpoint
      security:
        - demo-oauth:
            - openid
            - email
            - profile
      responses:
        '200':
          description: Successful operation

components:
  securitySchemes:
    demo-oauth:
      type: oauth2
      description: Enterprise OAuth 2.0 Authorization Code flow
      flows:
        authorizationCode:
          authorizationUrl: https://demo.duendesoftware.com/connect/authorize
          tokenUrl: https://demo.identityserver.io/connect/token
          scopes:
            openid: OpenID Connect identity
            email: User email address
            profile: User profile information
Step 5

Supercharge Developer UX with RapiDoc Vendor Extensions

To make authentication frictionless for developers testing your API, RapiDoc provides custom OpenAPI vendor extensions (x-*) to pre-populate credentials and enforce modern security protocols like PKCE:

ExtensionTypeApplicable LevelPurpose
x-client-idstringScheme or FlowPre-populates the Client ID input in the authorization modal, saving developers from manually entering it.
x-client-secretstringScheme or FlowPre-populates the Client Secret input. Intended strictly for test/sandbox credentials, never for production secrets.
x-default-scopesarray | stringScheme or FlowPre-selects specified scopes in the authorization dialog checkbox list (array of strings or space-separated list).
x-pkce-onlybooleanFlowWhen true, enforces PKCE (RFC 7636) and hides the Client Secret field completely from the authorization UI.
x-receive-token-inrequest-body | headerScheme or FlowSpecifies whether client credentials should be passed in request body (client_secret_post) or Authorization header (client_secret_basic) when calling the tokenUrl. Default is request-body.
x-receive-token-in-optionsarrayScheme or FlowLimits the client authentication options available in the UI dropdown (e.g. ["request-body", "header"]).
x-authorize-paramsobject | stringScheme or FlowCustom query parameters appended to authorizationUrl (e.g. proxy launch parameters, audience, prompt).
x-token-paramsobject | stringScheme or FlowCustom parameters included in the POST request body to tokenUrl (e.g. custom IdP proxy fields, audience, resource).

Specification Example with Vendor Extensions:

openapi-with-extensions.yaml
components:
  securitySchemes:
    # Scheme 1: Public Client (PKCE Enforced - Recommended for Documentation)
    public-oauth:
      type: oauth2
      description: Public client authorization flow with PKCE
      flows:
        authorizationCode:
          authorizationUrl: https://demo.duendesoftware.com/connect/authorize
          tokenUrl: https://demo.identityserver.io/connect/token
          scopes:
            openid: OpenID Connect identity
            profile: User profile information
            email: User email address

          # Pre-fill Client ID in the authorization dialog
          x-client-id: interactive.public

          # Pre-select default scopes in the checkbox list
          x-default-scopes:
            - openid
            - profile

          # Enforces PKCE: Hides client secret field entirely from the UI
          x-pkce-only: true

          # Custom query parameters sent to authorizationUrl (e.g. proxy launch parameters)
          x-authorize-params:
            launch: xyz123
            prompt: consent

          # Custom parameters sent in POST body to tokenUrl
          x-token-params:
            audience: https://api.example.com

    # Scheme 2: Sandbox / Confidential Client (With Pre-filled Test Secret)
    sandbox-oauth:
      type: oauth2
      description: Sandbox test scheme with credentials pre-populated
      
      # Scheme-level vendor extensions apply to all flows within this scheme
      x-client-id: interactive.confidential.short
      x-client-secret: secret
      x-default-scopes: openid email
      x-receive-token-in: request-body
      
      flows:
        authorizationCode:
          authorizationUrl: https://demo.duendesoftware.com/connect/authorize
          tokenUrl: https://demo.identityserver.io/connect/token
          scopes:
            openid: OpenID Connect
            email: Email address

Customizing Parameters via Attributes & Dynamic Events:

When working with Identity Provider proxies (such as Keycloak proxies requiring a launch context token), multi-tenant auth gateways, or token endpoints requiring custom parameters (audience, resource), you can customize parameters statically using attributes or dynamically via DOM lifecycle events:

custom-oauth-params.html
<!-- Option 1: Static / Semi-Static via HTML Attributes -->
<rapi-doc 
  spec-url="/specs/api.yaml"
  additional-authorize-params='{"launch": "xyz123", "prompt": "consent"}'
  additional-token-params='{"audience": "https://api.example.com"}'
></rapi-doc>

<!-- Option 2: Dynamic Programmatic Interception via Events -->
<script>
  const rapidocEl = document.querySelector('rapi-doc');

  // Intercept & inject dynamic query parameters before opening the authorization window
  rapidocEl.addEventListener('before-authorize', (e) => {
    const { securitySchemeId, flowType, authUrl, authParams } = e.detail;
    // authParams is a live URLSearchParams instance
    authParams.set('launch', sessionStorage.getItem('launch_context') || 'default-launch');
    authParams.set('tenant', window.currentTenantId);
    console.log('Opening authorization URL with customized params:', authParams.toString());
  });

  // Intercept & inject dynamic body parameters or headers before calling the token endpoint
  rapidocEl.addEventListener('before-token-request', (e) => {
    const { securitySchemeId, grantType, tokenUrl, params, headers } = e.detail;
    // params is a live URLSearchParams instance for the POST request body
    params.set('resource', 'https://api.mycompany.com');
    // headers is a live Headers instance
    headers.set('X-Device-Fingerprint', getDeviceFingerprint());
  });
</script>
Step 6

Test Authenticated Requests in the Interactive Console

Open index.html in your browser through a web server (e.g., using npx serve, Live Server, or Vite).

1
Click the "Authorize" button

Located in RapiDoc's top security bar or beside any protected endpoint with a padlock icon.

2
Select Scopes & Initiate

Verify that your Client ID and default scopes are pre-selected, then click "Authorize". A popup window will launch.

3
Authenticate at your IdP

Log in and authorize access. The popup will automatically close and return you to RapiDoc.

4
Execute Authenticated "TRY" Calls

The lock icon will turn active. Every request you make from the built-in console will automatically include Authorization: Bearer <token>!

Want to see it in action right now?

Test the full authorization flow live with pre-configured IdentityServer credentials in our sandbox demo.

Open Live OAuth Demo ↗
Troubleshooting Guide

Common Gotchas & Solutions

Running into issues during setup? Here are the top five configuration issues and how to resolve them quickly.

Redirect URI Mismatch

Your Identity Provider returns an error like "Invalid redirect_uri" or "redirect_uri_mismatch".

Solution: Ensure the redirect URI registered in your IdP console matches the exact URL of oauth-receiver.html, including protocol, port, and trailing path:
  • Exact port required: http://localhost:3000/oauth-receiver.html
  • Case sensitivity: oauth-receiver.html (all lowercase)

CORS Error on Token Endpoint

The authorization code is acquired, but the browser console displays a CORS network failure when calling tokenUrl.

Solution: Because RapiDoc runs entirely in the browser, your IdP's tokenUrl must respond with standard CORS headers:
  • Access-Control-Allow-Origin: * (or your docs origin)
  • Ensure your client registration is set to SPA / Public Web in Auth0, Okta, or Azure AD.

Popup Window Blocked

Clicking Authorize does not open the authentication window.

Solution: Browsers restrict popups that are not triggered by a direct user gesture:
  • Always trigger authorization by clicking the "Authorize" button directly.
  • Check your browser address bar for popup blocking indicators and click "Always allow popups from this site".

Client Secret Exposure

Committing client secrets into public OpenAPI specs compromises security.

Solution: Use PKCE for public documentation:
  • Add x-pkce-only: true under the flow definition.
  • This removes the client secret input from the UI and relies on dynamic cryptographic code challenges (RFC 7636).
  • Only use x-client-secret in internal mock or test sandboxes.

Multiple Credentials / Auth Method Mismatch

Your Identity Provider (e.g. OpenIddict, Duende, Keycloak) returns "Multiple client credentials cannot be specified" or rejects token exchange.

Solution: RFC 6749 Section 2.3.1 mandates using only one client authentication method per token request:
  • Default (Request Body): RapiDoc defaults to sending client credentials in the POST body (client_secret_post) to prevent browser CORS preflight failures.
  • Strict Basic Auth IdPs: If your server strictly requires HTTP Basic (client_secret_basic), add x-receive-token-in: header under your security scheme or select "Authorization Header" in the UI.
  • Public Clients (PKCE): For browser SPAs without a secret, use x-pkce-only: true; RapiDoc will transmit only client_id and code_verifier in the body without an Authorization header.