Skip to content

Instantly share code, notes, and snippets.

@vkarpov15
Last active September 18, 2019 00:26
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vkarpov15/8bcab907c961cab3740e2e1216ea93d2 to your computer and use it in GitHub Desktop.
Save vkarpov15/8bcab907c961cab3740e2e1216ea93d2 to your computer and use it in GitHub Desktop.
Brief guide to setting up oauth with Express gateway

Implementing Oauth in Express Gateway

Express Gateway gives you the ability to spin up your own oauth provider from the command line. Oauth enables your users to delegate API endpoints to various apps via scopes. In this introductory article, you'll learn how to get up and running with Oauth in Express Gateway.

Configuring the Gateway

The first step is to create a new gateway using the Express Gateway generator. First, install the express-gateway npm module, and then create a new gateway using eg gateway create.

$ npm i -g express-gateway
$ eg gateway create
? What's the name of your Express Gateway? oauth
? Where would you like to install your Express Gateway? oauth
? What type of Express Gateway do you want to create? Getting Started with Express Gateway
   create package.json
   create server.js
   create config/gateway.config.yml
   create config/models/applications.js
   create config/models/credentials.js
   create config/models/users.js
   create config/system.config.yml

To start oauth, run the following commands:
    cd oauth && npm start
$

Second, edit the config/gateway.config.yml file and enable oauth for the default pipeline as shown below. Once you turn on oauth, you should see an 'Unauthorized' error when you visit http://localhost:3000/ip. You need to restart the server for config changes to take effect, so if you ran npm start be sure to kill the process and then re-run npm start.

http:
  port: 8080
admin:
  port: 9876
  hostname: localhost
apiEndpoints:
  api:
    host: localhost
    paths: '/ip'
serviceEndpoints:
  httpbin:
    url: 'https://httpbin.org'
policies:
  - basic-auth
  - cors
  - expression
  - key-auth
  - log
  - oauth2
  - proxy
  - rate-limit
pipelines:
  - name: default
    apiEndpoints:
      - api
    policies:
      # The below enables oauth for the localhost:8080/ip endpoint
      - oauth2:
      - proxy:
          - action:
              serviceEndpoint: httpbin
              changeOrigin: true

Next, you'll need to create a new Express Gateway user. Users and applications have a one-to-many relationship, so you must create a user before you create an application. Make sure you do not restart the express gateway server after creating a user unless you have already set up a data store, because otherwise express gateway will use an in-memory data store and all your users will be deleted if the process is killed.

$ eg users create
? Enter username [required]: val
? Enter firstname [required]: Valeri
? Enter lastname [required]: Karpov
? Enter email: val@karpov.io
? Enter redirectUri: 
✔ Created c25fe037-30bb-42f7-9f3a-0264dcd60d14
{
  "firstname": "val",
  "lastname": "karpov",
  "email": "val@karpov.io",
  "isActive": true,
  "username": "val",
  "id": "c25fe037-30bb-42f7-9f3a-0264dcd60d14",
  "createdAt": "Wed Aug 16 2017 22:08:07 GMT-0700 (PDT)",
  "updatedAt": "Wed Aug 16 2017 22:08:07 GMT-0700 (PDT)"
}

Next, you need to create 2 credentials for this user: an oauth credential and a basic-auth (password) credential. Express Gateway has a one-to-many relationship between users and credentials, so a user can have multiple credentials of different types (OAuth, key-auth, basic, etc.). The below creates an oauth credential and a basic-auth credential with password "bacon". Note that password doesn't show up in the output of eg credentials create -t basic-auth, that's for security.

$ eg credentials create -c val -t oauth2
✔ Created val
{
  "isActive": true,
  "createdAt": "Wed Aug 16 2017 22:08:13 GMT-0700 (PDT)",
  "updatedAt": "Wed Aug 16 2017 22:08:13 GMT-0700 (PDT)",
  "id": "val",
  "secret": "45e94fce-1524-4fbf-89b9-57a157079db7"
}
$ eg credentials create -c val -t basic-auth -p "password=bacon"
✔ Created val
{
  "isActive": true,
  "createdAt": "Wed Aug 16 2017 22:08:21 GMT-0700 (PDT)",
  "updatedAt": "Wed Aug 16 2017 22:08:21 GMT-0700 (PDT)",
  "id": "val"
}

Finally, you need to create an application, or "app". The app represents a consumer of your API. Similar to how an app might use Facebook login and request access to the user's photos, an Express Gateway app will log in against Express Gateway and receive permission to access a certain set of API endpoints. To create an app, you need to specify an associated user, a name, and a redirect URI, which is the URL the user will be directed to after successfully logging in.

