> ## Documentation Index
> Fetch the complete documentation index at: https://developer.box.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configure Okta

export const ProgressBar = ({pages = [], ...props}) => {
  const [currentStep, setCurrentStep] = useState(0);
  const [isDarkMode, setIsDarkMode] = useState(false);
  useEffect(() => {
    const checkDarkMode = () => {
      const isDark = document.documentElement.classList.contains('dark');
      console.log('ProgressBar - isDarkMode:', isDark);
      setIsDarkMode(isDark);
    };
    checkDarkMode();
    const observer = new MutationObserver(() => {
      checkDarkMode();
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['class']
    });
    return () => {
      observer.disconnect();
    };
  }, []);
  useEffect(() => {
    if (pages.length > 0) {
      const currentPath = window.location.pathname;
      const stepIndex = pages.findIndex(page => {
        const pagePath = page.startsWith('/') ? page : `/${page}`;
        return currentPath.endsWith(pagePath) || currentPath.includes(pagePath);
      });
      if (stepIndex !== -1) {
        setCurrentStep(stepIndex + 1);
      }
    }
  }, [pages]);
  if (!pages || pages.length === 0) {
    return null;
  }
  const step = currentStep;
  const total = pages.length;
  console.log('ProgressBar - Rendering with isDarkMode:', isDarkMode);
  const progressBarContainerStyle = {
    width: '100%',
    marginBottom: '32px',
    display: 'flex',
    alignItems: 'center',
    gap: '16px'
  };
  const stepsContainerStyle = {
    display: 'flex',
    alignItems: 'center',
    gap: '8px',
    flexShrink: 0
  };
  const progressBarTrackStyle = {
    flex: 1,
    height: '22px',
    backgroundColor: 'rgba(169, 210, 244, 0.06)',
    border: isDarkMode ? '1px solid rgba(230, 241, 247, 0.67)' : '1px solid #e3ecf3',
    borderRadius: '4px',
    overflow: 'hidden',
    position: 'relative'
  };
  const progressBarFillStyle = {
    height: '100%',
    backgroundColor: 'rgba(113, 192, 248, 0.23)',
    width: `${step / total * 100}%`,
    transition: 'width 0.3s ease'
  };
  const getStepStyle = (stepNumber, isActive) => {
    if (isDarkMode) {
      return {
        width: '22px',
        height: '22px',
        borderRadius: '4px',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '12px',
        fontWeight: '600',
        position: 'relative',
        zIndex: 1,
        transition: 'all 0.3s ease',
        backgroundColor: isActive ? 'rgba(113, 192, 248, 0.23)' : 'transparent',
        color: isActive ? '#60a5fa' : '#a0aec0',
        border: isActive ? '1px solid #e3ecf3' : '1px solid #e0e6eb',
        cursor: 'pointer',
        textDecoration: 'none'
      };
    }
    if (isActive) {
      return {
        width: '22px',
        height: '22px',
        borderRadius: '4px',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: '12px',
        fontWeight: '600',
        position: 'relative',
        zIndex: 1,
        transition: 'all 0.3s ease',
        backgroundColor: 'rgba(169, 210, 244, 0.32)',
        color: '#374151',
        border: '1px solid #e1eef8',
        cursor: 'pointer',
        textDecoration: 'none'
      };
    }
    return {
      width: '22px',
      height: '22px',
      borderRadius: '4px',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      fontSize: '12px',
      fontWeight: '600',
      position: 'relative',
      zIndex: 1,
      transition: 'all 0.3s ease',
      backgroundColor: '#fbfbfb',
      color: '#9ca3af',
      border: '1px solid #e3ecf3',
      cursor: 'pointer',
      textDecoration: 'none'
    };
  };
  return <div style={progressBarContainerStyle} {...props}>
      <div style={stepsContainerStyle}>
        {Array.from({
    length: total
  }, (_, index) => {
    const stepNumber = index + 1;
    const pageIndex = index;
    const pagePath = pages[pageIndex];
    const fullPath = pagePath.startsWith('/') ? pagePath : `/${pagePath}`;
    const isActive = stepNumber === step;
    return <a key={stepNumber} href={fullPath} style={getStepStyle(stepNumber, isActive)}>
              {stepNumber}
            </a>;
  })}
      </div>
      <div style={progressBarTrackStyle}>
        <div style={progressBarFillStyle}></div>
      </div>
    </div>;
};

