Configure Okta Authentication

SkillSecurity

Guides your agent through setting up Okta sign-on for a Webiny project instead of the default Cognito.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the Configure Okta Authentication skill

About this skill

Configuring Okta as an identity provider (IDP) for Webiny projects. Use this skill when the developer asks about Okta authentication, Okta SSO, replacing Cognito with Okta, setting up external identity providers, configuring OIDC authentication, mapping JWT claims to Webiny identities, or customizin

What this skill tells your AI

The instructions your AI receives, as published by webiny/webiny-js in skills/user-skills/configure-okta/SKILL.md and read by ahel’s review.

TL;DR

Webiny supports Okta as an external identity provider (IDP) to replace the default Cognito authentication. First, install the @webiny/okta package (using the same version as the webiny dependency in package.json). Then create two files: an API config class that maps Okta JWT claims to Webiny identity data (OktaIdpConfig), and a React extension component (<Okta />) that wires issuer URL, client ID, and the API config path. Register the extension in webiny.config.tsx, set two environment variables (OKTA_ISSUER, OKTA_CLIENT_ID), and deploy.

Pattern / Core Concept

Okta integration has two parts:

  1. API Config — A class implementing OktaIdpConfig.Interface that maps JWT token claims to Webiny's identity structure. Registered via OktaIdpConfig.createImplementation() (the universal DI pattern).
  2. Extension Component — A React component that renders <Okta /> from @webiny/okta, passing the issuer URL, client ID, and path to the API config file. The <Okta /> component handles environment variable injection, API extension registration, and Admin login screen setup automatically.

How <Okta /> Works Internally

The <Okta /> component (from @webiny/okta) is a defineExtension that:

  • Sets Lambda env vars: OKTA_ISSUER, OKTA_CLIENT_ID
  • Sets Admin app env vars: REACT_APP_IDP_TYPE=okta, REACT_APP_OKTA_ISSUER, REACT_APP_OKTA_CLIENT_ID
  • Registers the internal OktaIdpFeature API extension (OIDC token verification)
  • Registers your custom API config extension (identity mapping)
  • Registers the Admin Okta login screen extension

Reference Tables

OktaIdpConfig.Interface

MethodSignatureRequiredDescription
getIdentity(token: JwtPayload) => OktaIdentity | Promise<OktaIdentity>YesMaps JWT claims to Webiny identity data
verifyTokenClaims(token: JwtPayload) => void | Promise<void>NoCustom claim verification (throw to reject the token)

OktaIdentity (Return Type of getIdentity)

FieldTypeDescription
idstringUnique user ID (typically token["sub"])
displayNamestringUser's display name
rolesstring[]Webiny security roles to assign
teamsstring[]Webiny teams (optional, filter out falsy values)
profile{ firstName, lastName, email }User profile fields
contextobjectRuntime data (not stored in DB)

<Okta /> Component Props

