Skip to content

Commit

Permalink
docs(idx): add documentation on the Interaction Code flow and IDX API
Browse files Browse the repository at this point in the history
  • Loading branch information
coldlink committed Oct 24, 2024
1 parent bb8b32e commit f5a86d5
Show file tree
Hide file tree
Showing 6 changed files with 1,462 additions and 38 deletions.
104 changes: 66 additions & 38 deletions docs/okta/idx/README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,85 @@
# Okta IDX API
# Okta IDX API and Identity Engine

Status: WIP

_More information about the Okta IDX API will be added soon_
#### To document

## Hoppscotch Collection
- [x] IDX API introduction
- [ ] Quick Start
- [ ] Why passcodes and passwordless?
- [ ] Gateway implementation
- [x] Further implementation context
- [x] [Hoppsotch](./hoppscotch.md)
- [x] [API endpoints](./idx-api.md)
- [ ] [Sign in](./sign-in-idx.md)
- [x] [Create account](./create-account-idx.md)
- [x] [Reset password](./reset-password-idx.md)

To make working with the Okta IDX API easier, we've added a [Hoppscotch](https://hoppscotch.com/) collection that can be used to make calls directly to the IDX API.
### Quick Start

### Setting up the collection + variables
_TODO: Add a quick start guide to using the IDX API_

Hoppscotch is a tool which self describes as a took for "developers to build, test and share APIs". It is similar to other tools such as Postman. Except [open source](https://github.com/hoppscotch/hoppscotch).
The collection might also work in other tools, but it's untested.
## Identity Engine

1. Download the [collection](./okta_idx_hoppscotch_collection.json)
2. In the desktop Hoppscotch app click "Collections" -> "Import/Export" button
3. Click "Import from Hoppscotch" and select the collection file.
4. When imported, a new "Okta IDX" collection should've appeared!
In Q3 2023, we upgraded our Okta environment to [Identity Engine](https://developer.okta.com/docs/concepts/oie-intro/), which is Okta's new(ish) authentication pipeline with additional features compared to the older [Classic Engine](https://developer.okta.com/docs/guides/archive-overview/main/), which we'll refer to as "Okta Classic" or "Okta Legacy" or some variation of the two.

You'll also need an Hoppscotch "Environment" containing the variables/secrets.
Primarily for us, Identity Engine enables features that were previously impossible or difficult to implement, such as sign in without a password, or MFA (multi-factor authentication). Currently in Gateway (and the identity platform as a whole), we've been implementing "email" factor authentication and recovery, primarily referred to as "passcodes" or "OTPs (one-time passcodes)", and the generic concept of "passwordless". See the ["Why passcodes and passwordless?"](#why-passcodes-and-passwordless) section for more information on why we're betting on passcodes and passwordless.

A collection pointing to the CODE environment is available on S3. Use the following to download it. Be sure to have the `identity` Janus credentials.
### Interaction Code flow

```sh
# this downloads it to your home directory, feel free to change the path if needed e.g. to your downloads folder
$ aws s3 cp --profile identity s3://identity-private-config/DEV/identity-gateway/okta_code_environment_hoppscotch.json ~/okta_code_environment_hoppscotch.json
```
In order to utilise some of these new features with Identity Engine, Okta have created a **proprietary** extension to the [OAuth 2.0 and Open ID Connect](../oauth.md) standard called the "[Interaction Code](https://developer.okta.com/docs/concepts/interaction-code/) grant type", which in their words "enables you to create a more customized user authentication experience", and behaves in a similar way to the [Authorization Code flow with PKCE](../oauth.md#oauth-20-flowsgrant-types).

Once downloaded, in Hoppscotch you can:
The [overview](https://developer.okta.com/docs/concepts/interaction-code/) gives a reasonable overview of how this new extension works. Essentially the flow consists a number of "interactions" between the client/user and the authorization server in order to authenticate the user. Each "interaction" is called a "remediation" step, and corresponds to a piece of user data or input required by the authorization server in order to continue to the next step, until the user is fully authenticated.

1. Select "Environments"
2. "Import/Export" button
3. Click "Import from Hoppscotch" and select the environment file.
4. When imported, a new "Okta CODE" environment will have appeared!
A bonus to the interaction code flow is that it makes it possible to both create new users and allow users to reset their password, as part of a single authentication process which wasn't previously possible using Classic flows. Previously we'd have to use multiple different Okta API endpoints to give the impression to the user that it was a single flow. Now with the Interaction Code flow, we can use this to potentially sign in, create a new user, or reset a password all as part of the same process!

Now the "Okta CODE" environment can be selected. You can do this in the top-right under the environments dropdown.
The documentation suggests that in order to use all these new features, we have to migrate our applications to use the Interaction Code flow. But since this is a **proprietary** extension, we'd rather avoid implementing this everywhere, as that would lead to potential vendor lock in, and we'd have to migrate all the user facing applications we've already migrated to use OAuth just to enable features like passwordless. This isn't ideal.

This file already prefills the non-secret and non-changeable variables, called "variables" in Hoppscotch. If these do change, make sure to update the file in s3!
Thankfully though, we have a simple solution to this, the only place that actually needs to migrate to use the Interaction Code flow is Gateway, as Gateway (and more accurately the `profile` subdomain) is the single point for all authentication activities at the Guardian. User facing applications that need an authenticated user session **_should_** continue to use the Authorization Code flow (with or without PKCE) in order to authenticate a user. This is because when the Authorization Code flow is started, it requires a browser based login, as it has to call the `/authorize` endpoint in order to check if the user is already authenticated or not. If the user isn't authenticated it uses the browser to attempt to authenticate the user.

Under the "secrets" tab, these are all things which are either secret, or change frequently. These should be filled in as needed.
This browser based sign in normally redirects to the Okta hosted login page. However thanks to our [Okta hosted login page interception](../login-page-interception.md) functionality, we perform a client side redirect from the Okta hosted page to Gateway, with all the parameters we need to authenticate the user. From there we use Gateway to authenticate the user, before redirecting back to the application once authenticated. This means the only place which we need to update to use the Interaction Code flow is Gateway!

### Using the collection
Because the Interaction Code grant type is a proprietary extension by Okta, we have to interact with it the way Okta wants us to, this means using their new authentication API where the Interaction Code flow is supported, namely the Okta IDX API.

To interface with the Okta IDX API, you always have to make 2 calls in order to begin with.
## IDX API

1. First call the "IDX /interact" endpoint.
- All the variables/parameters should be set up for this, so just click send!
- This returns an `interaction_handle` in the body.
- This will automatically be updated in the variables as `interactionHandle`
2. Next call the "IDX /introspect (with `interactionCode`)" endpoint.
- This uses the `interactionHandle` from the previous step.
- This returns a bunch of things, but it's automatically be updated in the variables as `stateHandle`
- The response includes a `remediation` property which contains an array of possible next steps, this is the same for every IDX API endpoint
- More information about the IDX API will be added soon.
3. Ready to make further calls!
- You may need to set up further secrets under environments to make these calls, the ones that you might need to set/update will be highlighted
The IDX API is built on the Okta Identity Engine and implements the Interaction Code flow grant type. In order to implement this they want clients to use their SDKs where this API is supported. The IDX API is also undocumented outside of [SDK documentation](https://github.com/okta/okta-auth-js/blob/master/docs/idx.md). Under the hood however the SDKs are making standard HTTP requests to a number of different API endpoints.

Our initial plan was to use the SDK in order to implement the Interaction Code flow and the IDX API in Gateway, however we found that the SDKs were too limiting in terms of being able to fully customise the flow and experience for users, and it also wouldn't set a [global session](../sessions.md#idp-session) outside of the Okta hosted flow. The only option remaining was to reverse engineer the calls made to the IDX API.

Thankfully for us this was relatively straightforward, we could see how the Okta hosted login page was using the IDX API, and document the behaviour in order of us to replicate. This documentation serves as the primary source for what we found in our investigation and implementation of the IDX API.

The decision to reverse engineer wasn't straightforward, we had to be relatively certain that Okta wouldn't suddenly change the behaviour of the IDX API which would potentially break our reverse engineered implementation. We came to this conclusion for two reasons; 1) The Okta IDX API is versioned, it returns a `version` key (currently `1.0.0`) in the response, and through the header, `Accept` and `Content-Type` supply `application/ion+json; okta-version=1.0.0` and 2) the [SDK](https://github.com/okta/okta-auth-js/?tab=readme-ov-file#release-status) also has a "Release Status" section, showing which versions of the SDK are supported, and when they will be deprecated. This gives us some confidence that the API won't change too much in the near future.

The IDX API is a relatively simple API, it consists of a number of different endpoints, each corresponding to a different "remediation" step in the Interaction Code flow. The API is documented in the [IDX API documentation](./idx-api.md), and the [Hoppscotch](./hoppscotch.md) documentation shows how to interact directly with the API. You can specifically see how the IDX is implemented for [sign in](./sign-in-idx.md), [create account](./create-account-idx.md), and [reset password](./reset-password-idx.md) in their respective documentation.

## Why passcodes and passwordless?

## Gateway implementation

_TODO: Add a section on how the IDX API is implemented in Gateway_

## Further implementation context

Here's a list of PRs/Issues that are related to Identity Engine, IDX API, and passwordless (passcodes). This may not be conclusive.

Identity Engine Upgrade PRs:

- Gateway
- https://github.com/guardian/gateway/pull/2422
- https://github.com/guardian/gateway/pull/2424
- https://github.com/guardian/gateway/pull/2433
- https://github.com/guardian/gateway/pull/2450
- https://github.com/guardian/gateway/pull/2463
- [Identity Platform](https://github.com/guardian/identity-platform)
- https://github.com/guardian/identity-platform/pull/679
- https://github.com/guardian/identity-platform/pull/682
- https://github.com/guardian/identity-platform/pull/684
- https://github.com/guardian/identity-platform/pull/685
- https://github.com/guardian/identity-platform/pull/688

Okta IDX API Setup and Social Sign In using IDX - https://github.com/guardian/gateway/pull/2625 & https://github.com/guardian/identity-platform/pull/718

See the [`passwordless` label](https://github.com/guardian/gateway/issues?q=label%3Apasswordless+) for all PRs related to passcodes/passwordless, and the respective label in [`identity-platform` repo](https://github.com/guardian/identity-platform/issues?q=label%3Apasswordless)

Specific PRs are shown in the documents describing the individual implementations/flows of the IDX API.
67 changes: 67 additions & 0 deletions docs/okta/idx/create-account-idx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Create Account flow with Okta IDX API

This document describes how the create account flow ([`/register`](https://profile.theguardian.com/register)) is implemented using the Okta IDX API.

See the [IDX API documentation](./idx-api.md) for more information on the API, e.g. to look up the specific endpoints and body used in the create account flow. The flowcharts below only show the expected success and error paths, if there are any unexpected errors, we fall back to the classic Okta API flow.

## User States

Currently the IDX API for users going through the create account journey is only implemented for new users. For existing users attempting to go through the registration flow we use the legacy Okta API for the time being in order to let the user know that they already have an account and can either reset their password or sign in. This is until we have UX consultation on how to handle existing users going through the registration flow.

| State | Description | Action |
| ---------------- | ------------------------------- | ------------------------------------------- |
| No existing user | The user does not exist in Okta | User is created using the IDX API |
| Existing user | The user exists in Okta | User sent email saying their account exists |

## Flowchart

```mermaid
flowchart TD
start(User visits /register)
start --> enter-email[/User enters email and submits form/]
enter-email --> interact[POST /oauth2/auth_server_id/v1/interact]
interact --> introspect[POST /idp/idx/introspect]
introspect --> enroll[POST /idp/idx/enroll]
enroll --> enroll-new[POST /idp/idx/enroll/new]
enroll-new --> enroll-new-check{Check Response}
enroll-new-check -- Success --> email-sent-passcode[/Show email sent page<br>with passcode input/]
enroll-new-check -- User Exists --> fallback-classic
email-sent-passcode -- Submit Code --> challenge-answer[POST /idp/idx/challenge/answer]
email-sent-passcode -- Resend Code --> email-sent-passcode-resend[POST /idp/idx/challenge/resend]
email-sent-passcode -- Change email --> start
email-sent-passcode-resend -- Success --> email-sent-passcode
challenge-answer --> challenge-answer-check{Check Response}
challenge-answer-check -- Success --> credential-enroll-password[POST /idp/idx/credential/enroll<br>password authenticator]
challenge-answer-check -- Invalid Passcode<br>Show Error --> email-sent-passcode
challenge-answer-check -- Passcode Expired<br><br>Show expired page --> start
credential-enroll-password --> password-page[/Show password page<br>user enters password and submits/]
password-page --> challenge-answer-password[POST /idp/idx/challenge/answer]
challenge-answer-password --> challenge-answer-password-check{Check Response}
challenge-answer-password-check -- Success --> login-redirect([303 Redirect /login/token/redirect])
challenge-answer-password-check -- Invalid Password<br>e.g. short/long/breached etc.<br>Show Error --> password-page
login-redirect -- set global session --> finish
finish(User finished account creation<br>they've redirected back to the application they were on<br>or the new account review page is shown)
fallback-classic(Fallback to Classic Flow<br>Handle existing user)
```

## Implementation

See the [`oktaIdxCreateAccount`](https://github.com/guardian/gateway/blob/bb8b32e30dd178a7ffe81ec75c64b2ce4ad93aeb/src/server/routes/register.ts#L319-L335) method for the implementation in code to send the user a passcode email for verification, this is called from the [`POST /register`](https://github.com/guardian/gateway/blob/bb8b32e30dd178a7ffe81ec75c64b2ce4ad93aeb/src/server/routes/register.ts#L108-L115) route.

The passcode submit route is [`POST /register/code`](https://github.com/guardian/gateway/blob/bb8b32e30dd178a7ffe81ec75c64b2ce4ad93aeb/src/server/routes/register.ts#L143-L145), and the route to resend the passcode is [`POST /register/code/resend`](https://github.com/guardian/gateway/blob/5211380b6cfbe2ad5bfe4f0d1aeed7a1ff831333/src/server/routes/register.ts#L244-L246).

### PRs

Here is a list of pull requests/issues relating to the create account flow with the Okta IDX API, probably not an exhaustive list:

- [#2567 - Initial (outdated) flowchart](https://github.com/guardian/gateway/issues/2567)
- [#2639 - Passcodes | Set up passcodes for registration](https://github.com/guardian/gateway/pull/2639)
- [#2671 - Passcodes | Add email template for RegistrationPasscode](https://github.com/guardian/gateway/pull/2671)
- Additional PRs for email related issues
- https://github.com/guardian/gateway/pull/2729
- https://github.com/guardian/gateway/pull/2737
- [#2752 - Passcodes | Remove usePasscodeRegistration query parameter and make passcode registration default](https://github.com/guardian/gateway/pull/2752)
- [#2773 - Passcodes | Fix issues after round one of testing](https://github.com/guardian/gateway/pull/2773)
- [#2786 - Passcodes | Improve passcode styling/functionality](https://github.com/guardian/gateway/pull/2786)
51 changes: 51 additions & 0 deletions docs/okta/idx/hoppscotch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Hoppscotch

To make working with the Okta IDX API easier, we've added a [Hoppscotch](https://hoppscotch.com/) collection that can be used to make calls directly to the IDX API.

### Setting up the collection + variables

Hoppscotch is a tool which self describes as a took for "developers to build, test and share APIs". It is similar to other tools such as Postman. Except [open source](https://github.com/hoppscotch/hoppscotch).
The collection might also work in other tools, but it's untested.

1. Download the [collection](./okta_idx_hoppscotch_collection.json)
2. In the desktop Hoppscotch app click "Collections" -> "Import/Export" button
3. Click "Import from Hoppscotch" and select the collection file.
4. When imported, a new "Okta IDX" collection should've appeared!

You'll also need an Hoppscotch "Environment" containing the variables/secrets.

A collection pointing to the CODE environment is available on S3. Use the following to download it. Be sure to have the `identity` Janus credentials.

```sh
# this downloads it to your home directory, feel free to change the path if needed e.g. to your downloads folder
$ aws s3 cp --profile identity s3://identity-private-config/DEV/identity-gateway/okta_code_environment_hoppscotch.json ~/okta_code_environment_hoppscotch.json
```

Once downloaded, in Hoppscotch you can:

1. Select "Environments"
2. "Import/Export" button
3. Click "Import from Hoppscotch" and select the environment file.
4. When imported, a new "Okta CODE" environment will have appeared!

Now the "Okta CODE" environment can be selected. You can do this in the top-right under the environments dropdown.

This file already prefills the non-secret and non-changeable variables, called "variables" in Hoppscotch. If these do change, make sure to update the file in s3!

Under the "secrets" tab, these are all things which are either secret, or change frequently. These should be filled in as needed.

### Using the collection

To interface with the Okta IDX API, you always have to make 2 calls in order to begin with.

1. First call the "IDX /interact" endpoint.
- All the variables/parameters should be set up for this, so just click send!
- This returns an `interaction_handle` in the body.
- This will automatically be updated in the variables as `interactionHandle`
2. Next call the "IDX /introspect (with `interactionCode`)" endpoint.
- This uses the `interactionHandle` from the previous step.
- This returns a bunch of things, but it's automatically be updated in the variables as `stateHandle`
- The response includes a `remediation` property which contains an array of possible next steps, this is the same for every IDX API endpoint
- More information about the IDX API will be added soon.
3. Ready to make further calls!
- You may need to set up further secrets under environments to make these calls, the ones that you might need to set/update will be highlighted
Loading

0 comments on commit f5a86d5

Please sign in to comment.