$ eg apps create -u val
? Enter name [required]: testapp
? Enter redirectUri: http://google.com
✔ Created 84828eee-2832-4ecd-8155-008fbea0f485
{
  "name": "testapp",
  "redirectUri": "http://localhost:8080/ip",
  "isActive": true,
  "id": "84828eee-2832-4ecd-8155-008fbea0f485",
  "userId": "val",
  "createdAt": "Wed Aug 16 2017 22:08:38 GMT-0700 (PDT)",
  "updatedAt": "Wed Aug 16 2017 22:08:38 GMT-0700 (PDT)"
}

Walking Through the Oauth Flow

Now that you've set up the necessary objects, let's walk through the actual oauth flow using Chrome and cURL. You'll notice that if you visit http://localhost:8080/ip in Chrome you'll get an 'Unauthorized' error message as shown below.

Your gateway.config.yml file protects the /ip endpoint behind oauth middleware, so you need to get an access token by walking through the Express Gateway oauth flow. To start, you need to visit the /oauth2/authorize endpoint and specify the following parameters in the URL query string:

  • response_type: String containing either 'bearer' or 'token'. For this example you'll use 'token'.
  • client_id: String containing the id of your app from the output of eg apps create -u val. In this case, '84828eee-2832-4ecd-8155-008fbea0f485', but it will be different for you.
  • redirect_uri: String that must match the redirectUri you specified when running the eg apps create -u val command.

Here's how the full URL looks:

http://localhost:8080/oauth2/authorize?response_type=token&client_id=803b1da9-879d-44b5-8d77-5199c4e11fba&redirect_uri=http://localhost:8080/ip

When you visit this URL, you should get redirected to a login screen. You can configure the UI, but for this article you'll just use Express Gateway's minimal built-in login screen.

Enter in the username and password you entered when you ran eg users create. If you're following this article exactly, the username will be "val" and the password will be "bacon". You will then get redirected to a page that asks you to authorize your app 'testapp' to access your account. In more advanced applications, this is also where Express Gateway will ask for other permissions (scopes).

Hit the 'Allow' button to continue the flow and you'll get an 'Unauthorized' error. Don't panic, you didn't do anything wrong, this is actually the right behavior. Oauth is all about granting API access to client apps, and does so by putting the access_token in the URL. This is the access token you use in the Authorization header in your HTTP requests to authenticate to the oauth policy. Your app will have to do that on its own, but, in the interest of keeping this example lean, you'll just use curl.

Copy the access_token from the URL bar. The access_token is URI-encoded, so first decode it using Node.js's shell.

$ node
> decodeURIComponent('599f481560a74545a0f9d54a2e3f7dde%7Cb1f7252fe6f24a0d98d98cc87693579c')
'599f481560a74545a0f9d54a2e3f7dde|b1f7252fe6f24a0d98d98cc87693579c'
> 

Next, use curl to make an HTTP request with the token in the Authorization header as shown below:

$ curl -H "Authorization: Bearer 599f481560a74545a0f9d54a2e3f7dde|b1f7252fe6f24a0d98d98cc87693579c" http://localhost:8080/ip
{
  "origin": "76.220.52.187"
}
$ 

Congratulations, you've successfully generated an access token through Express Gateway's oauth flow and used it to make an authenticated request!

Moving On

This article is just a "Hello, World" level example for oauth with Express Gateway. In this example you used Express Gateway as both the auth server (the server requesting auth) and the resource server (the server granting access to the API). However, Express Gateway can also serve as an auth server for an external API, so you can add OAuth permissions on top of any API. I'd recommend you try actually building a client-side app that uses Express Gateway oauth for login, and read up on scopes so you can control which portions of your API your app has access to.

@altsang
Copy link

altsang commented Aug 18, 2017

hey @vkarpov15 think this looks great! maybe just want to mention that for this walkthrough exercise, we're using the Express Gateway built in memory DB and that's why you shouldn't restart after you created credentials

@DrMegavolt
Copy link

Great article!

@altsang
Copy link

altsang commented Aug 22, 2017

probably want to mention that consumers can have multiple credential types (e.g. OAuth versus basic)

think it's also worth mentioning - since it's a key differentiator for our gateway - EG can serve as both the auth and resource server in the OAuth2 flow and in doing so we provide a reference implementation to ask for authorization in the template web page for logging in and authetnicating. EG out of the box is ready to front a headless API with no app capabilities needed to be able to ask for authorization and scope confirmation - you can just ours and customize

other then that a mass replace of "Oauth2" to "OAuth2" :) and good to , thx Val - great article indeed!!

@amit123delhi
Copy link

the oauth2/token global endpoint is not working for the password grant flow. Any suggestion or help how to use it would be appreciated.

Thanks,
Amit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment