├── .env_example ├── .gitignore ├── app.js ├── gateways ├── apigee │ ├── apiproxy.zip │ ├── apiproxy │ │ ├── okta-verify-jwt.xml │ │ ├── policies │ │ │ ├── AV-OktaJwks.xml │ │ │ ├── CacheInsert-OktaJwks.xml │ │ │ ├── CacheLookup-OktaJwks.xml │ │ │ ├── EV-JWT.xml │ │ │ ├── RF-MissingHeader.xml │ │ │ ├── RF-MissingRequiredScope.xml │ │ │ ├── RF-TestTokenOK.xml │ │ │ ├── RF-UnknownRequest.xml │ │ │ ├── SC-RetrieveOktaJwks.xml │ │ │ └── Verify-JWT-1.xml │ │ ├── proxies │ │ │ └── default.xml │ │ └── targets │ │ │ └── default.xml │ └── readme.md ├── aws │ ├── lambda.md │ └── readme.md ├── kong │ └── readme.md ├── mulesoft │ ├── jwt_validation.raml │ ├── jwt_validation_readme.md │ ├── mulesoft.raml │ └── readme.md ├── swag │ └── readme.md └── tyk │ └── readme.md ├── html └── index.html ├── okta.json ├── okta_setup_manual.md ├── package.json ├── readme.md └── routes.js /.env_example: -------------------------------------------------------------------------------- 1 | 2 | AUD=api://default 3 | 4 | OKTA_TENANT=https://dev-399486.okta.com 5 | ISSUER=https://dev-399486.okta.com/oauth2/default 6 | 7 | CLIENT_ID=0oa1opaydr1bnvBKL357 8 | CLIENT_SECRET= 9 | 10 | # Valid values: APIGEE || AWS_JWT || AWS_LAMBDA || KONG || MULESOFT || || SWAG || TYK 11 | GATEWAY= 12 | GATEWAY_URI= 13 | 14 | # App settings 15 | PORT=8080 16 | REDIRECT_URI=http://localhost:8080 17 | 18 | SESSION_SECRET="some random phrase" 19 | SESSION_MAX_AGE=60000 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /config/instances 3 | /node_modules 4 | npm-debug.log 5 | .env* 6 | !.env_example* 7 | package-lock.json 8 | /okta_bootstrap/output/* 9 | *snapshot_*.json -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | // Okta API Access Management 2 | 3 | //////////////////////////////////////////////////// 4 | require('dotenv').config() 5 | 6 | var bodyParser = require('body-parser') 7 | 8 | const express = require('express') 9 | 10 | var fs = require("fs") 11 | 12 | var session = require("express-session") 13 | 14 | /////////////////////////////////////////////////// 15 | 16 | const app = express() 17 | 18 | app.use(session({ 19 | secret: process.env.SESSION_SECRET, 20 | cookie: { maxAge: parseInt(process.env.SESSION_MAX_AGE) }, 21 | resave: true, 22 | saveUninitialized: true 23 | })) 24 | 25 | app.use(bodyParser.json()) 26 | 27 | require('./routes.js')(app) 28 | 29 | app.listen(process.env.PORT, function () { 30 | console.log('App listening on port ' + process.env.PORT + "...") 31 | }) -------------------------------------------------------------------------------- /gateways/apigee/apiproxy.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tom-smith-okta/okta-api-center/0740206e671031169384174934e6292f23f2f44f/gateways/apigee/apiproxy.zip -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/okta-verify-jwt.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | /solar-system 4 | 5 | 1517281941236 6 | tom.smith@okta.com 7 | 8 | solar-system 9 | 1517281941236 10 | tom.smith@okta.com 11 | 12 | AV-OktaJwks 13 | CacheInsert-OktaJwks 14 | CacheLookup-OktaJwks 15 | EV-JWT 16 | RF-MissingHeader 17 | RF-MissingRequiredScope 18 | RF-TestTokenOK 19 | RF-UnknownRequest 20 | SC-RetrieveOktaJwks 21 | Verify-JWT-1 22 | 23 | 24 | default 25 | 26 | 27 | 28 | 29 | 30 | default 31 | 32 | 33 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/AV-OktaJwks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | AV-OktaJwks 4 | 5 | 6 | 7 | cached.okta.jwks 8 | oktaJwksResponse.content 9 | 10 | false 11 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/CacheInsert-OktaJwks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CacheInsert-OktaJwks 4 | 5 | 6 | 7 | oktajwks 8 | 1 9 | 10 | cache1 11 | Application 12 | 13 | 3600 14 | 15 | oktaJwksResponse.content 16 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/CacheLookup-OktaJwks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | CacheLookup-OktaJwks 4 | 5 | 6 | 7 | oktajwks 8 | 1 9 | 10 | cache1 11 | Application 12 | cached.okta.jwks 13 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/EV-JWT.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | EV-JWT 4 | 5 | 6 |
7 | Bearer {jwt} 8 |
9 | false 10 | request 11 | inbound 12 |
-------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/RF-MissingHeader.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | RF-MissingHeader 4 | 5 | 6 | 7 | 8 | 9 | Missing Authorization Header 10 | 400 11 | Bad Request 12 | 13 | 14 | true 15 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/RF-MissingRequiredScope.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | RF-MissingRequiredScope 4 | 5 | 6 | 7 | { 8 | "error" : { 9 | "code" : 403, 10 | "message" : "missing required scope for that endpoint" 11 | } 12 | } 13 | 14 | 403 15 | Not Authorized 16 | 17 | 18 | true 19 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/RF-TestTokenOK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | RF-TestTokenOK 4 | 5 | 6 | 7 | { 8 | "jti" : "{jwt.Verify-JWT-1.id}", 9 | "secondsRemaining" : {jwt.Verify-JWT-1.seconds_remaining}, 10 | "timeRemainingFormatted" : "{jwt.Verify-JWT-1.time_remaining_formatted}" 11 | } 12 | 13 | 200 14 | OK 15 | 16 | 17 | true 18 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/RF-UnknownRequest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | RF-UnknownRequest 4 | 5 | 6 | 7 | 8 | { 9 | "error" : { 10 | "code" : 404.01, 11 | "message" : "that request was unknown" 12 | } 13 | } 14 | 15 | 404 16 | Not Found 17 | 18 | 19 | true 20 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/SC-RetrieveOktaJwks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SC-RetrieveOktaJwks 4 | 5 | 6 | 7 | 8 | GET 9 | 10 | false 11 | 12 | oktaJwksResponse 13 | 14 | 15 | 2xx 16 | 17 | https://partnerpoc.oktapreview.com/oauth2/ausce8ii5wBzd0zvQ0h7/v1/keys 18 | 19 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/policies/Verify-JWT-1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Verify-JWT-1 4 | 5 | 6 | RS256 7 | 8 | 9 | false 10 | https://partnerpoc.oktapreview.com/oauth2/ausce8ii5wBzd0zvQ0h7 11 | 12 | 13 | 14 | inbound.jwt 15 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/proxies/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Parse / Verify a JWT created by Okta 8 | 9 | 10 | request.header.authorization = null 11 | 12 | RF-MissingHeader 13 | 14 | 15 | 16 | EV-JWT 17 | 18 | 19 | 20 | CacheLookup-OktaJwks 21 | 22 | 23 | cached.okta.jwks = null 24 | 25 | SC-RetrieveOktaJwks 26 | 27 | 28 | cached.okta.jwks = null 29 | 30 | CacheInsert-OktaJwks 31 | 32 | 33 | cached.okta.jwks = null 34 | 35 | AV-OktaJwks 36 | 37 | 38 | 39 | Verify-JWT-1 40 | 41 | 42 | 43 | (proxy.pathsuffix MatchesPath "/planets") and (jwt.Verify-JWT-1.claim.scp !~ "*http://myapp.com/scp/silver*" 44 | RF-MissingRequiredScope 45 | 46 | 47 | 48 | (proxy.pathsuffix MatchesPath "/moons") and (jwt.Verify-JWT-1.claim.scp !~ "*http://myapp.com/scp/gold*" 49 | RF-MissingRequiredScope 50 | 51 | 52 | 53 | proxy.pathsuffix MatchesPath "/test" 54 | RF-TestTokenOK 55 | 56 | 57 | (request.verb = "GET") and 58 | ( 59 | (proxy.pathsuffix MatchesPath "/moons") or 60 | (proxy.pathsuffix MatchesPath "/planets") or 61 | (proxy.pathsuffix MatchesPath "/test") 62 | ) 63 | 64 | 65 | 66 | 67 | 68 | 69 | RF-UnknownRequest 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | /solar-system 85 | 86 | default 87 | secure 88 | 89 | 90 | default 91 | 92 | -------------------------------------------------------------------------------- /gateways/apigee/apiproxy/targets/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | https://okta-solar-system.herokuapp.com 17 | 18 | -------------------------------------------------------------------------------- /gateways/apigee/readme.md: -------------------------------------------------------------------------------- 1 | # Okta API Access Management + Apigee 2 | 3 | These instructions will explain how to set up Okta as an external OAuth authorization server for Apigee. In this architecture, the application will obtain an access token from Okta's authorization server, and pass that access token to Apigee as a bearer token (jwt). Apigee will evaluate the bearer token to determine whether the token is valid, and whether it contains the proper scopes for the requested resource. 4 | 5 | It is also possible to set up Okta as (only) an identity provider and instead use Apigee itself as the authorization server. Instructions for setting up that flow are [here](https://github.com/zeekhoo-okta/generator-okta-oidc-apigee). 6 | 7 | ## Prerequisites 8 | - An Okta tenant. These instructions assume that you have already set up your Okta tenant and can acquire access tokens from Okta by following the instructions in the [main readme of this repo](readme.md). 9 | - An Apigee tenant. If you do not already have an Apigee tenant, you can get a free trial [here](https://apigee.com/about/cp/apigee-edge-free-trial). 10 | - An API. In this example setup, we'll be using a mock "solar system" API, which is publicly available. You can substitute your own API if you wish. 11 | 12 | ## Setup: Apigee 13 | 14 | * This is an Okta-fied version of the more general Apigee repo created [here](https://github.com/DinoChiesa/ApigeeEdge-JWT-Demonstration). You are encouraged to explore the more comprehensive Apigee repo for more context. 15 | 16 | * There is also an excellent accompanying video overview of how Apigee handles JWTs [here](https://community.apigee.com/articles/49280/jwt-policies-in-apigee-edge.html). 17 | 18 | ### Overview 19 | 20 | Setting up the proxy in Apigee is very straightforward. This repo contains an `apiproxy.zip` archive that contains all of the setup info needed for this example. 21 | 22 | If you wish, you can make changes to any of the files and values in the `apiproxy` directory, and then zip the directory before uploading. You might want to just start with the pre-built archive first. 23 | 24 | The only values that need to be updated in the proxy are the `URL` value in the `SC-RetrieveOktaJwks.xml` file and the `Issuer` value in the `Verify-JWT-1.xml` file. 25 | 26 | These values are easily updated in Apigee after uploading the pre-built proxy. 27 | 28 | ### Steps 29 | 30 | - Before you deploy the proxy you need to create a cache on the Apigee environment. The cache should be named `cache1`. 31 | 32 | To deploy the proxy to your Apigee tenant: 33 | - in your Apigee tenant, go to "API Proxies" and click the `+Proxy` button 34 | - select "Proxy bundle" then click Next 35 | - upload the `apiproxy.zip` file 36 | - choose a name for the proxy or just keep the default, then click Next 37 | - click Build 38 | - your proxy will load. 39 | - click the link to view the proxy in the API editor 40 | - click the "develop" tab to view the flows and source XML 41 | - open the Verify-JWT-1 policy 42 | - update the Issuer value with your authorization server URL 43 | 44 | ![authorization server](https://s3.amazonaws.com/tom-smith-okta-api-center/authz_server.png "Authorization server") 45 | 46 | - deploy your proxy to test, dev, or prod, depending on your preference. 47 | 48 | you are now deployed! 49 | 50 | Your API proxy tenant should now be deployed at {{your Apigee env}}/solar-system 51 | 52 | Take note of your API proxy URL. 53 | 54 | There are three built-in proxy endpoints that you can test against. All of these endpoints will expect a valid access token minted by your Okta authorization server. The access token must be included in the header of the request. (The sample app will do this for you.) 55 | 56 | * {{your Apigee env}}/solar-system/test 57 | * if the access token is valid, this endpoint will return a 200 status OK 58 | * {{your Apigee env}}/solar-system/planets 59 | * if the access token is valid AND includes the scope `http://myapp.com/scp/silver`, this proxy endpoint will pass on the request to the target endpoint, which will return a list of planets. 60 | * {{your Apigee env}}/solar-system/moons 61 | * if the access token is valid AND includes the scope `http://myapp.com/scp/gold`, this proxy endpoint will pass on the request to the target endpoint, which will return a list of moons. 62 | 63 | These policies are expressed in the main Apigee proxy flow: `parse + validate a JWT obtained from Okta`. 64 | 65 | ![main flow](https://s3.amazonaws.com/tom-smith-okta-api-center/main_flow.png "main flow") 66 | 67 | You can of course adjust the values here to suit your own use-case. 68 | 69 | ## Testing 70 | 71 | Now that you have set up Apigee as an API proxy, you can test out the whole flow. Take note of the URL of your Apigee deployment, jump back to the main `readme` in this repo, and go to the `Test your application and access tokens` section. 72 | -------------------------------------------------------------------------------- /gateways/aws/lambda.md: -------------------------------------------------------------------------------- 1 | # Integrating Okta with Amazon API Gateway - Lambda authorizer 2 | 3 | This integration guide describes how to integrate Okta's API Access Management (OAuth as a Service) with Amazon API Gateway. 4 | 5 | AWS has recently (Spring 2020) released a new way to integrate Amazon API Gateway with external OAuth providers such as Okta: [JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html). 6 | 7 | This new way of integrating Okta is much simpler than setting up a custom authorizer using a Lambda function. The lambda authorizer approach is of course much more powerful and flexible, but you should start with the [JWT authorizer approach](readme.md) unless you're certain that you need a lambda authorizer. 8 | 9 | The basic flow is that Amazon API Gateway will accept incoming requests and pass them on to a custom Lambda authorizer. The Lambda authorizer (which we will set up) will evaluate the access token included in the request and determine whether the access token is 1) valid and 2) contains the appropriate scopes for the requested resource. 10 | 11 | We will set up the Lambda authorizer to validate the access tokens against Okta. 12 | 13 | We'll be using a mock "solar system" API that is publicly available, so you don't need to worry about setting up the API itself. 14 | 15 | ## Prerequisites 16 | 17 | ### Okta 18 | 19 | These instructions assume that you have already set up your Okta tenant and can acquire access tokens from Okta by following the instructions in the [main readme of this repo](readme.md). 20 | 21 | As a result of those setup steps, you should have the following values on hand before proceeding: 22 | 23 | ISSUER 24 | example: https://dev-399486.okta.com/oauth2/default 25 | this value will be `{{OKTA_TENANT}}/oauth2/default` unless you've set up a different authorization server in Okta. 26 | 27 | ### AWS 28 | 29 | You will also of course need an AWS account. 30 | 31 | ### Overview 32 | 33 | The high-level process we are going to follow is: 34 | 35 | 1. Set up your API in Amazon API Gateway 36 | 2. Add a Lambda function to your AWS account to handle authorization (this step includes setting up an IAM role) 37 | 3. Add the Lambda authorization function to selected resources in your API Gateway 38 | 39 | ## Set up your API in Amazon API Gateway 40 | 41 | In your AWS Management Console, go to API Gateway. 42 | 43 | Click “Create API” 44 | 45 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_create_api.png) 46 | 47 | Select *New API* and choose a name and description for your API: 48 | 49 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_new_api_settings.png) 50 | 51 | Click **Create API** 52 | 53 | We now have an “empty” API 54 | 55 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_empty.png) 56 | 57 | Now create a method: Actions->Create Method->GET 58 | 59 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_create_method_get.png) 60 | 61 | Click the checkmark to save the new method. 62 | 63 | In the GET - Setup screen, choose the following options: 64 | 65 | * Integration type: HTTP 66 | * Use HTTP Proxy integration: yes 67 | * HTTP method: GET 68 | * Endpoint URL: https://okta-solar-system.herokuapp.com 69 | * Content Handling: Passthrough 70 | * Use Default Timeout: yes 71 | 72 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_get_setup.png) 73 | 74 | Click **Save**. 75 | 76 | Your GET request should now look like this: 77 | 78 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_get_method_execution.png) 79 | 80 | At this point, test the gateway to ensure that it's properly proxying requests: 81 | 82 | Click the **Actions** button, then *Deploy API*. 83 | 84 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_deploy_api.png) 85 | 86 | For *Deployment Stage*, choose **[New Stage]**, and for *Stage name*, enter `test` 87 | 88 | You don't need to enter anything for the *Stage description* and *Deployment description* fields, but you can if you wish. 89 | 90 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_new_stage.png) 91 | 92 | Now click **Deploy** 93 | 94 | You will now have an *Invoke URL* where you can test the proxy. 95 | 96 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_invoke_url.png) 97 | 98 | Click the Invoke URL, and you should arrive at a simple page with the text "Okta solar system api": 99 | 100 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_solar-system_home.png) 101 | 102 | This Invoke URL is important; we're going to use it as the GATEWAY_URI for our sample application. 103 | 104 | Now, let's add a couple of "real" endpoints to the proxy. 105 | 106 | Go back to the API Gateway, and under your API name in the left-hand side, click *Resources*. 107 | 108 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_resources.png) 109 | 110 | Click the **Actions** button and select *Create Resource*. 111 | 112 | Leave the *Configure as proxy resource* box unchecked. 113 | *Resource Name*: `planets` 114 | *Resource Path*: `planets` 115 | 116 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_planets.png) 117 | 118 | Click **Create Resource**. 119 | 120 | Now let's add a method to that Resource. Click Actions -> Create Method -> GET->checkmark. 121 | 122 | Just as we did for the previous definition of GET, we're going to choose: 123 | 124 | *Integration type*: HTTP 125 | 126 | *Use HTTP Proxy integration*: **Yes** 127 | 128 | *HTTP Method*: GET 129 | 130 | *Endpoint URL*: `https://okta-solar-system.herokuapp.com/planets` 131 | 132 | *Content Handling*: Passthrough 133 | 134 | *Use Default Timeout*: Yes 135 | 136 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_planets_setup.png) 137 | 138 | Click **Save**. 139 | 140 | The sample application will test two endpoints: 141 | 142 | `/planets` 143 | and 144 | `/moons` 145 | 146 | If you would like to add the `/moons` endpoint, go ahead and do that now, using the same steps you did for `/planets`. The `/moons` endpoint is not required, but it helps to show how different users can have access to different resources. We'll assign the different scopes required to access these endpoints when we set up the Lambda authorization function. 147 | 148 | ## Set up the Lambda authorizer 149 | 150 | Amazon API Gateway uses a Lambda function to inspect access tokens. So, we need to set up a Lambda function as an authorizer for this API. 151 | 152 | Follow the instructions [here](https://github.com/tom-smith-okta/node-lambda-oauth2-jwt-authorizer) to set up the Lambda authorizer. 153 | 154 | > Stop when you get to the *Testing* section, and come back to this document. 155 | 156 | Now that you have set up your authorizer, we can add it to the `/planets` method we created earlier. 157 | 158 | ## Add the Lambda Authorizer to API Resources 159 | 160 | Click on the *Resources* section of your API, then click on the GET method that is a child of /planets: 161 | 162 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_method_req.png) 163 | 164 | Click *Method Request* 165 | 166 | In Settings->Authorization, choose the Lambda Authorizer that you set up. 167 | 168 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/amazon_api_gateway/aws_api_gateway_authorizer.png) 169 | 170 | Click the checkmark to save the authorizer. 171 | 172 | ## Deploy the API 173 | 174 | Now that we've added authorization to one of our resources, we can deploy the API again and test it. 175 | 176 | Click the **Actions** button, then *Deploy API*. 177 | 178 | Click **Deploy**. 179 | 180 | If you click on the *Invoke URL* as-is, then you will again arrive at the home for the solar system API. 181 | 182 | If you append */planets* to the Invoke URL, you will get an *Unauthorized* message. This means that our authorizer is doing its job and blocking attempts to reach the `/planets` resource without a valid access token. 183 | 184 | ## Testing 185 | 186 | Now that you have set up Amazon API Gateway as an API proxy, you can test out the whole flow. Take note of the Invoke URL, jump back to the main `readme` in this repo, and go to the `Test your application and access tokens` section. 187 | -------------------------------------------------------------------------------- /gateways/aws/readme.md: -------------------------------------------------------------------------------- 1 | # Integrating Okta with Amazon API Gateway - JWT authorizer 2 | 3 | This integration guide describes how to integrate Okta's API Access Management (OAuth as a Service) with Amazon API Gateway. 4 | 5 | AWS has recently (Spring 2020) released a new way to integrate Amazon API Gateway with external OAuth providers such as Okta: [JWT authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html). 6 | 7 | These setup instructions will use this new way of integrating Okta, which is much simpler than setting up a custom authorizer using a Lambda function. The [Lambda authorizer approach](lambda.md) is of course much more powerful and flexible, but you should start with the JWT authorizer approach unless you're certain that you need a Lambda authorizer. 8 | 9 | We'll be using a mock "solar system" API that is publicly available, so you don't need to worry about setting up the API itself. 10 | 11 | ## Prerequisites 12 | 13 | ### Okta 14 | 15 | These instructions assume that you have already set up your Okta tenant and can acquire access tokens from Okta by following the instructions in the [main readme of this repo](/readme.md). 16 | 17 | As a result of those setup steps, you should have the following values on hand before proceeding: 18 | 19 | ISSUER 20 | 21 | example: https://dev-399486.okta.com/oauth2/default 22 | 23 | this value will be `{{OKTA_TENANT}}/oauth2/default` unless you've set up a different authorization server in Okta. 24 | 25 | ### AWS 26 | 27 | You will also of course need an AWS account. 28 | 29 | ### Overview 30 | 31 | We are going to set up an "HTTP" type API in API gateway, and add Okta as a JWT source for authorization. 32 | 33 | We will also add JWT policies to the API gateway so that specific endpoints will be protected by specific scopes. 34 | 35 | ## Set up your API in Amazon API Gateway 36 | 37 | In your AWS Management Console, go to API Gateway and click **Create API**. 38 | 39 | On the "Choose an API type" screen: 40 | 41 | We are going to build an HTTP API, so click **Build** inside the HTTP API box. 42 | 43 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/01_http_api.png) 44 | 45 | In the **Create and configure integrations** box, click **Add integration**, then assign the following values: 46 | 47 | Integrations: HTTP 48 | 49 | Method: ANY 50 | 51 | URL endpoint: https://okta-solar-system.herokuapp.com 52 | 53 | API name: okta solar system 54 | 55 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/02_create_and_configure.png) 56 | 57 | Click **Review and Create**. 58 | 59 | You should now see an overview screen of your API. 60 | 61 | Click **Create**. 62 | 63 | Wait a second for a value to appear in the "Attached deployment" column, so you know that your API is deployed. 64 | 65 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/05_api_details.png) 66 | 67 | At this point, you can click on the **Invoke URL** and you will see that you are successfully proxying the solar system API home page: 68 | 69 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/06_proxy_works.png) 70 | 71 | >Note: stash your **Invoke URL** somewhere handy. 72 | 73 | >Note: throughout this project, we are just going to use the default Stage for this API, which means that updates will deploy automatically. So, you should not have to click the **Deploy** button to successfully complete this setup. 74 | 75 | ### Add a route 76 | 77 | Now let's add a route to our solar system API, so we can start getting some actual data back and see how authorization works. 78 | 79 | For this first route, we're just going to do some validation of the access token. We'll add scopes to the equation later, after we know that our authorization integration is working. 80 | 81 | Click on Develop->Routes, then **Create**. 82 | 83 | On the **Create a route** screen, choose GET as your method, and enter 84 | 85 | `/asteroids` 86 | 87 | in the path field: 88 | 89 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/07_create_route_asteroids.png) 90 | 91 | Click **Create** to create the route. 92 | 93 | On the **Routes** screen, click on **GET** underneath the `/asteroids` path, and you will see options to **Attach authorizer** and **Attach integration**: 94 | 95 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/08_route_details_asteroids.png) 96 | 97 | Click **Attach authorizer** and you will go to the Authorization screen: 98 | 99 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/09_first_authorizer.png) 100 | 101 | Click **Create and attach an authorizer** 102 | 103 | On the **Create JWT authorizer** screen, populate the **Authorizer settings** with the following values: 104 | 105 | Name: Okta 106 | 107 | Identity source: $request.header.Authorization 108 | 109 | Issuer URL: {{ISSUER}} 110 | 111 | (example: https://dev-399486.okta.com/oauth2/default) 112 | 113 | Audience: api://default 114 | 115 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/10_authorizer_settings.png) 116 | 117 | Click **Create and attach**. 118 | 119 | Your **Authorization** screen should look something like this: 120 | 121 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/11_authorizer_details.png) 122 | 123 | Now, we need to attach an "integration" to the `/asteroids` route. 124 | 125 | Click Develop->Routes and select the **GET** method of your `/asteroids` route (it may already be selected.) 126 | 127 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/12_routes_attach_integration_asteroids.png) 128 | 129 | Click **Attach integration**. 130 | 131 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/13_routes_attach_integration_asteroids.png) 132 | 133 | Click **Create and attach an integration**. 134 | 135 | On the **Create an integration** screen, populate the form with the following values: 136 | 137 | Integration with: HTTP URI 138 | 139 | HTTP method: GET 140 | 141 | URL: https://okta-solar-system.herokuapp.com/asteroids 142 | 143 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/14_create_an_integration.png) 144 | 145 | Click **Create**. 146 | 147 | Your integration should look something like this: 148 | 149 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/15_asteroid_integration_complete.png) 150 | 151 | ### Test the first route 152 | 153 | When we initially set up the API, we verified that the **Invoke URL** loads the home page of the target solar system API. 154 | 155 | Now, if we try to get data from a route (/asteroids) that we've attached an authorizer to (without including an access token), we should get an "Unauthorized" error: 156 | 157 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/16_asteroids_unauthorized.png) 158 | 159 | So, the API gateway is successfully blocking the request because it doesn't have an access token. 160 | 161 | Let's get an access token and see if the authorization process works. 162 | 163 | In the `.env` file of the test application, add "AWS_JWT" as the value for GATEWAY, and add your Invoke URL as the value for GATEWAY_URI. 164 | 165 | Restart the node app. 166 | 167 | Load the web page again, and click on "authenticate" in the Bronze access box to get an access token. Then, click on the **show me some asteroids!** button to get a selected list of asteroids. 168 | 169 | Once you're able to successfully get a list of asteroids, we can move on to adding more routes to the gateway, and these new routes will require scopes to allow access. 170 | 171 | ### Add the /planets route 172 | 173 | Go to your API Gateway and click Develop->Routes. 174 | 175 | On the **Routes** screen, click **Create**. 176 | 177 | On the **Create a route** screen, add a new route with: 178 | 179 | Method: GET 180 | 181 | Route: /planets 182 | 183 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/17_create_route_planets.png) 184 | 185 | Click **Create**. 186 | 187 | On the **Routes** screen, select the GET method of the `/planets` endpoint. 188 | 189 | Click **Attach authorizer**. 190 | 191 | On the **Authorization** screen, click on the **Select existing authorizer** box, and choose Okta. 192 | 193 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/18_select_existing_authorizer.png) 194 | 195 | Click **Attach authorizer**. 196 | 197 | The **Authorization** screen should now look something like this: 198 | 199 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/19_authorizer_details.png) 200 | 201 | Now, let's add a scope to further protect this route. 202 | 203 | Click **Add scope**. 204 | 205 | Enter http://myapp.com/scp/silver in the scope field, then click **Save**. 206 | 207 | We still need to add an "integration" for this route, so click on Develop->Routes. 208 | 209 | Select the GET method of the `/planets` endpoint. 210 | 211 | Click **Attach integration**. 212 | 213 | On the **Integrations** screen, click **Create and attach an integration**. 214 | 215 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/20_attach_integration.png) 216 | 217 | On the **Create an integration** screen, enter the following values: 218 | 219 | Integration target: HTTP URI 220 | 221 | HTTP method: GET 222 | 223 | URL: https://okta-solar-system.herokuapp.com/planets 224 | 225 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/amazon_api_gateway/jwt_authorizer/21_add_integration_planets.png) 226 | 227 | Click **Create**. 228 | 229 | You now have another route set up for your API gateway. The `/planets` route points to https://okta-solar-system.herokuapp.com/planets. Okta is the authorizer for this route, and the access token must include the http://myapp.com/scp/silver scope for the request to be honored. 230 | 231 | ### Add the /moons route 232 | 233 | To see how different scopes can align with Okta groups, routes, and scopes, you can add another route: `/moons`. 234 | 235 | Follow the same steps as the `/planets` route, but for the integration use the URI https://okta-solar-system.herokuapp.com/moons, and for the scope use http://myapp.com/scp/gold. 236 | 237 | ## Testing 238 | 239 | Now you can go back to the test application and see if the "show me the planets!" and "show me some moons!" buttons work. 240 | -------------------------------------------------------------------------------- /gateways/kong/readme.md: -------------------------------------------------------------------------------- 1 | # Integrating Okta + Kong 2 | 3 | This integration guide describes how to integrate Okta's API Access Management (OAuth as a Service) with Kong API Gateway. 4 | 5 | The integration described here is an authorization-tier integration; authentication will be happening outside of Kong. A web application will handle authentication vs. Okta, acquiring an access token, and sending that access token to Kong on behalf of the end-user. 6 | 7 | If you are instead interested in a scenario where Kong itself handles authentication vs. Okta, and passes user info to upstream apps, please see the blog post [here](https://developer.okta.com/blog/2017/12/04/use-kong-gateway-to-centralize-authentication). 8 | 9 | ## What You'll Build 10 | 11 | At the end of this setup, you'll have an architecture where: 12 | 13 | 1. Users will be able to authenticate against Okta and receive an access token (via the app) 14 | 2. Users will have different scopes in their access token, depending on their group assignments 15 | 3. The application will send the access token to Kong 16 | 4. Kong will check the validity of the access token locally 17 | 5. If the token and scopes are valid, Kong will send the request on to the API 18 | 6. The API will send the data payload to the gateway, which will send it on to the application 19 | 20 | ## Prerequisites for integrating Okta + Kong 21 | 22 | 1. **An Okta account.** If you don't already have one, you can get a free-forever account at [developer.okta.com](https://developer.okta.com/signup/) 23 | 2. **Kong Enterprise.** In this example we'll be using the [OpenID Connect (OIDC) plug-in for Kong](https://docs.konghq.com/plugins/ee-openid-connect/), which is only available for Kong Enterprise. If you don't already have a Kong Enterprise account, you can get a 30-day trial [here](https://konghq.com/free-trial/). 24 | 25 | ### Step-by-step 26 | The high-level process we are going to follow is: 27 | 28 | 1. Set up your Okta tenant 29 | 2. Set up your API in Kong 30 | 3. Set up and launch your application 31 | 32 | In the last step, we'll launch the sample application that will show the end-to-end flow. This sample application requires a few settings - environment variables - to launch. To manage these environment variables, the application uses the [dotenv npm package](https://www.npmjs.com/package/dotenv). There is an example .env file in the repo called `.env_example`. Copy the `.env_example` file now to a file called `.env`. 33 | 34 | This is what the .env_example file looks like: 35 | 36 | ``` 37 | # Okta settings 38 | 39 | # example: https://dev-511902.oktapreview.com 40 | OKTA_TENANT="" 41 | 42 | OKTA_API_TOKEN="" 43 | AUTHN_CLIENT_ID="" 44 | AUTHN_CLIENT_SECRET="" 45 | 46 | # example: https://dev-511902.oktapreview.com/oauth2/ausfqw42xrkmpfDHI0h7 47 | OKTA_AZ_SERVER_ISSUER="" 48 | 49 | # Gateway/Proxy base url 50 | # example: http://52.14.100.89:8080/solar-system 51 | PROXY_URI="" 52 | 53 | # App settings 54 | PORT="8080" 55 | REDIRECT_URI="http://localhost:8080" 56 | SILVER_USERNAME="" 57 | GOLD_USERNAME="" 58 | FAKE_USER_PASSWORD="" 59 | SESSION_SECRET="some random phrase" 60 | SESSION_MAX_AGE=60000 61 | 62 | # Supported values: aws, kong, mulesoft, swag, tyk 63 | GATEWAY="" 64 | ``` 65 | 66 | There are a couple of values you should fill in now, such as `OKTA_TENANT` and `GATEWAY`. I will point out when we generate the other values along the way; you can either enter them in your `.env` file as you go, or do it all at the end. There is a helper script that will gather the settings for you at the end. 67 | 68 | ## Set up Kong 69 | 70 | Make sure you have Kong up and running. If you have not yet set up your Kong tenant, you might want to check out their [5-minute quickstart](https://docs.konghq.com/enterprise/latest/getting-started/quickstart/). 71 | 72 | For now, you just need the URL of your Kong instance. The Kong API gateway typically runs on port 8000, so your url should look something like this: 73 | 74 | http://localhost:8000 75 | 76 | or 77 | 78 | http://ec2-18-24-32-111.us-east-2.compute.amazonaws.com:8000 79 | 80 | This is the `PROXY_URI` that you need to enter in the `.env` file. 81 | 82 | ## Set up your Okta tenant 83 | 84 | To properly demonstrate OAuth as a Service, you need a number of elements in your Okta tenant: a client, users, groups, an authorization server, scopes, policies, and rules. And, you need to establish the proper relationships among them. 85 | 86 | You have a couple of options to set these up: 87 | 88 | * You can use the Okta bootstrap tool. The Okta bootstrap tool is a "labs" type project. It is the fastest and easiest way to get your tenant set up. Instructions are [here](../../okta_setup/okta_setup_bootstrap.md). 89 | * You can set up your Okta tenant "manually", with Okta's easy-to-use admin UI. Instructions are available [here](../../okta_setup/okta_setup_manual.md). 90 | 91 | Go ahead and set up your Okta tenant, then come back to these instructions. 92 | 93 | ## Configure Kong 94 | 95 | To set up your API on Kong, it's easiest to use curl commands. Issue the following commands to set up your API with the example endpoints and scopes. 96 | 97 | ### Create the service (API) 98 | ``` 99 | curl -i -X POST \ 100 | --url http://localhost:8001/services/ \ 101 | --data 'name=solar-system' \ 102 | --data 'url=https://okta-solar-system.herokuapp.com' 103 | ``` 104 | ### Add a route (resource) - /planets 105 | ``` 106 | curl -i -X POST \ 107 | --url http://localhost:8001/services/solar-system/routes/ \ 108 | --data 'paths[]=/planets' \ 109 | --data 'strip_path=false' 110 | ``` 111 | You will get a json object as a result: 112 | ``` 113 | {"created_at":1531761136,"strip_path":false,"hosts":null,"preserve_host":false,"regex_priority":0,"updated_at":1531761136,"paths":["\/planets"],"service":{"id":"950db7a0-ae97-48ac-9327-89c8ee71034b"},"methods":null,"protocols":["http","https"],"id":"64640aa5-14ab-47a2-a75d-a93fa447be26"} 114 | ``` 115 | Copy the `id` value from the result. Note: make sure you copy the _route_ id, which is the last value, and not the _service_ id. 116 | 117 | ### Add the OIDC plugin to the /planets route 118 | Update the values for route_id, config.issuer, and config.client_id in the command below. You can find the OKTA_AZ_SERVER_ISSUER and the AUTHN_CLIENT_ID values in the bootstrap output file: 119 | `/okta_bootstrap/output/standard.json` 120 | 121 | and then execute this command: 122 | ``` 123 | curl -i -X POST \ 124 | --url http://localhost:8001/services/solar-system/plugins/ \ 125 | --data 'name=openid-connect' \ 126 | --data 'route_id={{ROUTE_ID}}' \ 127 | --data 'config.issuer={{OKTA_AZ_SERVER_ISSUER}}' \ 128 | --data 'config.client_id={{AUTHN_CLIENT_ID}}' \ 129 | --data 'config.ssl_verify=false' \ 130 | --data 'config.cache_ttl=60' \ 131 | --data 'config.scopes_required=http://myapp.com/scp/silver' \ 132 | --data 'config.scopes_claim=scp' 133 | ``` 134 | Note: we're disabling the `ssl_verify` option here for demo purposes, but you would not do that in production. 135 | 136 | ### Add another route - /moons 137 | ``` 138 | curl -i -X POST \ 139 | --url http://localhost:8001/services/solar-system/routes/ \ 140 | --data 'paths[]=/moons' \ 141 | --data 'strip_path=false' 142 | ``` 143 | again, capture the route id from the result. 144 | 145 | ### Add the OIDC plugin to the /moons route 146 | Use the same command as above, but make sure you update the `route_id` and `scopes_required` values. 147 | 148 | ``` 149 | curl -i -X POST \ 150 | --url http://localhost:8001/services/solar-system/plugins/ \ 151 | --data 'name=openid-connect' \ 152 | --data 'route_id={{ROUTE_ID}}' \ 153 | --data 'config.issuer={{OKTA_AZ_SERVER_ISSUER}}' \ 154 | --data 'config.client_id={{AUTHN_CLIENT_ID}}' \ 155 | --data 'config.ssl_verify=false' \ 156 | --data 'config.cache_ttl=60' \ 157 | --data 'config.scopes_required=http://myapp.com/scp/gold' \ 158 | --data 'config.scopes_claim=scp' 159 | ``` 160 | 161 | That completes the setup for Kong. We now have an API gateway (Service) and two resources (Routes) that are secured with scopes. 162 | 163 | ## Get the app settings 164 | 165 | If you used the Okta bootstrap tool for setup, you can run a script to gather the remaining settings that the app will need. 166 | 167 | The script will display the settings on the screen and also save them to an output file so that you can refer to them later if you need to. 168 | 169 | ```bash 170 | node get_settings.js --kong 171 | ``` 172 | 173 | Take these settings and update your `.env` file with any values that still need to be added. 174 | 175 | You can now launch your app: 176 | 177 | ```bash 178 | node app.js 179 | ``` 180 | 181 | When you load the web app, first try clicking on the "show me the planets" and/or the "show me the moons" buttons. You'll get an error notifying you that you need an access token. 182 | 183 | Next, try authenticating as one of the users. You'll get an id token and an access token displayed in the browser (in a production environment, you would not do this). The raw tokens are also available in the console if you want to check them out. 184 | 185 | Now that the user has a token (actually the token is sitting on the server), you can click on one of the "show me" buttons again to see if you get the requested resource. 186 | -------------------------------------------------------------------------------- /gateways/mulesoft/jwt_validation.raml: -------------------------------------------------------------------------------- 1 | #%RAML 1.0 2 | title: Okta API 3 | version: 1 4 | baseUri: https://okta-solar-system.herokuapp.com 5 | 6 | traits: 7 | jwt: 8 | headers: 9 | authorization: 10 | description: Bearer 11 | type: string 12 | responses: 13 | 400: 14 | description: Token was not provided. 15 | 401: 16 | description: Bad or expired token. To fix, you should re-authenticate the user. 17 | 403: 18 | description: The client id validation failed. 19 | 503: 20 | description: Error communicating with JWKS server. 21 | 22 | /asteroids: 23 | get: 24 | is: [jwt] 25 | description: retrieve a selected list of the asteroids 26 | responses: 27 | 200: 28 | body: 29 | application/json: 30 | example: | 31 | { 32 | "data": [ 33 | "ceres", "vesta", "pallas", "hygiea" 34 | ], 35 | "success": true, 36 | "status": 200 37 | } 38 | 39 | /moons: 40 | get: 41 | is: [jwt] 42 | description: retrieve a list of the moons 43 | responses: 44 | 200: 45 | body: 46 | application/json: 47 | example: | 48 | { 49 | "data": [ 50 | "callisto", "europa" 51 | ], 52 | "success": true, 53 | "status": 200 54 | } 55 | 56 | /planets: 57 | get: 58 | is: [jwt] 59 | description: retrieve a list of the planets 60 | responses: 61 | 200: 62 | body: 63 | application/json: 64 | example: | 65 | { 66 | "data": [ 67 | "jupiter", "mars" 68 | ], 69 | "success": true, 70 | "status": 200 71 | } 72 | 73 | /visitors: 74 | get: 75 | description: retrieve a list of interstellar visitors 76 | responses: 77 | 200: 78 | body: 79 | application/json: 80 | example: | 81 | { 82 | "data": [ 83 | "example1", "example2" 84 | ], 85 | "success": true, 86 | "status": 200 87 | } -------------------------------------------------------------------------------- /gateways/mulesoft/jwt_validation_readme.md: -------------------------------------------------------------------------------- 1 | # Integrating Okta with MuleSoft Anypoint 2 | 3 | There are two ways to integrate Okta as an authorization server with MuleSoft Anypoint: 4 | 5 | 1. Integrate Okta as an OpenID Connect Client Provider 6 | 2. Integrate Okta as an authorization server server via MuleSoft's JWT validation policy (requires Mule 4.1 or above) 7 | 8 | Broadly speaking, the OIDC client provider integration is deeper and more robust, including dynamic client registration, while the JWT validation method is lighter weight. 9 | 10 | If you're not sure which you need, or are not sure where to start, start with the JWT validation method. 11 | 12 | This readme describes the JWT validation method. 13 | 14 | The readme for the OIDC Connect Client Provider method is [here](readme.md). 15 | 16 | ## Prerequisites for this integration 17 | 18 | 1. **An Okta tenant.** These instructions assume that you have already set up your Okta tenant and can acquire access tokens from Okta by following the instructions in the [main readme of this repo](../readme.md). 19 | 2. **An API Gateway.** If you don't already have a Mulesoft Anypoint account, you can get a free 30-day trial version [here](https://anypoint.mulesoft.com/login/#/signup). 20 | 21 | ## Load the API definition to Exchange 22 | 23 | In your MuleSoft Anypoint tenant, click on the three small bars in the top left corner and go to Design Center 24 | 25 | ![alt text](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/mulesoft_design+center.png) 26 | 27 | Click on + Create New and select Create API specification 28 | 29 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/mulesoft_design_center_select.png) 30 | 31 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_new_api_specification.png) 32 | 33 | Give your API a name (like "okta solar system") and click "Create Specification". 34 | 35 | You now have an (almost) empty RAML file to design your API. 36 | 37 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_empty_raml.png) 38 | 39 | Next, copy the RAML template from the Okta API Center repo into the Mulesoft editor. 40 | 41 | ``` 42 | /gateways/mulesoft/jwt_validation.raml 43 | ``` 44 | 45 | Click Publish, then Publish to Exchange 46 | 47 | Assign asset version `1.0.0` then click Publish to Exchange 48 | 49 | ## Ingest API into API Manager 50 | 51 | Go to Anypoint API Manager. 52 | 53 | Click on Manage API, then Manage API from Exchange. 54 | 55 | In the API name field, enter `okta solar system` (or whatever you named your API) and click on the API name to autofill the fields. 56 | 57 | For "Managing type:" choose Endpoint with Proxy 58 | 59 | For "Mule version:" check the box for "Select if you are managing this API using Mule 4 or above." 60 | 61 | Your implementation should be pre-filled to be https://okta-solar-system.herokuapp.com 62 | 63 | Click Save. 64 | 65 | You should arrive at the Settings screen for your API. 66 | 67 | In the Deployment Configuration section: 68 | 69 | Runtime version: 4.3.0 70 | 71 | Proxy application name: {{some_unique_name}} 72 | 73 | Click Deploy. 74 | 75 | It will take a couple of minutes for Mule to deploy your API. 76 | 77 | After your API has deployed, scroll to the top of the page to find your Proxy URL. 78 | 79 | For example: http://my-api.us-e2.cloudhub.io/ 80 | 81 | >Note: take note now of this cloudhub proxy URL. You'll need it later and it can sometimes be hard to find again. 82 | 83 | First, test to see that the API is being proxied correctly. 84 | 85 | Load the following url in a web browser: 86 | 87 | ``` 88 | {{cloudhub proxy url}}/visitors 89 | ``` 90 | 91 | We have defined this endpoint in the RAML file to be completely open, so you should see a simple json object listing two of the recent visitors to the solar system. 92 | 93 | Now let's see if the authorization layer is working. 94 | 95 | Load the following url in a web browser: 96 | 97 | ``` 98 | {{cloudhub proxy url}}/asteroids 99 | ``` 100 | 101 | We have defined this endpoint in the RAML file to be protected by a JWT, so you should see a response like the following: 102 | 103 | ``` 104 | error: "Required header 'authorization' not specified" 105 | ``` 106 | 107 | You can now do a test to see if your proxy has deployed correctly. 108 | 109 | ## Add Your Okta JWKS URI to Mulesoft 110 | 111 | ### Get Your JWKS URI 112 | 113 | Now we need to add the JSON Web Key Set (JWKS) URL from your Okta authorization server to MuleSoft. 114 | 115 | Go to the well-known endpoint of your authorization server, which has the following pattern: 116 | 117 | ``` 118 | https://{{my_okta_domain}}/oauth2/{{authorization_server_id}}/.well-known/oauth-authorization-server 119 | ``` 120 | 121 | If you are using the developer edition of Okta, you're probably using the default authorization server, so your well-known endpoint is: 122 | 123 | ``` 124 | https://{{my_okta_domain}}/oauth2/default/.well-known/oauth-authorization-server 125 | ``` 126 | 127 | Once you have loaded your well-known endpoint, copy the `jwks_uri`. 128 | 129 | ### Create a JWKS validation policy 130 | 131 | On your MuleSoft API Administration screen, click on Policies. 132 | 133 | Click on Apply New Policy. 134 | 135 | Select JWT Validation->1.1.3 then click Configure Policy. 136 | 137 | Use the following values: 138 | 139 | (default) JWT origin: HTTP Bearer Authentication Header 140 | 141 | (default) JWT Signing Method: RSA 142 | 143 | (default) JWT Signing Key Length: 256 144 | 145 | JWT Key origin: JWKS 146 | 147 | JWKS Url: {{your JWKS URL}} 148 | 149 | (default) JWKS Caching TTL (minutes): 60 150 | 151 | Skip Client Id Validation: check 152 | 153 | Validate Audience Claim: leave blank for now 154 | 155 | Expiration Claim Mandatory: leave blank for now 156 | 157 | Not Before Claim Mandatory: leave blank for now 158 | 159 | Validate Custom Claim: leave blank for now 160 | 161 | Method & Resource conditions: 162 | * Apply configurations to specific methods & resources 163 | 164 | We're going to do just one endpoint for now. 165 | 166 | Method: 167 | GET 168 | 169 | URI template regex: 170 | /asteroids 171 | 172 | Click Apply 173 | 174 | Using Postman or some other API client, you can now try sending a GET request with an access token to the `/asteroids` endpoint. 175 | 176 | You should get a list of a few asteroids in return. 177 | 178 | If that flow works out, you can add two more policies to your API. 179 | 180 | Click on Apply New Policy. 181 | 182 | Select JWT Validation->1.1.3 then click Configure Policy. 183 | 184 | Use the same values as above, with the exception of: 185 | 186 | Validate Custom Claim: check 187 | 188 | In the Mandatory Custom Claim Validations section, add the following key-value pair: 189 | 190 | ``` 191 | scp : #[vars.claimSet.scp == ['http://myapp.com/scp/silver']] 192 | ``` 193 | 194 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/mulesoft/jwt_validation/mulesoft_jwt_validation_define_scope.png) 195 | 196 | make sure you click the + button on the right to lock in the key-value pair. 197 | 198 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/mulesoft/jwt_validation/mulesoft_jwt_validation_saved_scope.png) 199 | 200 | Method & Resource conditions: 201 | * Apply configurations to specific methods & resources 202 | 203 | Method: GET 204 | 205 | URI template regex: /planets 206 | 207 | Click Apply 208 | 209 | Repeat the same procedure for the /moons endpoint, but use the scp: 210 | 211 | ``` 212 | scp : #[vars.claimSet.scp == ['http://myapp.com/scp/gold']] 213 | 214 | ``` 215 | 216 | ## Testing 217 | 218 | Now you can go back to the test application and see if the "show me the planets!" and "show me some moons!" buttons work. 219 | -------------------------------------------------------------------------------- /gateways/mulesoft/mulesoft.raml: -------------------------------------------------------------------------------- 1 | #%RAML 1.0 2 | title: Okta solar system API 3 | version: 1 4 | baseUri: https://okta-solar-system.herokuapp.com 5 | 6 | traits: 7 | client-id-required: 8 | queryParameters: 9 | client_id: 10 | type: string 11 | client_secret: 12 | type: string 13 | 14 | securitySchemes: 15 | oauth_2_0: 16 | description: | 17 | Okta supports OAuth 2.0 for authenticating all API requests. 18 | type: OAuth 2.0 19 | describedBy: 20 | headers: 21 | Authorization: 22 | description: | 23 | Used to send a valid OAuth 2 access token. Do not use 24 | with the "access_token" query string parameter. 25 | type: string 26 | queryParameters: 27 | access_token: 28 | description: | 29 | Used to send a valid OAuth 2 access token. Do not use with 30 | the "Authorization" header. 31 | type: string 32 | responses: 33 | 401: 34 | description: | 35 | Bad or expired token. This can happen if the user or Okta 36 | revoked or expired an access token. To fix, re-authenticate 37 | the user. 38 | 403: 39 | description: | 40 | Bad OAuth request (wrong consumer key, bad nonce, expired 41 | timestamp...). Unfortunately, re-authenticating the user won't help here. 42 | settings: 43 | authorizationUri: AUTHORIZE_URL 44 | accessTokenUri: TOKEN_URL 45 | authorizationGrants: [ authorization_code, implicit ] 46 | 47 | /planets: 48 | get: 49 | is: [client-id-required] 50 | securedBy: [oauth_2_0] 51 | 52 | /moons: 53 | get: 54 | is: [client-id-required] 55 | securedBy: [oauth_2_0] -------------------------------------------------------------------------------- /gateways/mulesoft/readme.md: -------------------------------------------------------------------------------- 1 | # Integrating Okta with MuleSoft Anypoint 2 | 3 | There are two ways to integrate Okta as an authorization server with MuleSoft Anypoint: 4 | 5 | 1. Integrate Okta as an OpenID Connect Client Provider 6 | 2. Integrate Okta as an authorization server server via MuleSoft's JWT validation policy (requires Mule 4.1 or above) 7 | 8 | Broadly speaking, the OIDC client provider integration is deeper and more robust, including dynamic client registration, while the JWT validation method is lighter weight. 9 | 10 | If you're not sure which you need, or are not sure where to start, start with the JWT validation method. 11 | 12 | This readme describes the OIDC Connect Client Provider method. 13 | 14 | The readme for the JWT validation method is [here](jwt_validation_readme.md). 15 | 16 | ## Prerequisites for this integration 17 | 18 | 1. **An Okta tenant.** These instructions assume that you have already set up your Okta tenant and can acquire access tokens from Okta by following the instructions in the [main readme of this repo](../readme.md). 19 | 2. **An API Gateway.** If you don't already have a Mulesoft Anypoint account, you can get a free 30-day trial version [here](https://anypoint.mulesoft.com/login/#/signup). 20 | 21 | ## Configure your Mulesoft Account 22 | In your Mulesoft Anypoint tenant, click on the three small bars in the top left corner and go to Access Management (Below Management Center) 23 | click Client Providers 24 | click Add Client Provider -> OpenID Connect Dynamic Client Registration 25 | 26 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_external_identity.png) 27 | 28 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_dynamic_client_registration.png) 29 | 30 | The `Client Registration URL` is: {{OKTA_TENANT}}/oauth2/v1/clients 31 | 32 | The `Authorization Header` is: SSWS {{OKTA_API_KEY}} 33 | 34 | You can use the client ID and client secret that you set up during your Okta set-up as the Client ID and Client Secret for the Token Introspection Client. 35 | 36 | The Authorize URL, Token URL, and Token Introspection URL are all available from your Okta authorization server settings. 37 | 38 | If you are using the default settings, these URLs will look something like this: 39 | 40 | https://partnerpoc.oktapreview.com/oauth2/default/v1/token 41 | 42 | Click **Create**. 43 | 44 | Keep the values for `AUTHORIZE_URL` and `TOKEN_URL` handy, because you will need them in a moment. 45 | 46 | ## Add client provider to Environments 47 | 48 | In your Mulesoft Anypoint tenant, in the Access Management menu, click Environments 49 | 50 | Click on the Design environment 51 | 52 | Click on the Client provider pull-down item and select your client provider 53 | 54 | Click Update 55 | 56 | Repeat these steps to add your client provider to the Sandbox environment 57 | 58 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/mulesoft_edit_environment.png) 59 | 60 | Repeat these steps to add your client provider to the Sandbox environment 61 | 62 | ## Deploy Your Mulesoft API 63 | 64 | In your Mulesoft Anypoint tenant, click on the three small bars in the top left corner and go to Design Center 65 | 66 | ![alt text](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/mulesoft_design+center.png) 67 | 68 | Click on + Create New and select Create API specification 69 | 70 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/mulesoft_design_center_select.png) 71 | 72 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_new_api_specification.png) 73 | 74 | Give your API a name (like "okta solar system") and click "Create Specification". 75 | 76 | You now have an (almost) empty RAML file to design your API. 77 | 78 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_empty_raml.png) 79 | 80 | Next, copy the RAML template from the Okta API Center repo into the Mulesoft editor. 81 | 82 | ``` 83 | /gateways/mulesoft/mulesoft.raml 84 | ``` 85 | 86 | Update the values for `AUTHORIZE_URL` and `TOKEN_URL`. 87 | 88 | The file should save automatically; you can do command-s to force the save. 89 | 90 | Now click the “Publish” button in the upper right and select "Publish to Exchange" 91 | 92 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_publish_to_exchange.png) 93 | 94 | Enter am Asset version 1.0.0 and an API version 1 and click "Publish to Exchange". When it is complete, click Done 95 | 96 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_publish_to_exchange_detail.png) 97 | 98 | In your Mulesoft Anypoint tenant, click on the three small bars in the top left corner and go to API Manager 99 | 100 | Click the “Manage API" dropdown, and then “Manage API from Exchange” 101 | 102 | Start typing your API name (“okta solar system”) in the API name field to search for it. 103 | 104 | Choose the following options and click "Save". (Note that you might need to click somewhere in the Path field to activate the Save button.) 105 | 106 | ``` 107 | Asset type: RAML/OAS 108 | API version: 1 109 | Asset version: 1.0.0 110 | Managing type: Endpoint with Proxy 111 | Implementation URI: https://okta-solar-system.herokuapp.com 112 | Proxy deployment target: CloudHub 113 | Path: / 114 | ``` 115 | 116 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_manage_api_from_exchange.png) 117 | 118 | You now have a Settings screen for your API. Scroll down to the Deployment Configuration section, choose a runtime version (3.9.x works well), and enter a unique name for your cloudhub deployment. Make sure you save this url now. 119 | 120 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_deployment_config.png) 121 | 122 | Click "Deploy" to deploy your API to cloudhub. The deployment can take a few seconds or sometimes longer. You should see a successful deployment message when you are done: 123 | 124 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/mulesoft_deployment_successful.png) 125 | 126 | Save the path of your cloudhub.io deployment (example: "http://my-api.cloudhub.io") - you'll need it later. 127 | 128 | Click Close 129 | 130 | ## Set up Mulesoft Access Policies for Your API 131 | 132 | On the main settings screen of your API, click on "Policies", 133 | 134 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_click_policies.png) 135 | 136 | Then, click on “Apply New Policy” and select "OpenID Connect access token enforcement". 137 | 138 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/mulesoft_openid_access_token_enforcement.png) 139 | 140 | Click **Configure Policy** 141 | 142 | On the *Apply OpenId Connect access token enforcement policy* screen, add one scope to the list of scopes: 143 | `http://myapp.com/scp/silver`. 144 | 145 | Select "Apply configurations to specific methods & resources". 146 | 147 | For Methods, choose GET and for the URI template regex, enter: 148 | 149 | ``` 150 | /planets 151 | ``` 152 | 153 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_apply_access_policy.png) 154 | 155 | Be sure to click "Apply". 156 | 157 | We need to set up one more policy to show how different users get different access. Click **Apply New Policy** and this time use the scope `http://myapp.com/scp/gold` and the resource: 158 | 159 | ``` 160 | /moons 161 | ``` 162 | 163 | ## Set up a Mulesoft Authentication Client 164 | 165 | Any access tokens sent to Mulesoft need to be minted by a client that Mulesoft recognizes. Mulesoft supports dynamic client registration with Okta, which is pretty cool. 166 | 167 | In your Mulesoft Anypoint tenant, click on the three small bars in the top left corner and go to Exchange, where you will see a list of assets. Generally, the quickest way to find your API is to click on your organization name in the left-hand column. 168 | 169 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_assets.png) 170 | 171 | Click on your REST API 172 | 173 | You will see the portal home screen of your API. 174 | 175 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_request_access.png) 176 | 177 | You will now see the *Request API access* screen: 178 | 179 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_request_API_access.png) 180 | 181 | Click the API Instance pull-down and select your API Instance 182 | Click the Application pull-down and select + Create a new application 183 | Enter the following values when prompted: 184 | 185 | Application Name: Solar System Authn 186 | OAuth 2.0 Grant type: Authorization Code Grant 187 | OAuth 2.0 redirect URIs: http://localhost:8080 (or whatever REDIRECT_URI you established at the beginning of the process). 188 | 189 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/mulesoft_create_new_app.png) 190 | 191 | Click **Create** to create your new client. 192 | 193 | You will see the *Request API access* screen. Select your API instance and click **Request access**. 194 | 195 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_req_API_access.png) 196 | 197 | You will see an "Your request has been received and approved." message on your screen, and an additional tab will be opened that shows details and statistics about your application. 198 | 199 | ![alt text](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/new_mulesoft_api_access_successful.png) 200 | 201 | ## Wrapping up 202 | 203 | You're now almost ready to test the end-to-end flow with the sample app. Before jumping back to the instructions for the sample application, there are just a couple of things to take care of: 204 | 205 | * In that last step, you created a new client in Okta via the Mulesoft UI, which, again, is pretty cool. 206 | -- Go to your Okta tenant, find that new client, and assign it to the Everyone group - or at least to the sample users for this app. 207 | -- update the CLIENT_ID and CLIENT_SECRET values in the `.env` file with the client_id and client_secret from the client that you just created via the Mulesoft UI. 208 | 209 | * the Mulesoft Cloudhub URL - this will be the "GATEWAY_URI" value 210 | 211 | ## Testing 212 | 213 | Now that you have set up Mulesoft as an API proxy, you can test out the whole flow. Take note of the Invoke URL, jump back to the main `readme` in this repo, and go to the `Test your application and access tokens` section. 214 | -------------------------------------------------------------------------------- /gateways/swag/readme.md: -------------------------------------------------------------------------------- 1 | # Integrating Okta with Software AG 2 | 3 | Okta can integrate with Software AG in several different ways: 4 | 5 | * End-user authentication (OIDC) 6 | * JWT validation 7 | * OAuth 2 8 | 9 | Software AG's OAuth 2 integration is relatively broad and deep, including capabilities such as dynamic client registration, and creating scopes in Okta via the Software AG UI. Okta is a predefined third-party OAuth 2 provider in Software AG. 10 | 11 | That integration is most likely the integration you would want to use in production, and it is described [here](http://techcommunity.softwareag.com/web/guest/pwiki/-/wiki/Main/Securing+APIs+using+thirdparty+OAuth2+identity+provider+in+API+Gateway). 12 | 13 | If you want to get familiar with the basics of Software AG and Okta, this guide will describe the lighter-weight jwt validation integration. Software AG will be evaluating an access token (jwt) minted by Okta, to see whether the access token is valid before granting access to the requested endpoint. 14 | 15 | >*Note*: in a production environment, it is extremely important that the API itself also check the validity of the access token when it is passed on from Software AG. The API must inspect the access token for scopes (if applicable), and also at minimum check the values in the `exp` and `aud` fields. 16 | 17 | Again, if you are more interested in the full capabilities of the OAuth 2 integration between Software AG and Okta, please see their tutorial: [Securing APIs using thirdparty OAuth2 identity provider in API Gateway](http://techcommunity.softwareag.com/web/guest/pwiki/-/wiki/Main/Securing+APIs+using+thirdparty+OAuth2+identity+provider+in+API+Gateway). 18 | 19 | ## What You'll Build 20 | 21 | At the end of this setup, you'll have an architecture where: 22 | 23 | 1. End-users will be able to authenticate against Okta and receive an access token (via the app) 24 | 2. End-users will have different scopes in their access token, depending on their group assignments 25 | 3. The application will send the access token to the Software AG Gateway 26 | 4. Software AG will check the structural validity and signature of the access token 27 | 5. If the token is valid, Software AG will send the request on to the API 28 | 6. The API must also check the token for validity, and determine whether it has the appropriate scopes for the requested endpoint 29 | 7. The API will send the data payload to the gateway, which will send it on to the application 30 | 31 | Please note that step 6 is not actually shown in the code or in the demo, but it's something that should be applied in production. 32 | 33 | ## Prerequisites for integrating Okta + Software AG API Gateway 34 | 35 | 1. **An Okta account.** If you don't already have one, you can get a free-forever account at [developer.okta.com](https://developer.okta.com/signup/) 36 | 2. **A Software AG account.** If you don't already have a Software AG account, you can get a free trial [here](https://www.softwareag.com/corporate/products/downloads/free_downloads/default.html‎). 37 | 38 | ### Step-by-step 39 | The high-level process we are going to follow is: 40 | 41 | 1. Set up your API in Software AG 42 | * key outputs: PROXY_URI / Audience 43 | 2. Set up your Okta tenant 44 | * key outputs: OKTA_AZ_SERVER_ISSUER 45 | 3. Set up Okta as a JWT provider in your Software AG tenant 46 | 5. Set up and launch your application 47 | 48 | In the last step, we'll launch a sample application that will show the end-to-end flow. This sample application requires a few settings - environment variables - to launch. To manage these environment variables, the application uses the [dotenv npm package](https://www.npmjs.com/package/dotenv). There is an example .env file in the repo called `.env_example`. Copy the `.env_example` file now to a file called `.env`. 49 | 50 | This is what the .env_example file looks like: 51 | 52 | ``` 53 | # Okta settings 54 | 55 | # example: https://dev-511902.oktapreview.com 56 | OKTA_TENANT="" 57 | 58 | OKTA_API_TOKEN="" 59 | AUTHN_CLIENT_ID="" 60 | AUTHN_CLIENT_SECRET="" 61 | 62 | # example: https://dev-511902.oktapreview.com/oauth2/ausfqw42xrkmpfDHI0h7 63 | OKTA_AZ_SERVER_ISSUER="" 64 | 65 | # Gateway/Proxy base url 66 | # example: http://52.14.100.89:8080/solar-system 67 | PROXY_URI="" 68 | 69 | # App settings 70 | PORT="8080" 71 | REDIRECT_URI="http://localhost:8080" 72 | SILVER_USERNAME="" 73 | SILVER_PASSWORD="" 74 | GOLD_USERNAME="" 75 | GOLD_PASSWORD="" 76 | SESSION_SECRET="some random phrase" 77 | SESSION_MAX_AGE=60000 78 | 79 | # Supported values: aws, kong, mulesoft, swag, tyk 80 | # swag = Software AG 81 | GATEWAY="" 82 | ``` 83 | 84 | There are a couple of values you should fill in now, such as `OKTA_TENANT` and `GATEWAY`. I will point out when we generate the other values along the way; you can either enter them in your `.env` file as you go, or do it all at the end. There is a helper script that will gather the settings for you at the end. 85 | 86 | ## Configure Software AG 87 | 88 | ### API details 89 | 90 | Go to your Software AG webMethods API Gateway console 91 | 92 | Click *APIs* 93 | 94 | Click **Create APIs** 95 | 96 | Choose *Create API from scratch*, then **Create** 97 | 98 | In the API details screen, enter: 99 | 100 | *Name*: solar-system 101 | 102 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_api_details.png) 103 | 104 | Click *Continue to provide Technical information for this API* 105 | 106 | For the *Protocol* choices, select *HTTPS* 107 | 108 | In the *Host* field, enter the value for the Okta solar system API: 109 | 110 | `okta-solar-system.herokuapp.com` 111 | 112 | >*Note*: don't put the protocol in the host field 113 | 114 | and 115 | 116 | *Base path*: `/` 117 | 118 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_api_tech_information.png) 119 | 120 | Then, click *Continue to provide Resource & Methods for this API* 121 | 122 | We are going to add two resources to this API: `/planets` and `/moons` 123 | 124 | *Resource name*: Planets 125 | *Resource path*: /planets 126 | *Supported methods*: GET 127 | 128 | Click **Add** 129 | 130 | Click the **Add Resources** button to add the `/moons` resource: 131 | 132 | *Resource name*: Moons 133 | *Resource path*: /moons 134 | *Supported methods*: GET 135 | 136 | Click **Add** 137 | 138 | Now, scroll to the bottom of the page and click 139 | 140 | *Continue to provide Mocking information for this API* 141 | 142 | You'll see a screen that says "API mocking is not enabled". 143 | 144 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_api_mocking_enabled.png) 145 | 146 | Click the **Save** button to save your API. 147 | 148 | Now click the **Activate** button to activate your API. 149 | 150 | Click **Yes** on the "are you sure?" prompt. 151 | 152 | You now have a Gateway endpoint for your API. 153 | 154 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_api_gateway_endpoint.png) 155 | 156 | Enter the value of your Gateway endpoint in your `.env` file as the `PROXY_URI` value. 157 | 158 | ### Scopes 159 | 160 | Software AG does not check for scopes in access tokens, so we're going to skip the Scopes section and move straight to Policies. 161 | 162 | ### Policies 163 | 164 | Click on the *Policies* tab 165 | 166 | If necessary, click **Deactivate** 167 | 168 | Click **Edit** 169 | 170 | Click *Identify & Access*, then *Inbound Authentication - Transport* 171 | 172 | In the menu that pops up in the right-hand column, check the box for *JWT Authentication* 173 | 174 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_add_jwt_auth.png) 175 | 176 | Click **Save** 177 | 178 | That finishes setting up the Software AG API for the moment. Now we need to set up our Okta tenant, and then we'll come back to Software AG to add Okta as a JWT provider. 179 | 180 | ## Set up your Okta tenant 181 | 182 | To properly demonstrate OAuth as a Service, you need a number of elements in your Okta tenant: a client, users, groups, an authorization server, scopes, policies, and rules. And, you need to establish the proper relationships among them. 183 | 184 | You have a couple of options to set these up: 185 | 186 | * You can use the Okta bootstrap tool. The Okta bootstrap tool is a "labs" type project. It is the fastest and easiest way to get your tenant set up. Instructions are [here](../../okta_setup/okta_setup_bootstrap.md). 187 | * You can set up your Okta tenant "manually", with Okta's easy-to-use admin UI. Instructions are available [here](../../okta_setup/okta_setup_manual.md). 188 | 189 | Go ahead and set up your Okta tenant, then come back to these instructions. 190 | 191 | ### Get your `issuer` value 192 | 193 | If you used the Okta bootstrap tool to set up your Okta tenant, you can run a helper script to get you the settings you'll need the rest of the way: 194 | 195 | ```bash 196 | node get_settings.js --swag 197 | ``` 198 | 199 | This will output some values to the screen. For the next step in our set-up, we'll need the following values: 200 | 201 | * `ISSUER` 202 | * `JWKS_URI` 203 | * `AUDIENCE` 204 | 205 | ## Add Okta as JWT Issuer to Software AG 206 | 207 | Now that you've set up your Okta tenant with an authorization server, we can set up your Software AG tenant with Okta as a recognized JWT issuer. 208 | 209 | Go to the Administration section of Software AG. 210 | 211 | Click on the *Security* tab. 212 | 213 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_add_jwt.png) 214 | 215 | In the left-hand column, click on *JWT*. 216 | 217 | In the *External JWT configuration* section, click **Add issuer** 218 | 219 | In the *Issuer* field, enter your value for `ISSUER` 220 | 221 | In the JWKS URI field, enter your value for `JWKS_URI` 222 | 223 | In the Audience field, enter your value for `AUDIENCE` 224 | 225 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/swag/swag_external_jwt_configuration.png) 226 | 227 | Click **Save** to save the configuration. 228 | 229 | That completes setting up Okta as an authorizer for your API. Now we can launch the sample application to test. 230 | 231 | ## Get the app settings 232 | 233 | If you used the bootstrap tool for setup, and you haven't run the helper script yet to extract the relevant settings, go ahead and run it now: 234 | 235 | ```bash 236 | node get_settings.js --swag 237 | ``` 238 | 239 | The script will display the settings on the screen, and also save them to an output file so that you can refer to them later if you need to. 240 | 241 | Take these settings and update your `.env` file with any values that still need to be added. 242 | >Note: you don't need to copy every setting from the output, but it's no harm if you do. 243 | 244 | If you did not user the bootstrap tool for setup, refer to your Okta tenant for the appropriate values to enter into the `.env` file. 245 | 246 | ## Launch the app 247 | 248 | You can now launch your app: 249 | 250 | ```bash 251 | node app.js 252 | ``` 253 | 254 | When you load the web app, first try clicking on the "show me the planets" and/or the "show me the moons" buttons. You'll get an error from the API Gateway. 255 | 256 | Next, try authenticating as one of the users. You'll get an id token and an access token displayed in the browser (in a production environment, you would not do this). The raw tokens are also available in the console if you want to check them out. 257 | 258 | Now that the user has a token (actually the token is sitting on the server), you can click on one of the "show me" buttons again to see if you get the requested resource. 259 | 260 | Enjoy the solar system! 261 | 262 | ---------------- -------------------------------------------------------------------------------- /gateways/tyk/readme.md: -------------------------------------------------------------------------------- 1 | # Integration guide: Okta + Tyk 2 | 3 | Okta integrates with Tyk in several different ways: 4 | 5 | * Dashboard SSO 6 | * Developer Portal SSO 7 | * API Authentication 8 | ** OIDC - Open ID Connect 9 | ** JWT with scope claims 10 | 11 | This guide will describe the API Access Management integration in detail, but we will briefly touch on the Admin SSO integration and the OIDC integration. 12 | 13 | ### Admin SSO 14 | 15 | Tyk supports SSO to the admin dashboard and developer portal via OIDC. Instructions are here: [https://tyk.io/docs/integrate/sso/dashboard-login-okta-tib/](https://tyk.io/docs/integrate/sso/dashboard-login-okta-tib/) 16 | 17 | Note: you must install [Tyk Identity Broker](https://tyk.io/docs/integrate/sso/dashboard-login-ldap-tib/) as part of this process 18 | 19 | ### OIDC 20 | 21 | Tyk can enforce a policy that requires a valid OIDC ID Token in order to access an endpoint. Set up Okta as an OIDC provider and Tyk will check for a valid id token before passing on the request to an endpoint. 22 | 23 | Instructions are here: [https://tyk.io/docs/basic-config-and-security/security/authentication-authorization/openid-connect/](https://tyk.io/docs/basic-config-and-security/security/authentication-authorization/openid-connect/) 24 | 25 | ## API Access Management 26 | 27 | Tyk supports the evaluation of JSON web tokens (JWTs) to control access to endpoints. 28 | 29 | Before going in to the step-by-step process to enable this capability, it’s important to highlight an optional Tyk feature in regards to JWTs, such as OAuth Access Tokens or OIDC ID tokens, which is different from many other API gateways. 30 | 31 | A JWT passed to Tyk can include a “policy id” claim. This policy ID tells Tyk which Tyk policy is valid for that JWT. Alternatively, Tyk can extract scopes from the claims and apply policies based on them. Tyk will use this policy to determine if a JWT has access to the API it is attempting to access. 32 | 33 | So, in using Okta with Tyk, you can populate the policy id in a JWT in two primary ways, depending on your needs and your setup. This is just an overview for now, we'll go through the step-by-step a little later on: 34 | 35 | 1. In the user profile (i.e. user-level): create a custom attribute in the Okta user profile using the Okta Profile editor. This custom attribute must have the same name as the policy id field name in Tyk. Set up a custom claim in your Okta authorization server to always include this claim from the user profile. 36 | 37 | 2. In an application profile (i.e. group-level): go to the Okta Profile editor and create a custom attribute for the OIDC application that your users are authenticating against. Again, this custom attribute must have the same name as the policy id field name in Tyk. Set up a custom claim in your Okta authorization server to always include this claim from the application profile. Now, when you assign this application to groups in Okta, you can choose different policy IDs for different groups, and then end-users will inherit these policy ids when they are assigned to that group/application. 38 | 39 | ## What You'll Build 40 | 41 | At the end of this setup, you'll have an architecture where: 42 | 43 | 1. Users will be able to authenticate against Okta and receive an access token (via the app) 44 | 2. Users will have a "policy id" claim in their access token. The value of this claim will be derived from the user's group membership in Okta, and the policy id will map to a policy id in Tyk.` 45 | 3. The application will send the access token to the Tyk. 46 | 4. Tyk will check the validity of the access token locally. 47 | 5. If the token and scopes are valid, Tyk will send the request on to the API 48 | 6. The API will send the data payload to the gateway, which will send it on to the application 49 | 50 | 51 | ## Prerequisites for integrating Okta + Tyk 52 | 53 | 1. **An Okta account.** If you don't already have one, you can get a free-forever account at [developer.okta.com](https://developer.okta.com/signup/) 54 | 2. **Tyk** If you don't already have a Tyk tenant set up, you can create a forever free developer account on Tyk SaaS [here](https://tyk.io/api-gateway/saas/‎) or use [docker-compose to launch an on-prem stack](https://github.com/TykTechnologies/tyk-pro-docker-demo). 55 | 56 | ### Step-by-step 57 | The high-level process we are going to follow is: 58 | 59 | 1. Set up your API in Tyk 60 | 2. Set up your Okta tenant 61 | 3. Add your JWKS to Tyk 62 | 4. Set up and launch your application 63 | 64 | In the last step, we'll launch the sample application that will show the end-to-end flow. This sample application requires a few settings - environment variables - to launch. To manage these environment variables, the application uses the [dotenv npm package](https://www.npmjs.com/package/dotenv). There is an example .env file in the repo called `.env_example`. Copy the `.env_example` file now to a file called `.env`. 65 | 66 | This is what the .env_example file looks like: 67 | 68 | ``` 69 | # Okta settings 70 | 71 | # example: https://dev-511902.oktapreview.com 72 | OKTA_TENANT="" 73 | 74 | OKTA_API_TOKEN="" 75 | AUTHN_CLIENT_ID="" 76 | AUTHN_CLIENT_SECRET="" 77 | 78 | # example: https://dev-511902.oktapreview.com/oauth2/ausfqw42xrkmpfDHI0h7 79 | OKTA_AZ_SERVER_ISSUER="" 80 | 81 | # Gateway/Proxy base url 82 | # example: http://52.14.100.89:8080/solar-system 83 | PROXY_URI="" 84 | 85 | # App settings 86 | PORT="8080" 87 | REDIRECT_URI="http://localhost:8080" 88 | SILVER_USERNAME="" 89 | GOLD_USERNAME="" 90 | FAKE_USER_PASSWORD="" 91 | SESSION_SECRET="some random phrase" 92 | SESSION_MAX_AGE=60000 93 | 94 | # Supported values: aws, kong, mulesoft, swag, tyk 95 | GATEWAY="" 96 | ``` 97 | 98 | There are a couple of values you can fill in now, such as `OKTA_TENANT` and `GATEWAY`. I will point out when we generate the other values along the way; you can either enter them in your `.env` file as you go, or do it all at the end. 99 | 100 | ### Set up your API in Tyk 101 | Go to the Tyk dashboard and click on the APIs section. 102 | 103 | Click the **+ Add New API** button. 104 | 105 | In the API designer, for API Name, enter `solar-system` 106 | 107 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_API_name.png) 108 | 109 | scroll down, and in the **Target URL** field, enter: 110 | 111 | `https://okta-solar-system.herokuapp.com` 112 | 113 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_target_url.png) 114 | 115 | Leave the Authentication section as-is for right now; we'll come back to it later. 116 | 117 | Click **Save** to save your new API. 118 | 119 | At the top of your API home screen you'll now have an API URL. Copy this value and save it for later, it will be the basis of the PROXY_URI we will use when we set up the application. Note: Tyk by default listens on port 8080 for API calls, so your PROXY_URI will be something like this: 120 | 121 | http://52.14.100.89:8080/solar-system 122 | 123 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_api_url.png) 124 | 125 | ### Set up policies 126 | We're going to set up two policies in Tyk. 127 | 128 | One policy will control access to the /planets resource (which we will create) and the other will control access to the /moons resource (which we will also create). 129 | 130 | Click **Policies** to go to the Policies section. 131 | 132 | Click the **+ Add Policy** button. 133 | 134 | In the *Policy Name* field, enter 135 | 136 | `silver - access to /planets` 137 | 138 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_silver_policy.png) 139 | 140 | In the *Access Rights* section, go to the *Add access rule* dropdown and select 141 | 142 | `SOLAR-SYSTEM: DEFAULT` 143 | 144 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_access_rights.png) 145 | 146 | Now, under the *Path-based permissions* section, click **+ Add Path** 147 | 148 | In the *URL* field, enter 149 | 150 | `/planets` 151 | 152 | and in the *Allowed methods* field, choose 153 | 154 | `GET` 155 | 156 | Click the gray **Add** button next to the GET method. 157 | 158 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_path_permissions.png) 159 | 160 | Click the green **Add** button to add the path. 161 | 162 | >**IMPORTANT**: in the *Trial period* section, set the *ExpiresAfter* value to "Do not expire key". This essentially tells Tyk that we want to use the session length in the access token (jwt) rather than the internal token that Tyk generates. 163 | 164 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_do_not_expire_key.png) 165 | 166 | Click **Create** to create this policy. 167 | 168 | You will now have a Policy ID for this policy. Copy it so you can use it later. (We don't need this value in the .env file.) 169 | 170 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/tyk/tyk_silver_access.png) 171 | 172 | If you want to follow along fully with the sample application, create another policy, using the same steps, with a couple of exceptions: 173 | 174 | * In the *Name* field, enter 175 | 176 | `gold - access to /moons` 177 | 178 | * and in the *URL* field add *both* 179 | `/planets` 180 | 181 | and 182 | 183 | `/moons` 184 | 185 | (and use the GET method for /moons as well) 186 | 187 | Don't forget to set the *ExpiresAfter* value to "Do not expire key", and after you click **Create**, copy the Policy ID. 188 | 189 | That's it for now for Tyk. We're going to come back to Tyk later to set up Okta as a jwt provider. But, now that we have our policy IDs, we can set up our Okta tenant. 190 | 191 | ### Set up your Okta Tenant 192 | 193 | #### Add an OIDC application 194 | 195 | Applications->Add Application->Web->Next 196 | 197 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_create_new_application.png) 198 | 199 | Use the following settings for your application: 200 | 201 | *Name*: solar system client app 202 | 203 | *Base URIs*: http://localhost:8080 (leave as-is) 204 | 205 | *Login redirect URIs*: http://localhost:8080 (important!) 206 | If you plan on using a different home page for the application, enter the url here. For this integration, we'll set up an application that assumes your application lives at http://localhost:8080 207 | 208 | *Group Assignments*: None (remove the "Everyone" group) 209 | 210 | *Grant Type Allowed*: Authorization code 211 | 212 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_oidc_app_settings.png) 213 | 214 | Click **Done** to save your application. 215 | 216 | You will now have a client id and client secret. In your `.env` file, these are: 217 | 218 | * AUTHN_CLIENT_ID 219 | * AUTHN_CLIENT_SECRET 220 | 221 | #### Add a custom attribute to the Okta user profile 222 | 223 | We need to add a custom attribute to the user profile to store the Tyk policy_id. 224 | 225 | Users->Profile Editor 226 | 227 | Click the **Profile** button next to the application that you just created. 228 | 229 | Click **Add Attribute** 230 | 231 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_profile_editor_add_attribute.png) 232 | 233 | On the *Add Attribute* screen, enter the following values: 234 | 235 | *Display name*: Tyk policy id 236 | 237 | *Variable name*: pol 238 | 239 | Leave the rest of the settings as-is. 240 | 241 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_attribute.png) 242 | 243 | Click **Save**. 244 | 245 | #### Add groups 246 | 247 | We're going to create two groups in Okta to store users with different authorizations. 248 | 249 | Users->Groups->Add Group 250 | 251 | enter the name 252 | 253 | `silver subscribers` 254 | 255 | for the *name* and *description* 256 | 257 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_group.png) 258 | 259 | Click **Add Group** to create the group. 260 | 261 | Now click on the group name to open the group properties page. 262 | 263 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_group_properties.png) 264 | 265 | Click **Manage Apps** and find your solar system client application. 266 | 267 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_assign_application.png) 268 | 269 | Click *Assign*, and you will be prompted to add the Tyk policy id to this group. 270 | 271 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_custom_group_attrib.png) 272 | 273 | Add the "silver" Tyk Policy ID that you created earlier, and click **Save and Go Back**. 274 | 275 | Click **Done**. 276 | 277 | Now, create a group for the gold subscribers, following the same steps as above, but of course add the gold policy id that you created in Tyk. 278 | 279 | #### Create users 280 | 281 | Now we can add a sample user to the silver group and another user to the gold group. When these users authenticate, they will get different policy ids in their access token. 282 | 283 | Users->People->Add Person 284 | 285 | You can use whatever values you want for first name, last name, etc. 286 | 287 | *Groups*: add the user to the silver group 288 | 289 | Since this is a proof-of-concept, we're going to change the *Password* option to 290 | 291 | `Set by Admin` 292 | 293 | and we're going to de-select the box "User must change password on first login" 294 | 295 | >*Note*: the first time this user logs in, they will be prompted to set up a "forgot password" question. It's just one screen, it only happens once, and the overall flow continues as normal. 296 | 297 | Of course, choose a password that you'll remember for demo purposes. 298 | 299 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_user.png) 300 | 301 | In your .env file, the username and password that you've just created correspond to the 302 | 303 | SILVER_USERNAME 304 | and 305 | SILVER_PASSWORD 306 | 307 | fields. These fields are optional, just for UI convenience. 308 | 309 | Click **Save and Add Another**, and follow the same steps to add a sample Gold user. 310 | 311 | #### Set up the authorization server 312 | 313 | Now we have sample users, sample groups, and a custom user attribute that stores the Tyk policy id based on a user's group membership. 314 | 315 | Now we need to tell the authorization server to include the policy id claim in the access token. 316 | 317 | API->Authorization Servers->Default 318 | 319 | While you're on this screen, take note of the `Issuer URI` of your default authorization server. This corresponds to the 320 | 321 | OKTA_AZ_SERVER_ISSUER 322 | 323 | value in your `.env` file. 324 | 325 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_authorization_servers.png) 326 | 327 | First we're going to add a custom scope. 328 | 329 | Scopes->Add Scope 330 | 331 | *Name*: pol 332 | *Description*: Tyk policy 333 | *Default scope*: yes 334 | 335 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_scope.png) 336 | 337 | Click **Create** to create this scope. 338 | 339 | Now we're going to add a claim. 340 | 341 | Click on the *Claims* tab, then **Add Claim** 342 | 343 | *Name*: pol 344 | *Mapping*: appuser.pol 345 | 346 | Leave the other settings as-is 347 | 348 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_claim.png) 349 | 350 | Click **Save**. 351 | 352 | We need to have at least one access policy in order for the authorization server to work, so we're going to set up a default policy that is open. Obviously, this is for demo purposes only; in a production environment you would lock down your policies to least privilege. 353 | 354 | Click on the *Access Policies* tab, then **Add Policy** 355 | 356 | *Name*: default 357 | *Description*: default policy 358 | 359 | Leave assigned to all clients (again, this is something you would change for prod) 360 | 361 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_policy.png) 362 | 363 | Click **Create Policy**. 364 | 365 | Now we just need to add a rule to our policy to make it active. 366 | 367 | Click **Add Rule** 368 | 369 | *Rule Name*: default 370 | 371 | You can leave all of the other settings as-is for demo purposes. 372 | 373 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_add_rule.png) 374 | 375 | Click **Create Rule**. 376 | 377 | Now we can test to see if we're going to get that custom claim in the access token. 378 | 379 | Click on *Token Preview* 380 | 381 | *OAuth/OIDC client*: `solar system client app` 382 | 383 | *Grant type*: Authorization Code 384 | 385 | *User*: {{your silver user name}} 386 | 387 | *Scopes*: pol 388 | 389 | Then click **Preview Token** to see what the access token for this user will look like. You should see the correct Tyk policy ID in the `pol` claim for your user. 390 | 391 | 392 | ![](https://s3.us-east-2.amazonaws.com/tom-smith-okta-api-center-images/okta/okta_token_preview.png) 393 | 394 | Next, we're going to add your Okta authorization server as a jwt provider for your Tyk API instance. We're going to need the JSON Web Key Set (JWKS) from your authorization server, so while you're in your authorization server: 395 | 396 | Click *Settings*, then click on the Metadata URI. You'll get a list of settings. Click on the jwks_uri, and you'll see something like this: 397 | 398 | ``` 399 | {"keys":[{"alg":"RS256","e":"AQAB","n":"zGLom7s1dsiYQwo-ckNKUt6c1eEeqT-yvHc4a-3Hg1hbNUKhzFA42Yadzzlr-TobSrkjgtzUfxd3U7LiiKyXheFfmW5MGZlSrJ-SWk1ZfU_TY0BjnFY3_yxnppG8IYEh66xgXqz25d0adwUDweskSq4Z_YVJoZArHXKaXHdr00tar3LRpWyTldQyhQsQNFMjEE_F4ER83xJPKyr3HxRjz_mkMysGndBQHiXTi-kGNzOKVz3KRqMZjhG_h0ShctwzK2ox3n6giq2sRQJGN94PB2K88vHgsYhdW-axitpEcrbTL3I-r-zGLfBp3xOciDCZ_8sIyKRgtwo2ZIbYHIK7OQ","kid":"jh0M4QndoJU531l-17x_WGjw88SXxlZu9kdW8IGdpkI","kty":"RSA","use":"sig"}]} 400 | ``` 401 | 402 | You might have one or two keys. Using one of these keys, we need to create a public key (.pem format) for Tyk to use. 403 | 404 | We strongly recommend using the [jwk-to-pem npm library](https://www.npmjs.com/package/jwk-to-pem) to create your .pem. 405 | 406 | Your mileage may vary if you use another library. 407 | 408 | #### Add Okta as a jwt provider for your Tyk API 409 | 410 | Go to your API and scroll to the “Authentication” section. 411 | 412 | *Authentication mode*: JSON Web Token (JWT) 413 | *JWT Signing method*: RSA public Key 414 | *Public Key*: your .pem file 415 | *Identity Source*: sub (note that you need to actually key this in) 416 | *Policy Field name*: pol (note that you need to actually key this in) 417 | 418 | ![](https://lh4.googleusercontent.com/6WbnCtDgKC9mMQzVLzX98BEWgrzNhIoivo7fJ5XhZSCQ0QvIt2GkFHOQ_b8lOlKLPs_QtpViu2rzwqb-tcKb8KpOmK7w2nVJ2iHpPPWtUIEf9KqMtCFptOh3LZj8SYXfm4d2zziO) 419 | 420 | Click **Update** to update your API. 421 | 422 | Now, we have our Okta tenant set up, and the Tyk API Gateway is set up to accept jwts from Okta. We just need an application to coordinate the flow among the end-user, Okta, and Tyk. 423 | 424 | ### Setting up the application 425 | 426 | At this point, if you haven't been updating your `.env` file as you've gone through these instructions, it's time to update the file now. 427 | 428 | This is the file, with fields indicated as to whether they are required for the app: 429 | 430 | ``` 431 | # Okta settings 432 | 433 | # example: https://dev-511902.oktapreview.com 434 | OKTA_TENANT="" # required 435 | 436 | OKTA_API_TOKEN="" # not necessary 437 | AUTHN_CLIENT_ID="" # required 438 | AUTHN_CLIENT_SECRET="" # required 439 | 440 | # example: https://dev-511902.oktapreview.com/oauth2/default 441 | OKTA_AZ_SERVER_ISSUER="" # required 442 | 443 | # Gateway/Proxy base url 444 | # example: http://52.14.100.89:8080/solar-system 445 | PROXY_URI="" # required 446 | 447 | # App settings 448 | PORT="8080" # required 449 | REDIRECT_URI="http://localhost:8080" # required 450 | SILVER_USERNAME="" # optional 451 | SILVER_PASSWORD="" # optional 452 | GOLD_USERNAME="" # optional 453 | GOLD_PASSWORD="" # optional 454 | SESSION_SECRET="some random phrase" # required 455 | SESSION_MAX_AGE=60000 # required 456 | 457 | # Supported values: kong, mulesoft, tyk 458 | GATEWAY="" # required 459 | ``` 460 | 461 | Refer to the instructions above if you can't find a value. 462 | 463 | If you haven't already installed the Node application, go ahead and install: 464 | 465 | ``` 466 | npm install 467 | ``` 468 | 469 | Now you can launch the application: 470 | 471 | ``` 472 | node app.js 473 | ``` 474 | 475 | When you load the web app, first try clicking on the "show me the planets" and/or the "show me the moons" buttons. You'll get an error notifying you that you need an access token, or that the request is forbidden. 476 | 477 | Next, try authenticating as one of the users. You'll get an id token and an access token displayed in the browser (in a production environment, you would not do this). The raw tokens are also available in the console if you want to check them out. 478 | 479 | Now that the user has a token (actually the token is sitting on the server), you can click on one of the "show me" buttons again to see if you get the requested resource. 480 | -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Okta API Center 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 118 | 119 | 213 | 214 | 215 | 216 | 217 |
218 | 219 | 220 | 242 | 243 |
244 |
245 |
246 | 247 |