export const ChoiceDebug = ({option}) => {
  const [currentValue, setCurrentValue] = useState(null);
  const [allState, setAllState] = useState({});
  const [isDarkMode, setIsDarkMode] = useState(false);
  useEffect(() => {
    const updateState = () => {
      if (window.choiceStateManager) {
        setCurrentValue(window.choiceStateManager.getValue(option));
        setAllState(window.choiceStateManager.getState());
      }
    };
    updateState();
    const unsubscribe = window.listenToChoice?.(option, updateState) || (() => {});
    const handleGlobalUpdate = () => updateState();
    window.addEventListener("choiceStateUpdate", handleGlobalUpdate);
    return () => {
      unsubscribe();
      window.removeEventListener("choiceStateUpdate", handleGlobalUpdate);
    };
  }, [option]);
  useEffect(() => {
    const checkDarkMode = () => {
      if (document.documentElement.classList.contains("dark")) {
        setIsDarkMode(true);
      } else if (document.documentElement.classList.contains("light")) {
        setIsDarkMode(false);
      } else {
        setIsDarkMode(window.matchMedia("(prefers-color-scheme: dark)").matches);
      }
    };
    checkDarkMode();
    const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
    const handleMediaChange = e => {
      if (!document.documentElement.classList.contains("dark") && !document.documentElement.classList.contains("light")) {
        setIsDarkMode(e.matches);
      }
    };
    mediaQuery.addEventListener("change", handleMediaChange);
    const observer = new MutationObserver(() => {
      checkDarkMode();
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => {
      mediaQuery.removeEventListener("change", handleMediaChange);
      observer.disconnect();
    };
  }, []);
  return <div style={{
    padding: "10px",
    backgroundColor: isDarkMode ? "#2d3748" : "#f5f5f5",
    border: isDarkMode ? "1px solid #4a5568" : "1px solid #ddd",
    borderRadius: "4px",
    fontSize: "12px",
    fontFamily: "monospace",
    marginTop: "20px",
    color: isDarkMode ? "#e2e8f0" : "inherit"
  }}>
      <strong>Choice Debug:</strong>
      <br />
      Option: {option}
      <br />
      Current Value: {currentValue || "undefined"}
      <br />
      All State: {JSON.stringify(allState, null, 2)}
    </div>;
};

export const Observe = ({option, value, children, ...props}) => {
  const [shouldShow, setShouldShow] = useState(false);
  useEffect(() => {
    const updateVisibility = () => {
      const matches = window.matchesChoiceValues?.(option, value) || false;
      setShouldShow(matches);
    };
    updateVisibility();
    const unsubscribe = window.listenToChoice?.(option, updateVisibility) || (() => {});
    return unsubscribe;
  }, [option, value]);
  if (!shouldShow) {
    return null;
  }
  return <div {...props}>{children}</div>;
};

export const Trigger = ({option, value, children, ...props}) => {
  const handleClick = () => {
    window.triggerChoice?.(option, value);
  };
  return <div onClick={handleClick} style={{
    cursor: "pointer"
  }} {...props}>
      {children}
    </div>;
};

export const Grid = ({columns = 2, compact = false, children, ...props}) => {
  const gridStyles = {
    display: "grid",
    gridTemplateColumns: `repeat(${columns}, 1fr)`,
    gap: compact ? "8px" : "16px",
    marginBottom: compact ? "10px" : "20px"
  };
  return <div style={gridStyles} {...props}>
      {children}
    </div>;
};

export const Choice = ({option, value, color = "", unset = false, lazy = false, children, ...props}) => {
  const [shouldShow, setShouldShow] = useState(false);
  const [hasEverShown, setHasEverShown] = useState(false);
  const [isDarkMode, setIsDarkMode] = useState(false);
  useEffect(() => {
    const updateVisibility = () => {
      const hasOptionValue = window.hasChoiceValue?.(option) || false;
      const matchesValue = window.matchesChoiceValues?.(option, value) || false;
      let show = false;
      if (unset && !hasOptionValue) {
        show = true;
      } else if (!unset && matchesValue) {
        show = true;
      }
      setShouldShow(show);
      if (show && !hasEverShown) {
        setHasEverShown(true);
      }
    };
    updateVisibility();
    const unsubscribe = window.listenToChoice?.(option, updateVisibility) || (() => {});
    return unsubscribe;
  }, [option, value, unset, hasEverShown]);
  useEffect(() => {
    const checkDarkMode = () => {
      if (document.documentElement.classList.contains("dark")) {
        setIsDarkMode(true);
      } else if (document.documentElement.classList.contains("light")) {
        setIsDarkMode(false);
      } else {
        setIsDarkMode(window.matchMedia("(prefers-color-scheme: dark)").matches);
      }
    };
    checkDarkMode();
    const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
    const handleMediaChange = e => {
      if (!document.documentElement.classList.contains("dark") && !document.documentElement.classList.contains("light")) {
        setIsDarkMode(e.matches);
      }
    };
    mediaQuery.addEventListener("change", handleMediaChange);
    const observer = new MutationObserver(() => {
      checkDarkMode();
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => {
      mediaQuery.removeEventListener("change", handleMediaChange);
      observer.disconnect();
    };
  }, []);
  const getColorStyles = () => {
    const baseStyles = {
      border: isDarkMode ? "1px dashed #4a5568" : "1px dashed #e1e5e9",
      padding: "20px",
      marginBottom: "20px",
      borderRadius: "8px",
      backgroundColor: isDarkMode ? "#1a202c" : "#ffffff"
    };
    const colorMap = {
      green: {
        light: {
          backgroundColor: "#d4edda",
          borderColor: "#28a745"
        },
        dark: {
          backgroundColor: "#1a3a2a",
          borderColor: "#66bb6a"
        }
      },
      red: {
        light: {
          backgroundColor: "#f8d7da",
          borderColor: "#dc3545"
        },
        dark: {
          backgroundColor: "#3a1a1a",
          borderColor: "#ef5350"
        }
      },
      blue: {
        light: {
          backgroundColor: "#d1ecf1",
          borderColor: "#0c5460"
        },
        dark: {
          backgroundColor: "#1a2a3a",
          borderColor: "#42a5f5"
        }
      },
      none: {
        backgroundColor: "transparent",
        padding: "0",
        margin: "0",
        border: "none"
      }
    };
    const colorStyles = color !== "none" ? colorMap[color]?.[isDarkMode ? "dark" : "light"] || ({}) : colorMap.none;
    return {
      ...baseStyles,
      ...colorStyles
    };
  };
  if (lazy && !hasEverShown && !shouldShow) {
    return null;
  }
  return <div style={{
    ...getColorStyles(),
    display: shouldShow ? "block" : "none"
  }} className="choice-content" {...props}>
      {children}
    </div>;
};

export const Choose = ({option, value, color = "", children, ...props}) => {
  const [isSelected, setIsSelected] = useState(false);
  const [hasOptionTriggered, setHasOptionTriggered] = useState(false);
  const [isDarkMode, setIsDarkMode] = useState(false);
  useEffect(() => {
    const currentValue = window.getChoiceValue?.(option);
    const optionTriggered = window.hasChoiceValue?.(option) || false;
    setIsSelected(currentValue === value);
    setHasOptionTriggered(optionTriggered);
    const unsubscribe = window.listenToChoice?.(option, newValue => {
      setIsSelected(newValue === value);
      setHasOptionTriggered(true);
    }) || (() => {});
    return unsubscribe;
  }, [option, value]);
  useEffect(() => {
    const checkDarkMode = () => {
      if (document.documentElement.classList.contains("dark")) {
        setIsDarkMode(true);
      } else if (document.documentElement.classList.contains("light")) {
        setIsDarkMode(false);
      } else {
        setIsDarkMode(window.matchMedia("(prefers-color-scheme: dark)").matches);
      }
    };
    checkDarkMode();
    const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
    const handleMediaChange = e => {
      if (!document.documentElement.classList.contains("dark") && !document.documentElement.classList.contains("light")) {
        setIsDarkMode(e.matches);
      }
    };
    mediaQuery.addEventListener("change", handleMediaChange);
    const observer = new MutationObserver(() => {
      checkDarkMode();
    });
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => {
      mediaQuery.removeEventListener("change", handleMediaChange);
      observer.disconnect();
    };
  }, []);
  const handleClick = () => {
    window.triggerChoice?.(option, value);
  };
  const handleKeyDown = e => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      handleClick();
    }
  };
  const getColorStyles = () => {
    const baseStyles = {
      border: isDarkMode ? "1px dashed #4a5568" : "1px dashed #e1e5e9",
      cursor: "pointer",
      padding: "20px",
      position: "relative",
      backgroundColor: isDarkMode ? "#2d3748" : "#f8f9fa",
      outline: "none",
      height: "100%",
      borderRadius: "8px",
      transition: "all 0.2s ease",
      display: "flex",
      flexDirection: "column"
    };
    const colorMap = {
      green: {
        light: {
          backgroundColor: "#d4edda",
          borderColor: "#28a745"
        },
        dark: {
          backgroundColor: "#1a3a2a",
          borderColor: "#66bb6a"
        }
      },
      red: {
        light: {
          backgroundColor: "#f8d7da",
          borderColor: "#dc3545"
        },
        dark: {
          backgroundColor: "#3a1a1a",
          borderColor: "#ef5350"
        }
      },
      blue: {
        light: {
          backgroundColor: "#d1ecf1",
          borderColor: "#0c5460"
        },
        dark: {
          backgroundColor: "#1a2a3a",
          borderColor: "#42a5f5"
        }
      }
    };
    const colorStyles = colorMap[color]?.[isDarkMode ? "dark" : "light"] || ({});
    if (isSelected) {
      return {
        ...baseStyles,
        ...colorStyles,
        borderStyle: "solid",
        borderWidth: "3px",
        borderColor: colorStyles.borderColor || (isDarkMode ? "#42a5f5" : "#0061d5"),
        backgroundColor: colorStyles.backgroundColor || (isDarkMode ? "#1a2a3a" : "#e3f2fd"),
        boxShadow: isDarkMode ? "0 2px 8px rgba(66, 165, 245, 0.3)" : "0 2px 8px rgba(0, 97, 213, 0.3)",
        transform: "scale(1.02)"
      };
    }
    if (hasOptionTriggered && !isSelected) {
      return {
        ...baseStyles,
        ...colorStyles,
        opacity: 0.5
      };
    }
    return {
      ...baseStyles,
      ...colorStyles
    };
  };
  const iconStyles = {
    float: "left",
    position: "relative",
    top: "2px",
    marginRight: "12px",
    width: "20px",
    height: "20px",
    color: isSelected ? isDarkMode ? "#42a5f5" : "#0061d5" : isDarkMode ? "#a0aec0" : "#666"
  };
  return <div onClick={handleClick} style={getColorStyles()} tabIndex={0} onKeyDown={handleKeyDown} {...props}>
      <div style={iconStyles}>
        {isSelected ? <svg viewBox="0 0 24 24" fill="currentColor" style={{
    width: "100%",
    height: "100%"
  }}>
            <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" />
          </svg> : <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{
    width: "100%",
    height: "100%"
  }}>
            <circle cx="12" cy="12" r="10" />
          </svg>}
      </div>
      <div style={{
    flex: 1
  }} className="choose-content">
        {children}
      </div>
    </div>;
};

<ProgressBar
  pages={[
                      "guides/sso-identities-and-app-users/connect-okta-to-app-users/scaffold-application-code",
                      "guides/sso-identities-and-app-users/connect-okta-to-app-users/configure-okta",
                      "guides/sso-identities-and-app-users/connect-okta-to-app-users/configure-box",
                      "guides/sso-identities-and-app-users/connect-okta-to-app-users/logging-into-app",
                      "guides/sso-identities-and-app-users/connect-okta-to-app-users/find-or-create-box-users",
                      "guides/sso-identities-and-app-users/connect-okta-to-app-users/run-the-app"
                    ]}
/>

Our next step in the Okta / Box integration is to create and configure the Okta
application and users, then extract a few pieces of information that we will
need to connect to Okta in our application.

<Frame noborder center shadow>
  <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-applications.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=de2695def45f14a5b46e484025bd8a02" alt="Okta Application Dashboard" width="1028" height="535" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-applications.png" />
</Frame>

For this tutorial we will be starting with a blank Okta application and user
dashboard to avoid any negative effects on existing installations that may be
in place, and to ensure that we have admin rights to the instance.

## Create an Okta Application

Starting from the [Okta developer site][okta-dev], sign up for a new developer
account, or log in under your personal account if you already have one.

If you're logging in with an existing account, you should see the Okta
dashboard. Click on the **Admin** button at the top right.

<Frame noborder center shadow>
  <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-dashboard.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=df9225368c85eb7ced01988a3588e69d" alt="Okta Application Dashboard" width="1183" height="400" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-dashboard.png" />
</Frame>

If you've created a new developer account rather than logging into an existing
account, you will have already be redirected to the admin dashboard.

You should now see the admin panel. Click on the **Applications** option at the
top.

<Frame noborder center shadow>
  <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-admin-dashboard.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=a339cdad33f03fb572cce2da3eebc757" alt="Okta Admin Dashboard" width="1022" height="304" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-admin-dashboard.png" />
</Frame>

On the application page, click the **Add Application** button. Select **Web**
as the application type and click the **Next** button.

<Frame noborder center shadow>
  <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-app-type.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=373e829bcaa125adaa4cd5a0b95e77be" alt="Okta App Types" width="1016" height="378" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-app-type.png" />
</Frame>

Okta employs both [OAuth 2][oauth2] and [OpenID Connect][openid-connect] (OIDC)
for application authorization and user authentication, respectively. The OpenID
Connect integration allows us to use baked in OIDC connectors within a number
of popular language frameworks to simplify application and user management by
handling the callback routes and providing methods for logging in,
logging out, and protecting routes into your application.

To simplify this first integration, we're going to use the default callback
routes and settings for the language and framework OIDC connector. Depending on
your preferred integration type, the configuration settings will slightly
change.

Fill out the application details with the following configuration settings:

<Choice option="programming.platform" value="node" color="none">
  * Name: Any
  * Base URIs: `http://localhost:3000/`
  * Login redirect URIs: `http://localhost:3000/authorization-code/callback`
  * Logout redirect URIs: `http://localhost:3000/logout`
  * Grant type allowed: Only **Authorization Code** selected

  <Frame noborder center shadow>
    <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-node.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=c618eddb942b259befb40d497e05c05f" alt="Okta App Configuration" width="719" height="728" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-node.png" />
  </Frame>
</Choice>

<Choice option="programming.platform" value="java" color="none">
  * Name: Any
  * Base URIs: `http://localhost:8080/`
  * Login redirect URIs: `http://localhost:8080/authorization-code/callback`
  * Logout redirect URIs: `http://localhost:8080/logout`
  * Grant type allowed: Only **Authorization Code** selected

  <Frame noborder center shadow>
    <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-java.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=2ae67741947dcdcbaa2100485e2f8d88" alt="Okta App Configuration" width="718" height="726" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-java.png" />
  </Frame>
</Choice>

<Choice option="programming.platform" value="python" color="none">
  * Name: Any
  * Base URIs: `http://127.0.0.1:5000/`
  * Login redirect URIs: `http://127.0.0.1:5000/oidc/callback`
  * Logout redirect URIs: `http://127.0.0.1:5000/logout`
  * Grant type allowed: Only **Authorization Code** selected

  <Frame noborder center shadow>
    <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-python.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=e6b9dba35874a59a59b61ac2d1eaee65" alt="Okta App Configuration" width="717" height="728" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-python.png" />
  </Frame>
</Choice>

<Choice option="programming.platform" value="cs" color="none">
  * Name: Any
  * Base URIs: `https://localhost:5001/`
  * Login redirect URIs: `https://localhost:5001/authorization-code/callback`
  * Logout redirect URIs: `https://localhost:5001/logout`
  * Grant type allowed: Only **Authorization Code** selected

  <Frame noborder center shadow>
    <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-cs.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=aa21e7d8fde28a0c548cd6430d7d1175" alt="Okta App Configuration" width="719" height="729" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-appconfig-cs.png" />
  </Frame>
</Choice>

<Choice option="programming.platform" unset color="none">
  <Danger>
    **Incomplete previous step**
    Please select a preferred language / framework in step 1 to get started.
  </Danger>
</Choice>

Click the **Done** button to create the application and be dropped on to the
general settings of the application.

## Copy Application Credentials

Using the configuration files set up in the last step, we next have to add in
the Okta application org and app details within the files.

Most Okta application information can be found on the general settings page,
with the exception of the `Org URL` that is used in the configuration URIs to
reference back to your Okta organization. To obtain the `Org URL`, go to the
dashboard of your Okta admin console. The `Org URL` will be in the top right
corner of the screen.

Depending on the language and framework previously chosen, we'll set up the
appropriate configuration files.

<Frame noborder center shadow>
  <img src="https://mintcdn.com/box/K3l9SyfYdcG-z-Ku/guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-org-url.png?fit=max&auto=format&n=K3l9SyfYdcG-z-Ku&q=85&s=9e50499b019ff1a94ee643f9be57e392" alt="Okta Org URL" width="1035" height="225" data-path="guides/sso-identities-and-app-users/connect-okta-to-app-users/img/okta-qs-step2-org-url.png" />
</Frame>

<Choice option="programming.platform" value="node" color="none">
  * Open `config.json` within the local application directory in your preferred editor.
  * Update the following line items with the appropriate Okta configuration info:
    * `oktaClientId`: Obtained from the **Client Credentials** section of the application general settings.
    * `oktaClientSecret`: Obtained from the **Client Credentials** section of the application general settings.
    * `oktaOrgUrl`: Obtained from the top right of the main admin dashboard page.
  * Save the file.

  Your `config.json` file should look similar to the following.

  ```js theme={null}
  const oktaClientId = exports.oktaClientId = '0oa48567frkg5KW4x6';
  const oktaClientSecret = exports.oktaClientSecret = 'cugDJy2ERfIQHDXv-j2134DfTTes-Sa3';
  const oktaOrgUrl = exports.oktaOrgUrl = 'YOURDOMAIN.okta.com';
  const oktaBaseUrl = exports.oktaBaseUrl = 'http://localhost:3000';
  const oktaRedirect = exports.oktaRedirect = '/authorization-code/callback';
  ```
</Choice>

<Choice option="programming.platform" value="java" color="none">
  * Open the `/src/main/resources/application.properties` file and update the following lines:
    * `okta.oauth2.issuer`: Your Org URL, obtained from the top right of the main admin dashboard page, followed by `/oauth2/default`. For example, if your Org URL was `https://dev-123456.okta.com`, the issuer string should be `https://dev-123456.okta.com/oauth2/default`.
    * `okta.oauth2.clientId`: Obtained from the **Client Credentials** section of the application general settings.
    * `okta.oauth2.clientSecret`: Obtained from the **Client Credentials** section of the application general settings.
  * Save the file

  Your `/src/main/resources/application.properties` file should look similar to
  the following.

  ```java theme={null}
  okta.oauth2.redirect-uri=/authorization-code/callback
  okta.oauth2.issuer=https://YOURDOMAIN.okta.com/oauth2/default
  okta.oauth2.clientId=0oa48567frkg5KW4x6
  okta.oauth2.clientSecret=cugDJy2ERfIQHDXv-j2134DfTTes-Sa3
  security.oauth2.sso.loginPath=/authorization-code/callback
  ```
</Choice>

<Choice option="programming.platform" value="python" color="none">
  In addition to the standard configuration information for the org and app, the
  Python / Flask integration requires an additional auth token.

  To create an auth token:

  * Go to the **API** -> **Token** section of the Okta admin dashboard.
  * Click the **Create Token** button.
  * Enter a name for the token and click **Create**.
  * Copy the token that is generated.

  Next, update the local application configuration file.

  * Open `config.py` within the local application directory in your preferred editor.
  * Update the following line items with the appropriate Okta configuration info:
    * `okta_client_secret`: Obtained from the **Client Credentials** section of the application general settings.
    * `okta_org_url`: Obtained from the top right of the main admin dashboard page.
    * `okta_auth_token`: The token created above.
  * Save the file.

  Your `config.py` file should look similar to the following.

  ```python theme={null}
  okta_client_id = '0oa48567frkg5KW4x6'
  okta_client_secret = 'cugDJy2ERfIQHDXv-j2134DfTTes-Sa3'
  okta_org_url = 'http://YOURDOMAIN.okta.com'
  okta_auth_token = '01KkTQTRfs1yKLr4Ojy26iqoIjK_4fHyq132Dr5T'
  okta_callback_route = '/oidc/callback'
  ```

  Lastly, update the Flask configuration file

  * Open `client_secrets.json` within the local application directory in your preferred editor.
  * Update the following line items with the appropriate Okta configuration info:
    * `client_id`: Obtained from the **Client Credentials** section of the application general settings.
    * `client_secret`: Obtained from the **Client Credentials** section of the application general settings.
    * `auth_uri`: Your Org URL, obtained from the top right of the main admin dashboard page, followed by `/oauth2/default/v1/authorize`. For example, if your Org URL was `https://dev-123456.okta.com`, the issuer string should be `https://dev-123456.okta.com/oauth2/default/v1/authorize`.
    * `token_uri`: Your Org URL, obtained from the top right of the main admin dashboard page, followed by `/oauth2/default/v1/token`. For example, if your Org URL was `https://dev-123456.okta.com`, the issuer string should be `https://dev-123456.okta.com/oauth2/default/v1/token`.
    * `issuer`: Your Org URL, obtained from the top right of the main admin dashboard page, followed by `/oauth2/default`. For example, if your Org URL was `https://dev-123456.okta.com`, the issuer string should be `https://dev-123456.okta.com/oauth2/default`.
    * `userinfo_uri`: Your Org URL, obtained from the top right of the main admin dashboard page, followed by `/oauth2/default/userinfo`. For example, if your Org URL was `https://dev-123456.okta.com`, the issuer string should be `https://dev-123456.okta.com/oauth2/default/userinfo`.
  * Save the file.

  Your `client_secrets.json` file should look similar to the following.

  ```json theme={null}
  {
    "web": {
      "client_id": "0oa48567frkg5KW4x6",
      "client_secret": "cugDJy2ERfIQHDXv-j2134DfTTes-Sa3",
      "auth_uri": "https://YOURDOMAIN.okta.com/oauth2/default/v1/authorize",
      "token_uri": "https://YOURDOMAIN.okta.com/oauth2/default/v1/token",
      "issuer": "https://YOURDOMAIN.okta.com/oauth2/default",
      "userinfo_uri": "https://YOURDOMAIN.okta.com/oauth2/default/userinfo",
      "redirect_uris": [
        "http://127.0.0.1:5000/oidc/callback"
      ]
    }
  }
  ```
</Choice>

<Choice option="programming.platform" value="cs" color="none">
  * Open `Startup.cs` within the local application directory in your preferred editor.
  * Update the following line items within the `ConfigureServices` method with the appropriate Okta configuration info:
    * `OktaDomain`: Obtained from the top right of the main admin dashboard page.
    * `ClientId`: Obtained from the **Client Credentials** section of the application general settings.
    * `ClientSecret`: Obtained from the **Client Credentials** section of the application general settings.
  * Save the file.

  Your `ConfigureServices` method should look similar to the following.

  ```csharp theme={null}
  services.AddControllersWithViews();
  services.AddAuthentication(options =>
  {
      options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
      options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
      options.DefaultChallengeScheme = OktaDefaults.MvcAuthenticationScheme;
  })
  .AddCookie()
  .AddOktaMvc(new OktaMvcOptions
  {
      OktaDomain = "https://YOURDOMAIN.okta.com",
      ClientId = "0oa48567frkg5KW4x6",
      ClientSecret = "cugDJy2ERfIQHDXv-j2134DfTTes-Sa3"
  });
  ```
</Choice>

<Choice option="programming.platform" unset color="none">
  <Danger>
    **Incomplete previous step**
    Please select a preferred language / framework in step 1 to get started.
  </Danger>
</Choice>

## Create a User

Our last step in the Okta setup is to create a test user that we will use to
log in to the application.

1. Go to the **Users** section of the Okta admin dashboard.
2. Click on the **Add Person** button.
3. Enter all appropriate user info. Under password, select **Set by admin** and input a password for the user. Also deselect the **User must change password on first login** option. You will use the username and password to log in. These settings will only be used for testing purposes and are not best practices for user creation and security.
4. Click the **Save** button to create the user.

## Summary

* You created an Okta application.
* You updated the Okta configuration information in the local application.
* You created a test Okta user.

<Observe option="programming.platform" value="node,java,python">
  <Next>I've created my Okta app and set up user / local configuration</Next>
</Observe>

[okta-dev]: https://developer.okta.com/

[oauth2]: https://oauth.net/2/

[openid-connect]: https://openid.net/
