Secure Python Litestar Site With OpenID/OIDC Using Okta Hosted Login
Tags: tutorial, python, security, programming
Published: 2024-02-16 22:09:18

Here is a tutorial on how to setup [OKTA](https://www.okta.com) as a OpenID/OIDC security provider for a site programmed in Python 3.11.x using [Litestar](https://www.litestar.dev).
This is done with 'Authorization Code flow'
#### About the Authorization Code grant ####
The Authorization Code flow is the recommended method for controlling access to web applications capable of securely storing secrets, see https://developer.okta.com/docs/guides/implement-grant-type/authcode/main/

## OKTA Setup ##

### Step 1 ###
<table>
<tr>
<td valign="top">
After you have created your OKTA account open `Applications` => `Applications` as seen on the right.
</td>
<td>
<a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2oqsbt35lsghlo293ya.png" target="_blank">
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t2oqsbt35lsghlo293ya.png"/></a>
</td>
</tr></table>

### Step 2 ###
Click `Create App Integration`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nvzikq1c8p66ntdl8xp7.png)

### Step 3 ###
Choose `OIDC` - Open Connect with a description of
'Token-based OAuth 2.0 authentication for Single Sign-On (SSO) through API endpoints. Recommended if you intend to build a custom app integration with the Okta Sign-In Widget.'
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7ire96qy769y2tc4o8z.png)

And then choose `Web Application` with a description of 
'Server-side applications where authentication and tokens are handled on the server (for example, Go, Java, ASP.Net, Node.js, PHP)'

And Click `Next`

### Step 4 ###
Checked the following (*may not matter*):
- Client Credentials
- Refresh Token
- Implicit (hybrid)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6czzrrbq7lk411l3643i.png)

### Step 5 ###
Ensure that both `Sign-in redirect URIs` and `Sign-out redirect URIs (Optional) have the correct values`. By default Litestar brings up the web site on port 8000.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nl1eaa565ocxxtwytxmu.png)

### Step 6 ###
In `Assignments` select `Allow everyone in your organization to access`.
In `Enable immediate access (Recommended)` select `Enable immediate access with *Federation Broker Model*`
Click `Save`
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4pqduqiox4v6sb5hp8g6.png)

### Step 7 ###
Create a text file named '**.env**' and from the `General` tab, copy both `Client ID` and `Client Secret` to the file to have something like the following:
```
CLIENT_ID=your_client_id
CLIENT_SECRET=your_client_secret
OKTA_DOMAIN=dev-123456789.okta.com
REDIRECT_URL=http://localhost:8000/authorization-code/callback
OKTA_PROMPT=consent
```
And provide the you value for `OKTA_DOMAIN`.<br/>
You do not to supply a value for `OKTA_PROMPT` or even include it if you choose not to. For more details about regarding this parameter see https://developer.okta.com/docs/reference/api/oidc/#parameter-details.
Using OKTA_PROMPT is very helpful when testing multiple user accounts.


## Python Code ##
Github.com repository found here https://github.com/pbaletkeman/litestarOpenID

Copy the .env file from the previous step to the root directory of your Python project.

For the most part the code is well documented, however here are some notes:
- It uses Mako templates, https://www.makotemplates.org/
- /profile is not secured, and is used to show you JWT Bearer Token which is needed to access /read-items and other secure routes, this is set in the callback method
- More user properties are found in the `user_response` object located in the callback method

## Additionality PKCE ##
You can use Authorization Code Grant with Proof Key for Code Exchange (PKCE) which you can read about here:
https://developer.okta.com/docs/guides/implement-grant-type/authcodepkce/main/#about-the-authorization-code-grant-with-pkce.

To enforce PKCE you will have to select 'Require PKCE as additional verification' as seen in the image below.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4o3728k2cl5hdxh69mu.png)
You can still use PKCE without requiring it.

Here is the Python code for this,
https://github.com/pbaletkeman/okta-litestar-oidc-pkce
Which is a lot like the none PKCE code.
Note that the following have been added/changed:

lines: 181, 182, 192, 193
```
'code_challenge': code_challenge,
'code_challenge_method': 'S256',
```

line: 231
`query_params = {'grant_type': 'authorization_code', 'code': code,`

line: 185, 197 
And the `response_mode` has been changed from 'query' to 'form_post' which tells OKTA to send the data as a form post instead of using the query string. Query string is still valid and can be used if you choose to.