Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

16815 authz design #17094

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions auth/docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,38 @@
## Prerequisites

A few secrets are required to run the Auth which are not committed to source. These values are
configured in Okta.
configured in Okta. We have to set up applications with properly scoped permissions to allow our
application to properly retrieve that data from Okta.

| Environment variable | Value |
|----------------------|---------------------------------|
| OKTA_ADMIN_CLIENT_API_ENCODED_PRIVATE_KEY | Base 64 encoded private key pem |
| SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET | Base 64 encoded secret |
| Environment variable | Value |
|-----------------------------------------------------------------|---------------------------------|
| OKTA_ADMIN_CLIENT_API_ENCODED_PRIVATE_KEY | Base 64 encoded private key pem |
| SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET | Shared secret |

Setup for `OKTA_ADMIN_CLIENT_API_ENCODED_PRIVATE_KEY`:
1. Sign into Okta Admin Portal
2. Go to Applications > Applications in the sidebar
3. Click "Create a new app integration" button
4. Select "API Services" radio button and click "Next"
5. Give it an appropriate name like "Authn Admin Integration"
6. Select "Public key / Private key" as the Client authentication method
7. Copy client ID and private key in PEM format somewhere
8. Grant the application the `okta.apps.read` scope
9. Grant the application the `Read-only Administrator role`
10. Set client id at `okta.adminClient.clientId` in application.yml
11. Base 64 encode the private key PEM and set it in the environment variable `OKTA_ADMIN_CLIENT_API_ENCODED_PRIVATE_KEY`

Setup for `SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET`:
1. Sign into Okta Admin Portal
2. Go to Applications > Applications in the sidebar
3. Click "Create a new app integration" button
4. Select "API Services" radio button and click "Next"
5. Give it an appropriate name like "Authn Token Integration"
6. Select "Client secret" as the Client authentication method
7. Copy client ID and client secret string somewhere
8. Grant the application the `okta.apiTokens.read` scope
9. Set client id at `spring.security.oauth2.resourceserver.opaquetoken.client-id` in application.yml
10. Set secret in the environment variable `SPRING_SECURITY_OAUTH2_RESOURCESERVER_OPAQUETOKEN_CLIENT_SECRET`

## How to run application locally

Expand Down
155 changes: 155 additions & 0 deletions auth/src/scripts/get_client_access_token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import jwt
import time
import requests
import uuid
import pprint

"""
============================
CREATE THE OKTA API JWT
============================
"""

"""
okta_private_key and client_id is generated within Okta by an RS onboarding person and emailed
to the client. See https://developer.okta.com/docs/guides/implement-oauth-for-okta-serviceapp/main

See this documentation to understand how to setup an authorization server:
https://developer.okta.com/docs/guides/customize-authz-server/main/#create-scopes
"""
authorization_server_id = "" # set your authorization server id here
client_id = "" # set you application user's client it
okta_private_key = """""" # set your application user's private key in PEM format
okta_kid = "" # set your application user's Key ID string
requested_scope = "sender" # update requested scope to desired one
dpop_private_key = """""" # Set DPoP private key in PEM format
dpop_public_key_json = {} # set DPoP public key in JWK json format

encoded_jwt = jwt.encode(
{
"ver": 1,
"aud": f"https://reportstream.oktapreview.com/oauth2/{authorization_server_id}/v1/token",
"iat": time.time(),
"exp": time.time() + 1000,
"cid": client_id,
"iss": client_id,
"sub": client_id,
"scp": [
requested_scope
],
"auth_time": 1000
},
okta_private_key,
algorithm='RS256',
headers={
"alg": "RS256",
"kid": okta_kid
}
)
print("The encoded JWT")
print(encoded_jwt)
print("="*15)

"""
==============================================================
CREATE THE DPoP JWT (ONLY IF THE APP HAS DPoP ENABLED IN OKTA)
==============================================================
"""


encoded_dpop_jwt = jwt.encode(
{
"htm": "POST",
"htu": f"https://reportstream.oktapreview.com/oauth2/{authorization_server_id}/v1/token",
"iat": time.time(),
},
dpop_private_key,
algorithm='RS256',
headers={
"typ": "dpop+jwt",
"alg": "RS256",
"jwk": dpop_public_key_json
}
)
print("The encoded DPoP JWT")
print(encoded_dpop_jwt)
print("="*15)

"""
============================
MAKE THE OKTA TOKEN REQUEST
============================
"""
headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"DPoP": encoded_dpop_jwt
}
payload = {
"grant_type": "client_credentials",
"scope": requested_scope,
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": encoded_jwt,
"client_id": client_id
}
r = requests.post(
f"https://reportstream.oktapreview.com/oauth2/{authorization_server_id}/v1/token",
params=payload,
headers=headers
)

"""
============================
UPDATE NONCE IN DPoP JWT
============================
"""
encoded_dpop_jwt_with_nonce = jwt.encode(
{
"htm": "POST",
"htu": f"https://reportstream.oktapreview.com/oauth2/{authorization_server_id}/v1/token",
"iat": time.time(),
"nonce": r.headers["dpop-nonce"],
"jti": str(uuid.uuid4())
},
dpop_private_key,
algorithm='RS256',
headers={
"typ": "dpop+jwt",
"alg": "RS256",
"jwk": dpop_public_key_json
}
)
print("The encoded DPoP JWT")
print(encoded_dpop_jwt)
print("="*15)

"""
============================================
MAKE THE OKTA TOKEN REQUEST WITH UPDATE DPoP
============================================
"""
headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded",
"DPoP": encoded_dpop_jwt_with_nonce
}
payload = {
"grant_type": "client_credentials",
"scope": requested_scope,
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": encoded_jwt,
"client_id": client_id
}
r = requests.post(
"https://reportstream.oktapreview.com/oauth2/ausekaai7gUuUtHda1d7/v1/token",
params=payload,
headers=headers
)
print("request response: ", r.text)
print(r)
encoded_token = r.json()["access_token"]
print("ENCODED TOKEN: ", encoded_token)
decoded_token = jwt.decode(encoded_token, options={"verify_signature": False})
print("\n\n\nFINAL DECODED BEARER TOKEN:")
print("===========================")
pprint.pprint(decoded_token)
Loading