A Very Short (but very detailed) Nametag Tutorial

Welcome

Welcome to Nametag! This tutorial will walk you through setting up a Nametag-enabled web site running on your own computer. We don’t expect any prior experience with Nametag, OAuth2, or any particular Python libraries. However, we will be using Python to serve our very simple web site, so having Python (version 3) installed on your computer is required; some experience with that will be useful. You will also need an Internet connection—even though your sample web site will be running on your computer and only accessible by you, we will need to contact the Nametag servers to do the authentication.

In summary:

Things you need Things you don’t need
A computer with Internet access Experience with Nametag
Python installed Experience with OAuth2
A Nametag Developer account Experience making Python-backed websites

There are two parts to setting up this example

  1. telling Nametag about the application you are going to create; this should take about 10 minutes after you have your Nametag developer account
  2. creating the application; this can be as fast as 10 minutes or it can take longer if you delve into the details and spend time thinking about how your application can use the concepts and practices from this example.

These don’t all have to be done at once; you can do the Nametag configuration today and come back later to work on the application if you want.

Configuring Nametag

Nametag uses Nametag to permit you access to the developer tools at https://nametag.co, so the first step is to download the Nametag Hello app from the app store for your device or visit https://nametag.co/install and enroll in Nametag. This process should take well under 5 minutes.

After you have your Nametag account, work with your Nametag representative directly or email help@nametag.co using a Nametag-verified email (you can configure as many emails the Nametag Hello app as you want) or send us your Nametag number which is displayed on the home screen of the Nametag Hello app.

Nametag supports development teams comprising members with different roles; every Nametag-enabled application is managed by a team, even if that team is just one person. So the next thing to do is create a team for your example application.

  1. Go to https://console.nametag.co/manage/teams, you may be prompted to log in with your Nametag account if you aren’t already logged in
  2. When you get to the Teams page click “New Team”; you will automatically be a member
  3. Give your team a name and click “Save”; for this example name your team “Candy Shop Team”

If you are working with other people, you can add their Nametag accounts to your team.