PropTypeDescription
issuerstringOkta issuer URL (e.g., https://dev-xxx.okta.com)
clientIdstringOkta application client ID
apiConfigstringAbsolute path to the API config file

Environment Variables

VariableUsed ByDescription
OKTA_ISSUERAPI + AdminOkta issuer URL
OKTA_CLIENT_IDAPI + AdminOkta application client ID

Full Examples

Example 1: Basic Okta Configuration

Step 0: Install the @webiny/okta dependency

@webiny/okta is an optional dependency. Add it to package.json using the same version as the webiny dependency, then install:

# Check the webiny version in package.json, then add @webiny/okta with the same version
# For example, if "webiny": "^0.0.0-unstable.xxx":
yarn add @webiny/okta@^0.0.0-unstable.xxx

Important: After adding the dependency, tell the user to run yarn to install it. Do NOT run yarn automatically — let the user do it.

Step 1: Create the API config

Create extensions/okta/MyOktaConfig.ts:

import { OktaIdpConfig } from "@webiny/okta";

class MyIdpConfig implements OktaIdpConfig.Interface {
  getIdentity(token: OktaIdpConfig.JwtPayload) {
    return {
      id: String(token["sub"]),
      displayName: token["name"],
      roles: [token["webiny_group"]],
      teams: [token["team"]].filter(Boolean),
      profile: {
        firstName: token["first_name"],
        lastName: token["last_name"],
        email: token["email"]
      },
      context: {
        canAccessTenant: true,
        defaultTenant: "root"
      }
    };
  }
}

const MyOktaConfig = OktaIdpConfig.createImplementation({
  implementation: MyIdpConfig,
  dependencies: []
});

export default MyOktaConfig;

Step 2: Create the extension component

Create extensions/okta/MyOktaExtension.tsx:

import React from "react";
import { Okta } from "@webiny/okta";

export const MyOktaExtension = () => {
  return (
    <Okta
      issuer={String(process.env.OKTA_ISSUER)}
      clientId={String(process.env.OKTA_CLIENT_ID)}
      apiConfig={import.meta.dirname + "/MyOktaConfig.ts"}
    />
  );
};

Step 3: Register in webiny.config.tsx

import React from "react";
import { MyOktaExtension } from "./extensions/okta/MyOktaExtension.js";

export const Extensions = () => {
  return (
    <>
      {/* Replace <Cognito /> with Okta */}
      <MyOktaExtension />

      {/* ... other extensions ... */}
    </>
  );
};

Step 4: Set environment variables

Add to your .env file (or CI/CD environment):

OKTA_ISSUER=https://dev-xxxxx.okta.com/oauth2/default
OKTA_CLIENT_ID=your-okta-client-id

Step 5: Deploy

yarn webiny deploy

Example 2: Custom Claim Verification

If your Okta setup uses custom claims that need validation:

import { OktaIdpConfig } from "@webiny/okta";

class MyIdpConfig implements OktaIdpConfig.Interface {
  getIdentity(token: OktaIdpConfig.JwtPayload) {
    return {
      id: String(token["sub"]),
      displayName: token["name"],
      roles: [token["webiny_role"]],
      profile: {
        firstName: token["given_name"],
        lastName: token["family_name"],
        email: token["email"]
      },
      context: {
        canAccessTenant: true,
        defaultTenant: "root"
      }
    };
  }

  verifyTokenClaims(token: OktaIdpConfig.JwtPayload) {
    // Reject tokens without the required custom claim
    if (!token["webiny_role"]) {
      throw new Error("Token is missing the 'webiny_role' claim.");
    }

    // Reject tokens from unauthorized organizations
    const allowedOrgs = ["org_abc123", "org_def456"];
    if (!allowedOrgs.includes(token["org_id"] as string)) {
      throw new Error("User does not belong to an authorized organization.");
    }
  }
}

const MyOktaConfig = OktaIdpConfig.createImplementation({
  implementation: MyIdpConfig,
  dependencies: []
});

export default MyOktaConfig;

Example 3: Using DI Dependencies in Config

If your config needs access to other Webiny services (e.g., to look up tenant-specific roles):

import { OktaIdpConfig } from "@webiny/okta";
import { TenantContext } from "webiny/api/tenancy";

class MyIdpConfig implements OktaIdpConfig.Interface {
  constructor(private tenantContext: TenantContext.Interface) {}

  getIdentity(token: OktaIdpConfig.JwtPayload) {
    const tenant = this.tenantContext.getTenant();

    return {
      id: String(token["sub"]),
      displayName: token["name"],
      roles: [token["webiny_group"]],
      profile: {
        firstName: token["first_name"],
        lastName: token["last_name"],
        email: token["email"]
      },
      context: {
        canAccessTenant: true,
        defaultTenant: tenant?.id ?? "root"
      }
    };
  }
}

const MyOktaConfig = OktaIdpConfig.createImplementation({
  implementation: MyIdpConfig,
  dependencies: [TenantContext]
});

export default MyOktaConfig;

Quick Reference

Imports

// API config
import { OktaIdpConfig } from "@webiny/okta";

// Extension component
import { Okta } from "@webiny/okta";

Key Interfaces

InterfacePackagePurpose
OktaIdpConfig.Interface@webiny/oktaAPI-side JWT-to-identity mapping
OktaIdpConfig.JwtPayload@webiny/oktaJWT token payload type
OktaIdpConfig.IdentityData@webiny/oktaIdentity return type

File Structure

extensions/okta/
├── MyOktaConfig.ts        # API config (JWT claim mapping)
└── MyOktaExtension.tsx    # Extension component (Okta setup)

Registration

In webiny.config.tsx, replace <Cognito /> with <MyOktaExtension />.

Deploy

yarn webiny deploy        # Deploy all (Core + API + Admin)

Both API and Admin need to be redeployed since Okta affects both the backend (token verification, identity mapping) and the frontend (login screen).

Related Skills

  • webiny-dependency-injection — The universal DI pattern used by OktaIdpConfig.createImplementation()
  • webiny-project-structure — How webiny.config.tsx and extensions are organized
  • webiny-local-development — Deploying and testing your Okta configuration

Signals

GitHub stars
8k
Forks
679
Last commit
Sep 2026

ahel review

  • K1binfo
    installs-packages

Automated review, not a security audit. Ruleset v1+k2.

Advanced
Item type
skill
Key
webiny-configure-okta
Source
github.com/webiny/webiny-js