Skip to content

Demo Wing OAuth server

Benjamin Pelletier edited this page Aug 27, 2019 · 2 revisions

Onboarding

Via Google Cloud (preferred)

If you are comfortable using Google Cloud, or are already hosting other parts of your infrastructure on Google Cloud, then you can simply create a service account yourself and give Wing its email address. This lets you stay in complete control of your service account, and create and revoke your own keys.

  1. Create a service account in one of your cloud projects.
  2. Tell Wing the email address of the service account you just created. It looks something like [ACCOUNT]@[PROJECT].iam.gserviceaccount.com.
  3. Create a key for the service account. You need to store this key securely and must not share it with anyone else - even Wing.

Via Wing-managed account

If you do not want to use Google Cloud, just tell Wing your preferred base domain (e.g., wing.com) which will serve as your USS name. Wing will provide a key as a JSON file that must be kept secret.

Obtaining a key

1. Load the service account credentials

Use your service account key JSON file to get an OAuth access token with the email scope. See the Google OAuth documentation for details. There are Python and Java client libraries available, but the documentation also describes how to do this manually with HTTP requests.

In Python:

from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(
    'service-account.json').with_scopes(['email'])

2. Request the JWT from the UTM Token Provider

Make a POST request to https://utm-oauth-demo-us.appspot.com/oauth/token. You must specify the following URL query parameters:

  • grant_type must always be client_credentials.
  • scope is a space-separated list of OAuth scopes you want to request. Valid values include dss.read.identification_service_areas and dss.write.identification_service_areas.
  • intended_audience is the hostname of the service (DSS or USS server) you actually want to call. The JWT that is issued will be restricted to use only that server, ensuring that the server can't take your JWT and use it to impersonate you to other parties.

You must also send an Authorization header containing the access bearer token generated in Step 1.

Successful responses

A successful response looks like this:

{
  "access_token": "...",
  "expires_in": 1800,
  "scope": "dss.read.identification_service_areas",
  "token_type": "Bearer"
}

You can use the access token to make requests to the DSS or USS server.

Troubleshooting possible error responses

  • {"error": "invalid_grant"} - ensure you set the grant_type=client_credentials query parameter.

  • {"error": "invalid_client"} - ensure that:

    • you have added an Authorization header with a Bearer token
    • the Bearer token has the email scope
    • you have included an intended_audience query parameter
    • the service account you're using is allowed to use the service
  • {"error": "invalid_scope"} - you requested a scope that you have not been given permission to use.

Example Python code

The script below will retrieve an access token when provided with a service account JSON key file.

# python3
"""Small example showing how to fetch a JWT."""

import argparse
import json
import sys
import urllib.parse

# pip install requests google-auth
from google.auth.transport import requests
from google.oauth2 import service_account

OAUTH_TOKEN_URL = 'https://utm-oauth-demo-us.appspot.com/oauth/token'


def ParseArgs(args):
  """Parse passed command-line arguments."""
  parser = argparse.ArgumentParser(
      description='Small example showing how to fetch a JWT')
  parser.add_argument(
      '--service-account-json',
      help='path to a JSON service account file',
      required=True)
  parser.add_argument(
      '--audience',
      help='the "aud" that the JWT should be issued for',
      required=True)
  parser.add_argument(
      '--scope',
      nargs='+',
      help='OAuth scope to request (e.g. '
      '"dss.write.identification_service_areas"). Can be specified multiple '
      'times',
      required=True)
  return parser.parse_args(args)


def Main(argv):
  """Small example showing how to fetch a JWT."""

  args = ParseArgs(argv)

  # Read the service account credentials from the file and create an authorized
  # session object that knows how to set the Authorization HTTP header.
  credentials = service_account.Credentials.from_service_account_file(
      args.service_account_json).with_scopes(['email'])
  session = requests.AuthorizedSession(credentials)

  # Request the JWT.
  url = '{}?grant_type=client_credentials&scope={}&intended_audience={}'.format(
      OAUTH_TOKEN_URL, urllib.parse.quote(' '.join(args.scope)),
      urllib.parse.quote(args.audience))
  response = session.post(url)

  print(json.dumps(response.json(), indent=2))


if __name__ == '__main__':
  sys.exit(Main(sys.argv[1:]))                                                                             

Validating

A token generated by this auth server may be validated by checking the signature against this public key:

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlImo4cK6pDDpPDJp3ETO
AghFLL35W+fNx3drwbq78+eAKrAkNuBN05JKDF5i8+EcnVzKSMZCrebx9mlBnctU
bEpnVefJcj2pmLyOJVbn7wfPdebkGFFiFPKzyzF71hZjX1LNuTSNklvsX+Ns7R78
h0wfw0ICG3NcSrk/f+IxqnH1iPn/d6E7OeHz3nNPxZV5OeEnP61Myy11f5/oXq7v
GHJhqfgG225Ld7cfwTdyMMBkfEcI4ha2lgyDcrgTqofW7+hzVXdXWI5Bkj8awEAk
jmIh08UtXHYygGAfJ+6TirbI/PodrL7IXwAMNiPyPMBdJHh7hnaDr9c3Z10kcEhZ
leqjyXrohiHtIitBsDLJfHSE3ta5QYGvyLqqtVAo//BAWpdGSscEg5RkLT514siP
jJKUsiwi8s073S8ayplHFaUBd8GnvG1nTvztjsVl2pkdQ9FYlkU3yat5cof25zXm
bVD6elaG9mh4Flp+DvxMvTGBCuO+M0UMqOuVRPJt9G0T2269M72hcO+SqVIk5Ko3
39HEOPihnALRE/GbvtdKV++qjE00ePeB8fXJOl+qePlHTxQBdBGq8fu+n/2JOgz+
slTZwk1QYA0iw5I8QI/SFLSFgtxYgiopQ/8C+1aN3yRhB/HpJThAXYu684HT3uVv
6Htni4wEiCUNVhNF/gb1+BUCAwEAAQ==
-----END PUBLIC KEY-----