This next step will be unique for every application (be it a web-based application, a mobile application, or any other Nametag-enabled software you create). The result of this is to have unique credentials for every application; there is no reason to share credentials between applications and it is, in fact, a very bad idea to do that. Let’s create a Nametag app configuration for your example web application.

  1. Click “Apps” at the menu at the top of the page (or go to https://console.nametag.co/manage/apps), choose your team from the dropdown and click “New”

  2. On the “General” page fill in this information

    1. Internal Name: my-candy-shop

    2. Public Name: Candy Shop

    3. Description: The world's best candy store: Candy Shop dot Com

    4. Visit URL: candy.example.com/account (note: this doesn’t have to be a real url for this demonstration, when you create your first production application, you will want to have a real URL for this)

    5. ToS URL: candy.example.com/terms-of-service (note: this doesn’t have to be a real url for this demonstration, when you create your first production application, you will want to have a real URL for this)

    6. Download the sample logo for the Candy Shop application and use it as the logo.

    When this tab (the “General” tab) is complete, it should look about like the filled out “General” tab in the screenshot.

    img

  3. On the “Data requests” tab fill in this information

    1. Add Email (nt:email) with an expiration of 1 day and a reason of We use your email address to contact you when we need to.
    2. Add Name (nt:name) with an expiration of 1 day and a reason of We want to know you!
    3. Add Login (login) with an expiration of 1 day and a reason of So you can log in

    When this tab (the “Data requesets” tab) is complete, it should look about like the screenshot showing the data requests tab as you go through the process of adding scopes for data you need from your users.

    img

  4. On the “Configuration” tab

    1. Copy the Client ID to a text file on your computer
    2. Generate a Client Secret and copy that to the same text file
    3. Add a Callback URL of http://localhost:8080/loggedin

    It should look about like the configuration tab figure.

    img

You have now down all of the configuration needed to create a web application that uses Nametag for authentication and information management.

Next we’ll make a simple web application and use all of this information!

Create a Simple Web Application using Nametag

Now that we’ve informed Nametag about our application and have copies of the Client ID, Client Secret, and Callback URL, we can start implementing a web site that uses Nametag to allow people to log in.

Before you get excited (or worried), calling what we are about to make “a website” is a very loose interpretation of what a modern website looks like. We aren’t going to have any CSS or other styling, we aren’t going to use any modern web frameworks, there isn’t going to be any databases or dynamic content (other than what Nametag provides for you). It’s going to be very simplistic to the point of being pretty unappealing. But it is going to be functional and the steps to make it work are going to be clear.

If you are familiar with Python, and especially if you are familiar with OAuth2 web apps in Python, you might want to skip this section and look at the Python code itself in Section 4 (You are also allowed to go look at it even if you aren’t familiar with those things. Encouraged, even.)

Let’s get started making our Python-backed web site.

Create a Python3 environment the contains the Python packages: flask, requests, and authlib. The pipenv tool can be quite useful for this, and we include a Pipfile and Pipfile.lock. If you prefer Python virtual environments we include the familiar requirements.txt file. Or, simply, if you have pip installed, you can type:

pip install flask
pip install requests
pip install authlib

and if you don’t have pip installed, see https://pip.pypa.io/en/stable/installing/ for more information.

The example here uses a server-side web framework for Python called Flask; Flask will let us focus on the parts of our application that are used by Nametag and take care of the rest for us. We can create a very simple Flask application that has two URLs it will respond to: / (the initial URL) and /loggedin, the URL that will display information from Nametag, if you approve it. For now, though, those two URLs will simply print some basic text in your browser. To start, create a Python file by typing (or copying-and-pasting) this into a text file:

#!/usr/bin/env python
from flask import Flask, request, session, redirect

app = Flask(__name__)

@app.route("/")
def main_page():
    home_page = "<h1>Welcome</h1><p>Welcome to my webpage</p>"
    return home_page

@app.route("/loggedin")
def logged_in():
    loggedin_page = """<h1>Logged In</h1>
    <p>Later we will show data from Nametag here</p>"""
    return loggedin_page

if __name__ == "__main__":
    app.run(port=8080, debug=True)

If you copy and paste, or type, that into a file called nt.py then run python nt.py you should see printed to your screen:

* Serving Flask app 'nt' (lazy loading)
* Environment: production
  WARNING: This is a development server. Do not use it in a production deployment.
  Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.[1]:8080/ (Press CTRL+C to quit)

(if you see a Python error instead, check the nt.py file for spacing problems, copy-and-paste errors, and make sure you’re in a properly configured Python environment) Now enter the URL http://127.0.0.[1]:8080/ in your web browser and you should see the Welcome page. Entering http://127.0.0.[1]:8080/loggedin in your web browser should show you the Logged In page. It should look about like the screen shots of the sample app.

img

Nametag uses OAuth2 to negotiate credentials between the end-user, Nametag, and your web application. The OAuth2 exchange is shown in the diagram in Nametag Authentication Flow Sequence Diagram. This diagram doesn’t show the flow where the Customer rejects your request; in that case the Customer’s web browser is directed back to the CandyShop but the CandyShop web application doesn’t have the authorization token, so cannot request an access token or any customer data. Your web application needs to handle that case.

img

Our simple web application needs to implement those steps. The good news is that the Python Authlib library will help us immensely with all of this. Authlib uses the requests library, and we will also use it, so we need to include that, too. And, lastly, we’ll want to read some information from the environment on your computer (more on this to come), so we will include the os library to help us to do that. Given all of that, the top part of your Python script should now look like:

#!/usr/bin/env python3
from flask import Flask, request, session, redirect
from authlib.integrations.requests_client import OAuth2Session
import requests
import os

We will need to set up a few useful variables, too. To help prevent having your Nametag API credentials in files that might get checked into source control or otherwise read by someone who shouldn’t see them, we will get the credentials from environment variables (more on this later); the other variables we can simply set. Below the import lines, set these variables in the Python script.

client_id = os.getenv("NT_CLIENT_ID")
client_secret = os.getenv("NT_CLIENT_SECRET")
redirect_uri = "http://localhost:8080/loggedin"
scope = "nt:email login"
authorization_endpoint = "https://nametag.co/authorize"
token_endpoint = "https://nametag.co/token"

These lines do:

  1. set the client_id variable from the environment variable called NT_CLIENT_ID; on Linux and MacOS, the command

    export NT_CLIENT_ID=the client id from the Nametag app page of the developer console
    

    will set the environment variable; on Windows

    set NT_CLIENT_ID the client id from the Nametag app page of the developer console
    

    will do the same.

  2. set the client_secret variable from the environment variable called NT_CLIENT_SECRET

  3. The redirect_uri set here needs to be exactly the same as what you set in the Nametag App configuration page

  4. The scope variable is a space-seperated string of scopes; if you set a scope that wasn’t configured in the Nametag App configuration page your users will see an error on the Nametag page, so make sure any scopes you include here are configured on the Nametag App configuration page; you can request fewer scopes here than are configured, though; the login scope is required for the example to work.

  5. The authorization_endpoint is always the same for all Nametag-enabled applications

  6. The token_endpoint is also always the same

You now have the first part of your Python-backed website. If you want you can press Ctrl-C to stop the Flask web server you started before and re-start it. While you’ve added quite a bit to the Python file, you’ll see that nothing has changed. But soon…

Referring back to the Nametag authorization flow we have implemented only Step 1. Steps 2 and 3 make a lot of use of the Authlib library we imported and are done in three lines of Python code:

client = OAuth2Session(client_id, client_secret, scope=scope, redirect_uri=redirect_uri)
uri, state = client.create_authorization_url(authorization_endpoint)
page = (f"<h3>Sign in with Nametag</h3><a href=\"{uri}\"><img src=\"https://nametag.co/button.svg\"/></a>")
  1. Creating the OAuth2Session is the first part of Step 2 in the Flow Diagram.
  2. Getting the uri and state is the rest of Step 2 and all of Step 3
  3. This creates the Nametag button (you can, of course, use whatever button you want, you don’t have to download ours)

If you stop your Python webserver now (press Ctrl-C in the window where you ran python nt.py) and restart it, visiting https://localhost:8080 will present you with a page that looks like the one below and peeking at the page source you’ll see the use of uri in href for the button.

img

Hooray! We have built the first part of our application’s interaction with Nametag!

At this point if you click the button you will be taken to the Nametag login page, you’ll see a QR code to scan, and you can approve the request; it will look like the flow shown in the image showing the first half of the visual flow.

img

This is looking pretty good—we have gotten all the way to Nametag and back to our loggedin page. But we still haven’t gotten any data from Nametag. Let’s do that.

When Nametag returns the user to what you configured as the Callback URL, there will be two pieces of information in the query parameters; these, in combination with your Client Secret will let you get information about the user who granted you permission.

Ignoring some error checking that is in the full version, we can get the returned code from the URL in two lines of Python:

query_string = parse_qs(urlparse(request.url).query)
auth_code = query_string["code"][0]

These two lines1:

  1. take the URL, split off the query, and parse it into a Python dictionary that we’ve called query_string
  2. Take the first (and, in our case, always the only) item from the code query-string parameter and store it in the variable auth_code.

And now we have the three pieces of information we need to request data about our Candy Shop customer from Nametag: the Authorization Code, the Client ID, and the Client Secret.

There are four more steps to go, then we will have user information in hand:

  1. Re-establish the OAuth2 session with Nametag
  2. Request a token based on the authorization code we got back
  3. Build a request URL
  4. Fetch the data from the request URL

After that all our example application does is print the data to the webpage. Other examples we provide go into how to store and use this information.

Re-establishing the OAuth2 session uses Python Requests’ session variable to hold state between the initial page and the loggedin page, so we can use these lines to re-establish the OAuth2 session:

client = OAuth2Session(
    client_id,
    client_secret,
    state=session["oauth_state"],
    redirect_uri=redirect_uri,
)

The we can request a token from that client session (client.fetch_token) using the auth_token we got above:

token = client.fetch_token(
    token_endpoint,
    authorization_response=redirect_uri,
    grant_type="authorization_code",
    code=auth_code,
)

Again skipping some error checking that is in the full program below, we can make a URL that can be used to get user data from Nametag:

ntfetchurl = ("https://nametag.co/people/me"
	      "/properties/nt:email"
	      f"?token={token['id_token']}")

where we are contacting nametag.co and asking for information about people who are the special subject me about whom we want to know nt:email using the id_token (which encodes the user—this is why we can (and must) use me as the subject) we got back when we requested the client to fetch_token.

Now we can simply fetch that URL using Python’s Requests library:

response = requests.get(ntfetchurl)

Once again ignoring error checking, the response will be a JSON object that will look like:

{
  "subject": "7yrxpm0oy4l7iycrrkEs5mpwwi@yujstm3v0ljqsx.nametag.co",
  "properties": [
    {
      "expires": 1626291016,
      "scope": "nt:email",
      "value": "candy-fan-01@example.com",
      "status": 200
    }
  ]
}

and now we know that the user’s email address is candy-fan-01@example.com.

Importantly, we also know their Nametag subject is 7yrxp...@yujst....nametag.co. This is, in fact, the only piece of information you should store about this person. You can use this subject in combination with your Client Id and Client Secret to retrieve the personal information of Candi Lovre at any time in the future as long as Candi hasn’t revoked their permission to you.

This is the value of Nametag

Thank you for reading.

A Nametag Authorization Example in 70 Lines of Python

This is an example web application that you can run on your computer using Python and three additional Python packages. I lied slightly—there are more than 70 lines of Python below because of the comments; the lines of functional Python code is 70, though.

#!/usr/bin/env python3
from flask import Flask, request, session, redirect
from authlib.integrations.requests_client import OAuth2Session
import requests
import os
import json
import time
from urllib.parse import urlparse, parse_qs

app = Flask(__name__)

# The client_id, client_secret, and redirect_uri come from the Nametag
# app configuration page.
client_id = os.getenv("NT_CLIENT_ID")
client_secret = os.getenv("NT_CLIENT_SECRET")
redirect_uri = "http://localhost:8080/loggedin"
# asking for more items in the scope than you've configured will lead
# to a NT error page.
# setting the scope narrower than is configured at NT and still
# requesting that scope will return a status 403 for the object with
# that scope in the list of returned objects.
scope = "nt:email login"
# these variables are always the same when working with Nametag
authorization_endpoint = "https://nametag.co/authorize"
token_endpoint = "https://nametag.co/token"


@app.route("/")
def main_page():
    # Make sure we have credentials configured for the server,
    # otherwise print a mildly helpful message.
    if not client_id or not client_secret:
        return("Please configure the environment variables "
               "<kbd>NT_CLIENT_ID</kbd> and "
               "<kbd>NT_CLIENT_SECRET</kbd>.")
    # configure an OAuth2 session with the credentials from the NT app
    # page.
    client = OAuth2Session(
        client_id, client_secret, scope=scope, redirect_uri=redirect_uri
    )
    # generaate a login URL for the app configured on the NT app page
    uri, state = client.create_authorization_url(authorization_endpoint)
    # store the OAuth state information in Flask's encrypted session
    # space.
    session["oauth_state"] = state
    # create the most basic page with a NT login button on it.
    page = ("<h3>Sign in with Nametag</h3>"
            f"<a href=\"{uri}\">"
            "<img src=\"https://nametag.co/button.svg\"/>"
            "</a>")
    # you can return a redirect to the NT auth URL here to skip
    # offering the button and go straight to the NT login page.
    #return redirect(uri)

    # returning `page` will have flask return the HTML in that
    # variable to the browser.
    return page

# This is the endpoint that the Nametag login page will come back to
# after confirming with the mobile app if the request is approved or
# denied
@app.route("/loggedin")
def logged_in():
    # The code returned in the query string is needed to get a token
    # for making requests.
    query_string = parse_qs(urlparse(request.url).query)
    # But if `code` isn't in the query string, it means either the
    # request was denied or something else went wrong.
    if "code" not in query_string:
        return "Request denied or otherwise unsuccessful"
    auth_code = query_string["code"][0]
    # Configure a new OAuth2 session using the saved state (you can
    # also use the `state` variable returned in the query string).
    client = OAuth2Session(
        client_id,
        client_secret,
        state=session["oauth_state"],
        redirect_uri=redirect_uri,
    )
    # Using the configured client session request a token for making
    # requests.
    token = client.fetch_token(
        token_endpoint,
        authorization_response=redirect_uri,
        grant_type="authorization_code",
        code=auth_code,
    )
    # If the token has in it the thing we need, we can make a
    # request, otherwise we display a failure message.
    if "id_token" in token:
        # Build a URL out of the subject and id_token from the token.
        ntfetchurl = ("https://nametag.co/people/me"
                      "/properties/nt:email,nt:name,nt:phone"
                      f"?token={token['id_token']}")
        # Using the Python Requests package, fetch the URL
        response = requests.get(ntfetchurl)
        # If we get a status code of OK, print the results to the
        # screen; this is the place you would store the `subject`, use
        # the email address to look up other information (hopefully
        # stored with a hash of the email address, not the address
        # itself).
        if response.status_code == 200:
            now = int(time.time())
            nametag_results = json.dumps(response.json(), indent=2)
            return(f"success at {now}<br><pre>{nametag_results}</pre>")
        else:
            return("Failure: status code", response.status_code)
    else:
        return("Failure: the token we got back didn't have what we needed")


if __name__ == "__main__":
    # We need a secret key so we can use Flask's session for storing
    # some state.
    app.secret_key = os.urandom(24)
    app.run(port=8080, debug=True)

Footnotes

1 A whole URL that Nametag returns to you might look like https://localhost:8080?code=db52d&state=4uF8; the first line makes a Python dictionary that looks in part like query_string["code"]=["db52d"] and the second line takes the first element (again, in the case of what Nametag will return to your application, there will always only ever be one element in this array) from the array that is in the query_string dictionary element referenced by code, resulting in access_code being equal to db52d (or, more practically, the actual code Nametag returns to your application).