The currently logged-in Okta user is:

248 | 249 |

The gateway is:

250 | 251 | 277 | 278 |
279 |
280 | SILVER Access: A list of the planets 281 |
282 |
283 |
284 |
285 | 286 |
287 | 288 |
289 | 290 | proxy endpoint: {{GATEWAY_URI}}/planets 291 | 292 |
293 | 294 |
295 | 296 |
297 |
298 |

Planets

299 |
300 |
301 |
302 |
303 |
304 | 305 |
306 |
307 | GOLD Access: A list of (selected) moons 308 |
309 |
310 |
311 | 312 |
313 | 314 |
315 |
316 | proxy endpoint: {{GATEWAY_URI}}/moons 317 | 318 |
319 | 320 |
321 | 322 |
323 |
324 |

Moons

325 |
326 |
327 |
328 | 329 |
330 |
331 |
332 | 333 |
334 | 335 |
336 |
The OAuth flow
337 | 338 |
339 |
    340 |
  • The user is authenticating using the authorization code grant type.
  • 341 |
  • After authentication, you can see the authorization code in the address bar, and it's also in the developer console.
  • 342 |
  • The access token and id token are availabile in the console. These would not typically be sent to the browser in an authorization code flow, unless you're using PKCE.
  • 343 |
  • They are shown here for demo purposes.
  • 344 |
345 |
346 | 347 |
348 |
Access token, decoded:
349 |
[none]
350 |
351 | 352 |
353 |
ID token, decoded:
354 |
[none]
355 |
356 | 357 |
358 |
359 |
360 | 361 |
362 | 363 | -------------------------------------------------------------------------------- /okta.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Okta API Center", 3 | "description": "Tools and docs to integrate Okta with API Gateways", 4 | "url": "https://okta-api-am.herokuapp.com", 5 | "categories": [ 6 | "authentication", 7 | "authorization", 8 | "api-authentication" 9 | ] 10 | } -------------------------------------------------------------------------------- /okta_setup_manual.md: -------------------------------------------------------------------------------- 1 | # Setting up your Okta tenant for the Solar System sample application 2 | 3 | These instructions are specific to the "solar system" use-case described above, but after completing the setup, hopefully you will see how it can be applied to your own use-case. 4 | 5 | ## Prerequisites 6 | 7 | * An Okta tenant. If you don't already have an Okta tenant, you can sign up for a free-forever [Okta developer edition](https://developer.okta.com/). 8 | 9 | > Note: These instructions assume that you are using the developer edition of Okta. If you are using the Enterprise version, some of the menus may be a little different. 10 | 11 | > Note: Also, we’re going to use the default authorization server that is built in to the developer edition. This is what the default authorization server looks like on the Okta API screen: 12 | 13 | ![](https://tom-smith-okta-api-center-images.s3.us-east-2.amazonaws.com/default_authorization_server.png) 14 | 15 | If you don't have a default authorization server, you can [set one up](https://developer.okta.com/docs/guides/customize-authz-server/create-authz-server/). 16 | 17 | ## Outputs 18 | 19 | At the end of this setup, you will have the following values, which will be needed to set up the test application and the API gateway: 20 | 21 | client_id 22 | 23 | client_secret 24 | 25 | ## Setup 26 | 27 | ### Create an OIDC Application 28 | 29 | 1. Click “Applications” and then “Add Application”. 30 | 2. Choose “Web”, then Next. 31 | 3. The following login redirect URI is created for you by default: 32 | `http://localhost:8080/authorization-code/callback` 33 | 4. Add another login redirect URI: 34 | `http://localhost:8080` 35 | 5. Leave all of the other default settings as-is. Click Done. 36 | 37 | > You've created an OIDC client in your Okta tenant. Take note of your `Client ID` and `Client secret`, because we'll need those later. 38 | 39 | > Note: the developer edition assigns new OIDC applications to the Everyone group by default. If you're not using the developer edition, take a moment to assign your new application to the Everyone group. 40 | 41 | ### Create Groups 42 | 43 | Create one group that will contain silver-level subscribers, and another group that will contain gold-level subscribers. 44 | 45 | 1. Set up a group: Directory->Groups->Add Group 46 | 2. Name the group “silver subscribers”; you can use the same for the description 47 | 3. Click Add Group 48 | 49 | > Repeat the same steps for the "gold subscribers" group. 50 | 51 | ### Create Users 52 | 53 | Create one user who is a member of the silver subscribers group, and another user who is a member of the gold subscribers group. 54 | 55 | 1. Add a user: Users->People->Add Person 56 | 57 | | Field | Value | 58 | | :--- | :--- | 59 | | First name: | Carl | 60 | | Last name: | Sagan | 61 | | Username: | carl.sagan@mailinator.com | 62 | | Primary email: | carl.sagan@mailinator.com | 63 | | Secondary email: | {{your email}} | 64 | | Groups: | silver subscribers | 65 | | Password: | you can choose to either set the user's password now (set by admin) or send the user an activation email. The activation email will go to both the primary and secondary email addresses. | 66 | 67 | 2. Add another user: Users->People->Add Person 68 | 69 | | Field | Value | 70 | | :--- | :--- | 71 | | First name: | Jodie | 72 | | Last name: | Foster | 73 | | Username: | jodie.foster@mailinator.com | 74 | | Primary email: | jodie.foster@mailinator.com | 75 | | Secondary email: | {{your email}} | 76 | | Groups: | gold subscribers | 77 | | Password: | you can choose to either set the user's password now (set by admin) or send the user an activation email. The activation email will go to both the primary and secondary email addresses. | 78 | 79 | ### Add a CORS Trusted Origin 80 | 81 | You need to add a CORS Trusted Origin for http://localhost:8080 if you don't already have one. 82 | 83 | 1. Security->API 84 | 2. Click Trusted Origins 85 | 3. Click Add Origin 86 | 4. On the Add Origin Screen, give a name such as "Solar" and add http://localhost:8080 as the Origin URL 87 | 5. Check the boxes for CORS and Redirect 88 | 6. Click Save 89 | 90 | ### Add Custom Scopes 91 | 92 | Create custom scopes in your authorization server to represent "gold" privileges and "silver" privileges. 93 | 94 | >Note: we are going to structure scopes as URLs per [API best practices](https://developer.okta.com/docs/concepts/api-access-management). 95 | 96 | 1. API->Authorization Servers->default 97 | 2. Click the Scopes tab 98 | 3. Click Add Scope 99 | | Field | Value | 100 | | :--- | :--- | 101 | | Name: | http://myapp.com/scp/silver | 102 | | Description: | silver scope | 103 | | Default scope: | [non checked] | 104 | | Metadata: | [checked] | 105 | 106 | 4. Click Create 107 | 108 | > Repeat the same steps for the "gold" scope, using `http://myapp.com/scp/gold` as the name. 109 | 110 | ### Add an Authorization Policy 111 | 112 | > IMPORTANT: By default, the authorization server has a Default Policy that honors all requests for all scopes. This is great for development and troubleshooting, but to test that users are being accurately denied access to certain scopes, you need to make the Default Policy inactive. 113 | 114 | Create an authorization policy that will govern when scopes are granted. 115 | 116 | 1. API->Authorization Servers->default 117 | 2. Click the Access Policies tab 118 | 3. Click Add New Access Policy 119 | | Field | Value | 120 | | :--- | :--- | 121 | | Name: | Solar system API access | 122 | | Description: | Solar system API access | 123 | | Assign to: | My Web App (also OK to leave assigned to `All clients` for demo purposes) | 124 | 4. Click Create Policy 125 | 126 | ### Add Rules 127 | 128 | Add rules to your policy. 129 | 130 | 1. In your policy, click the Add Rule button 131 | 132 | | Field | Value | 133 | | :--- | :--- | 134 | | Rule Name: | silver access to solar system API | 135 | | Grant Type: | Authorization Code (also OK to leave all selected for demo purposes) | 136 | | User is: | Assigned the app and a member of the following: 137 | |   | Groups: silver subscribers 138 | | Scopes requested: | Select "The following scopes:" | 139 | |   | Click "OIDC default scopes" to populate the OIDC default scopes | 140 | |   | Then add following scopes: "http://myapp.com/scp/silver" | 141 | 142 | 2. Click Create Rule 143 | 144 | Now the gold access rule. Note that we are adding both silver *and* gold scopes to the gold subscribers group. 145 | 146 | 1. In your policy, click the Add Rule button 147 | 148 | | Field | Value | 149 | | :--- | :--- | 150 | | Rule Name: | gold access to solar system API | 151 | | Grant Type: | Authorization Code (also OK to leave all selected for demo purposes) | 152 | | User is: | Assigned the app and a member of the following: | 153 | |   | Groups: gold subscribers | 154 | | Scopes requested: | Select "The following scopes:" | 155 | |   | Click "OIDC default scopes" to populate the OIDC default scopes | 156 | |   | Then add following scopes: | 157 | |   | http://myapp.com/scp/gold | 158 | |   | http://myapp.com/scp/silver | 159 | 160 | 2. Click Create Rule 161 | 162 | ### What we've done 163 | 164 | Your authorization server is now set up so that when an application asks for an access token on behalf of a user: 165 | 166 | * if the user is a member of the _silver subscribers_ group and the application requests the `http://myapp.com/scp/silver` scope, then the authorization server will honor the request and include the `http://myapp.com/scp/silver` scope in the access token. 167 | 168 | * if the user is a member of the _gold subscribers_ group and the application requests the `http://myapp.com/scp/silver` scope *or* the `http://myapp.com/scp/gold` scope, then the authorization server will honor the request and include the requested scope(s) in the access token. 169 | 170 | The application can then send this access token to an API to request resources on behalf of the user. The API (or API gateway) will verify that the access is valid, and ensure that it has the appropriate scope(s) for the resource that is being requested. 171 | 172 | You can now return to the main setup and move to "Set up the test application". 173 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "okta-api-am", 3 | "version": "1.0.0", 4 | "description": "okta integrations with api gateways", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "node app.js" 8 | }, 9 | "engines": { 10 | "node": "6.11.3" 11 | }, 12 | "author": "tom.smith@okta.com", 13 | "dependencies": { 14 | "@okta/jwt-verifier": "^1.0.0", 15 | "body-parser": "^1.19.0", 16 | "dotenv": "^8.2.0", 17 | "express": "^4.17.1", 18 | "express-session": "^1.17.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Okta API Center 2 | 3 | ## Overview 4 | 5 | The Okta API Center gives developers tools to see how easily Okta's API Access Management (OAuth as a Service) capabilities integrate with leading API gateways and application proxies. 6 | 7 | This project includes: 8 | 9 | 1. Instructions for setting up various leading API gateways to use Okta as an authorization server 10 | 2. Instructions for setting up Okta with users, groups, authorization policies, and custom scopes 11 | 3. A sample Node.js application that will allow sample end-users to get access tokens, and pass those access tokens to protected endpoints in your API gateway 12 | 13 | If you want to see what these flows can look like from an end-user perspective, you can check out the [public demo site](https://okta-api-am.herokuapp.com) and [video](https://youtu.be/n8r-9Gpoods). 14 | 15 | Okta is a standards-compliant OAuth 2.0 authorization server and a certified OpenID Provider. 16 | 17 | ## Quick setup 18 | 1. follow the [step-by-step instructions](okta_setup_manual.md) to set up your Okta tenant with all of the objects that you need to generate access tokens with scopes 19 | 2. use the sample application `app.js` to enable sample users to get access tokens (with scopes) from your Okta authorization server 20 | 3. set up your API Gateway to validate access tokens issued by Okta 21 | 4. test your setup by using the sample application to send requests with access tokens to your API gateway. 22 | 23 | ## Prerequisites 24 | 25 | * __An Okta tenant__ - If you don't already have an Okta tenant, you can sign up for a free-forever [Okta developer edition](https://developer.okta.com/). 26 | 27 | * __Node.js__ - the test application for this setup runs on Node. 28 | 29 | * __An API Gateway__ - if you want to test the API gateway piece of this setup, you'll need an API gateway. Okta will work with any gateway that supports an external OAuth provider; a list of gateways that have been proven out follows. 30 | 31 | ## Gateways 32 | 33 | Okta is a standards-compliant OAuth 2.0 authorization server and a certified OpenID Provider, so Okta will work with any API gateway or service that supports an external OAuth provider. As of today (July 2020), we have directly proven out compatibility with the following gateways (and reverse proxies): 34 | 35 | * Amazon API gateway 36 | * Apigee 37 | * Google Cloud Endpoints 38 | * Kong 39 | * Mulesoft 40 | * NGINX 41 | * Software AG 42 | * Tyk 43 | 44 | ## Overview of setup 45 | 46 | The overall setup has the following components: 47 | 48 | 1. Set up your Okta tenant 49 | 2. Set up the sample application (and test it) 50 | 3. Set up your API (a mock API is available) and API Gateway 51 | 4. Test the application -> API gateway connection 52 | 53 | You may find it helpful to read the following overview before jumping in to the setup steps. 54 | 55 | ## Overview of API access management & sample application 56 | 57 | An API access management workflow typically includes the following components: 58 | * An API 59 | * An API gateway 60 | * An application 61 | * An OAuth authorization server 62 | * An identity provider 63 | 64 | And, of course, a use-case to drive the configuration of all of those components. 65 | 66 | This setup uses a simple use-case to illustrate how the overall flow works: 67 | 68 | * You are managing a "solar system" API and a viewing application. 69 | * You want to control access to the API so that only users with a silver-level subscription (scope) get access to a list of the planets, and only users with a gold-level subscription (scope) get access to a (partial) list of the moons. 70 | 71 | With that use-case as context, the detailed setup instructions follow. 72 | 73 | ### Set up your Okta tenant 74 | 75 | To illustrate this use-case, you need to set up a number of different objects (users, groups, clients, policies, etc.) in your Okta tenant. Instructions for setting up your Okta tenant are [here](okta_setup_manual.md). 76 | 77 | After you've set up your Okta tenant, come back here and move on to testing your setup against the test application. 78 | 79 | ### Set up the test application 80 | 81 | The test application allows your end-users to authenticate against your Okta tenant and get an access token (via the authorization code grant flow). The application can then send the access token to protected endpoints on your chosen API Gateway. 82 | 83 | ### Prerequisites for the sample application 84 | 85 | You'll need the following values from setting up your Okta tenant: 86 | 87 | OKTA_TENANT 88 | 89 | example: https://dev-399486.okta.com 90 | 91 | ISSUER 92 | 93 | example: https://dev-399486.okta.com/oauth2/default 94 | 95 | this value will be `{{OKTA_TENANT}}/oauth2/default` unless you've set up a different authorization server in Okta. 96 | 97 | CLIENT_ID 98 | 99 | CLIENT_SECRET 100 | 101 | ### Setup for sample application 102 | 103 | 1. Download this repo: 104 | 105 | `git clone https://github.com/tom-smith-okta/okta-api-center` 106 | 107 | 2. Change to the application directory: 108 | 109 | `cd okta-api-center` 110 | 111 | 3. Install the node modules: 112 | 113 | `npm install` 114 | 115 | 4. This app uses the `dotenv` npm package to manage configuration settings. 116 | 117 | Copy the `.env_example` file to a file called 118 | 119 | `.env` 120 | 121 | Open the `.env` file and update the settings for your environment. If you've followed all of the instructions so far and accepted all of the defaults, then you'll only need to update the following values: 122 | 123 | OKTA_TENANT 124 | 125 | ISSUER 126 | 127 | CLIENT_ID 128 | 129 | CLIENT_SECRET 130 | 131 | If you're using Tyk as your gateway, change GATEWAY_IS_TYK to `true`. 132 | 133 | There is a sample value for `GATEWAY_URI` that you can ignore for now; you'll update that after you set up your API Gateway. 134 | 135 | Save the `.env` file. 136 | 137 | #### Launch and test the application 138 | 139 | With your settings updated in the `.env` file, go ahead and launch the application: 140 | 141 | `node app.js` 142 | 143 | Open a web browser and go to 144 | 145 | `http://localhost:8080` 146 | 147 | The happy path is to click the `authenticate` button in the "silver access" box and authenticate as carl.sagan. If all goes well, you will see a decoded access token in the access token box. 148 | 149 | Similarly, if you click the authenticate button in the "gold access" box and authenticate as jodie.foster, you will see a decoded access token in the access token box. 150 | 151 | The "raw" access token is available in the developer console if you want to inspect it. 152 | 153 | > Note: a "real world" web application that is using the authorization code grant flow would not typically send the access token to the browser, but would rather keep it server-side. We're sending it back to the browser here for demo purposes. 154 | 155 | > Note: if you authenticate as carl.sagan when you click on the authenticate button in the "gold access" box, you will successfully authenticate (get an Okta session) but you will not get an access token because the requested scopes do not line up with the policy you've set up in the authorization server. 156 | 157 | > Note: if you've followed the default Okta setup instructions, your default access policy will still be active in your tenant. The default access policy actually allows any user to be granted any scope (as long as the scope is requested in the authorization request). If you want to see if the authorization policies are "really" working, then just make the default policy for the authorization server inactive. 158 | 159 | If you click on the "show me" links now, they won't work, because we haven't set up the `gateway_uri` in our app yet. That's the next step. 160 | 161 | ### Set up your API Gateway + API 162 | 163 | Each API Gateway accommodates external OAuth providers slightly differently. Follow the instructions in the 'gateways' folder of this repo for the gateway that you are using. Instructions are available for the following gateways: 164 | 165 | * Apigee 166 | * Amazon API gateway 167 | * Kong 168 | * Mulesoft 169 | * Software AG 170 | * Tyk 171 | 172 | Please note that I have provided a very simple solar system API here: https://okta-solar-system.herokuapp.com 173 | 174 | This API echoes a list (json object) of the planets: https://okta-solar-system.herokuapp.com/planets 175 | 176 | And a (partial!) list of the moons: https://okta-solar-system.herokuapp.com//moons 177 | 178 | For demo purposes, the API is wide open. In a real-world use-case you would of course lock down the API so that it could be accessed only through your gateway. 179 | 180 | When you have finished setting up your API Gateway, come back to this doc to test your application and access tokens. 181 | 182 | You will need the URI of your gateway for the next step. 183 | 184 | ### Test your application and access tokens 185 | 186 | Now that you have set up your API Gateway, you should have a gateway uri. Enter that value in the `.env` file and restart the Node application. 187 | 188 | Now, after you authenticate, you should be able to click on one of the "show me" buttons and get a list of the moons and/or planets, depending on the scopes in your access token. 189 | -------------------------------------------------------------------------------- /routes.js: -------------------------------------------------------------------------------- 1 | 2 | var bodyParser = require("body-parser") 3 | 4 | var fs = require("fs") 5 | 6 | const OktaJwtVerifier = require('@okta/jwt-verifier') 7 | 8 | var request = require("request") 9 | 10 | var session = require("express-session") 11 | 12 | //*******************************************/ 13 | 14 | const oktaJwtVerifier = new OktaJwtVerifier({ 15 | issuer: process.env.ISSUER 16 | }) 17 | 18 | module.exports = function (app) { 19 | 20 | app.get('/', function(req, res, next) { 21 | 22 | fs.readFile('./html/index.html', 'utf8', (error, page) => { 23 | 24 | evaluate_vars(page, (error, page) => { 25 | if (error) { throw new Error(error) } 26 | 27 | res.send(page) 28 | 29 | }) 30 | }) 31 | }) 32 | 33 | app.post('/endSession', function(req, res, next) { 34 | 35 | delete req.session.access_token 36 | 37 | res.send("removed access token from server-side session"); 38 | }) 39 | 40 | app.post('/getAccessToken', function(req, res, next) { 41 | var code = req.body.code; 42 | 43 | console.log("the authorization code is: " + code); 44 | 45 | // exchange the authorization code 46 | // for an access token 47 | 48 | var options = { 49 | method: 'POST', 50 | url: process.env.ISSUER + "/v1/token", 51 | qs: { 52 | grant_type: 'authorization_code', 53 | code: code, 54 | redirect_uri: process.env.REDIRECT_URI 55 | }, 56 | headers: { 57 | 'cache-control': 'no-cache', 58 | authorization: 'Basic ' + getBasicAuthString(), 59 | 'content-type': 'application/x-www-form-urlencoded' 60 | } 61 | } 62 | 63 | request(options, function (error, response, body) { 64 | if (error) throw new Error(error); 65 | 66 | console.log(body); 67 | 68 | var obj = JSON.parse(body); 69 | 70 | if (obj.hasOwnProperty("access_token")) { 71 | req.session.access_token = obj.access_token; 72 | console.log("the access token is: " + req.session.access_token); 73 | } 74 | if (obj.hasOwnProperty("id_token")) { 75 | req.session.id_token = obj.id_token; 76 | } 77 | 78 | var response_to_browser = {} 79 | 80 | response_to_browser.access_token = obj.access_token 81 | response_to_browser.id_token = obj.id_token 82 | 83 | oktaJwtVerifier.verifyAccessToken(obj.id_token, process.env.CLIENT_ID) 84 | .then(jwt => { 85 | response_to_browser.id_token_decoded = jwt.claims 86 | console.log(jwt.claims) 87 | 88 | oktaJwtVerifier.verifyAccessToken(obj.access_token, process.env.AUD) 89 | .then(jwt => { 90 | response_to_browser.access_token_decoded = jwt.claims 91 | 92 | console.log(jwt.claims) 93 | 94 | console.log("the response to the browser is: ") 95 | console.dir(response_to_browser) 96 | 97 | res.json(JSON.stringify(response_to_browser)) 98 | }) 99 | .catch(err => { 100 | console.log("something went wrong with the access_token validation") 101 | console.log(err) 102 | 103 | }) 104 | }) 105 | .catch(err => { 106 | console.log("something went wrong with the id_token validation") 107 | console.log(err) 108 | }) 109 | }) 110 | }) 111 | 112 | app.post('/getData', function(req, res, next) { 113 | var endpoint = req.body.endpoint; 114 | 115 | console.log("the requested endpoint is: " + endpoint); 116 | 117 | console.log("the access_token token is: \n" + req.session.access_token + "\n"); 118 | 119 | // send the access token to the requested API endpoint 120 | 121 | if (process.env.hasOwnProperty("GATEWAY_URI") && process.env.GATEWAY_URI != "") { 122 | 123 | var url = process.env.GATEWAY_URI + "/" + req.body.endpoint 124 | 125 | console.log("sending request to: " + url) 126 | 127 | var options = { 128 | method: 'GET', 129 | url: url, 130 | headers: { 131 | 'cache-control': 'no-cache', 132 | authorization: "Bearer " + req.session.access_token, 133 | 134 | accept: 'application/json', 135 | 'content-type': 'application/x-www-form-urlencoded' 136 | } 137 | } 138 | 139 | request(options, function (error, response, body) { 140 | if (error) throw new Error(error) 141 | 142 | console.log("******\nresponse from API gateway: ") 143 | console.log("the status code is: " + response.statusCode) 144 | 145 | console.log("the body is:") 146 | console.log(body) 147 | 148 | if (response.statusCode == 403) { 149 | res.json({message: 'forbidden'}) 150 | console.log("the request is forbidden") 151 | } 152 | else if (response.statusCode == 401) { 153 | res.json({ message: 'unauthorized' }) 154 | console.log("the request is unauthorized") 155 | } 156 | // Add ec here for 504 157 | else { 158 | res.json(body) 159 | } 160 | }) 161 | } 162 | else { 163 | res.json({message: 'gateway_uri not yet defined.'}) 164 | } 165 | }) 166 | 167 | function getBasicAuthString() { 168 | 169 | var x = process.env.CLIENT_ID + ":" + process.env.CLIENT_SECRET 170 | 171 | var y = new Buffer(x).toString('base64') 172 | 173 | return y 174 | } 175 | } 176 | 177 | function evaluate_vars(page, callback) { 178 | var regex 179 | for (var key in process.env) { 180 | regex = new RegExp('{{' + key + '}}', 'g') 181 | 182 | page = page.replace(regex, process.env[key]) 183 | } 184 | return callback(null, page) 185 | } --------------------------------------------------------------------------------