Skip to content

Authentication

Authentication to the Superfacility API is handled by submitting an OAuth access token (JWT) with your API call.

Create a Superfacility API Client in Iris

In order to create access tokens, you first need to create an OAuth client. This can be done on the Iris profile page in the "Superfacility API Clients" section. Clicking the "+ New Client" button in this section will bring up a window like this:

Screenshot of SFAPI client creation window in Iris

A Superfacility API Client can be used to generate access tokens until it is deleted or until it expires. A client can be created for your user account or for any collab accounts to which you have access.

Client policy

For the API's initial roll out, we will offer read-only clients (all GET calls) to all NERSC users with a maximum lifetime of 6 months. At a later stage, write/execute-capable clients (POST and PUT calls) with a 24h lifetime will be made available for all users. Write/execute-capable clients with longer lifetime are available by request on a per-case basis. If such a client is crucial for your workflow, please reach out to us via ticket

Client Source IP Range

Each client must have a source IP range specified. You can enter an IP range in the free-form text field, or you can choose one of the available "IP Presets". Information on these presets is listed in the table below.

IP Preset Information
Your IP This inserts the IP address of the computer on which you are creating the client. Choose this option if you plan to use the SF API from your computer.
Spin This fills in the IP address range corresponding to the Spin system at NERSC. Use this option if you are creating a client to use with a Spin service.
Cori Nodes This inserts the IP address range of nodes on the Cori system. Choose this option if you are planning to make SF API calls from Cori login nodes or the NERSC JupyterHub.
DTN Nodes This inserts the IP address range of the NERSC Data Transfer Nodes. Use this option if you are planning to make SF API calls from a DTN.

Save the client information

Once you have filled out the new client form, you will receive a private/public key-pair and a client ID. It is important to save the private key in a secure location, as you will not be able to view it again in Iris.

Exchange a "client assertion" for an "access token"

Next you need to use your private key to generate a client assertion that can be exchanged for an access token. Access tokens have short lifetimes of approximately 10 minutes.

There are two ways to use your client key to generate an access token:

Using the AuthLib Python Library to get an Access Token

There are libraries for most programming languages that allow you to generate and use an access token from the client information shown in Iris. In this example, we will use the Authlib Python library.

After installing the Authlib library via either conda or pip, we can then use it to generate an access token from the key pair and client ID created in Iris:

from authlib.integrations.requests_client import OAuth2Session
from authlib.oauth2.rfc7523 import PrivateKeyJWT

token_url = "https://oidc.nersc.gov/c2id/token"
client_id = "<your client id>"
private_key = "<your private key>"

session = OAuth2Session(
    client_id, 
    private_key, 
    PrivateKeyJWT(token_url),
    grant_type="client_credentials",
    token_endpoint=token_url
)
session.fetch_token()

Further information about the OAuth2Session is available in the Authlib documentation. An OAuth2Session object implements "OAuth for Requests," a replacement for the requests-oauthlib library. You can use it just like a Requests Session object (in fact it is derived from that). In constructing session above we have given it all the metadata it needs to automatically update the token if it expires. This way, you don't have to manually request a new token when the old one expires.

Using the command line to get an Access Token

Here, we show how to use the command line and some standard tools (curl, openssl, etc) to create a client assertion and exchange it for an access token.

1. Save the client id to a json file

First, create a json file called payload.json:

{
        "iss" : "<client_id>",
        "sub" : "<client_id>",
        "aud" : "https://oidc.nersc.gov/c2id/token",
        "exp" : <expiration timestamp>
}

"client_id" is your client id from Iris.

The expiration timestamp should be in the future. You can get a future date (eg. 5 mins from now) from the GNU date command:

date --date 'now + 5 minutes' "+%s"

or from BSD date:

date -v +5M "+%s"

2a. Create the client assertion using the "jose" tool

Next we need to create a client assertion (a JWT), by taking the payload.json file, adding a header and signing it with our private key. The simple way to do this is to install the jose tool, and run:

ASSERTION=$(jose jws sig -I payload.json -k my-keyset.jwk -c)

Here, my-keyset.jwk is private key in JWK format as shown by Iris.

2b. Or, create the client assertion using standard tools

Alternatively, you can create the client assertion using standard tools. Iris shows the generated client keys in both JWK and PEM formats. Using the latter, you can construct a JWT using openssl. Save the PEM-formatted private key as priv_key.pem and run:

echo -n '{ "alg": "RS256" }' | openssl base64 -A | tr '/+' '_-' | tr -d '=' > head.b64
openssl base64 -in payload.json -A | tr '/+' '_-' | tr -d '=' > body.b64
cat head.b64 <(echo '.') body.b64 | tr -d "\n" > jwt.txt
openssl dgst -sha256 -sign priv_key.pem jwt.txt | openssl base64 -A | tr '/+' '_-' | tr -d '=' > sig.sha256.b64
ASSERTION=`cat jwt.txt <(echo '.') sig.sha256.b64 | tr -d "\n"`

The tr command trailing the openssl lines translates base64 to the base64url encoding that JWTs use.

3. Exchange the client assertion for an access token

Now you're ready to exchange the encrypted assertion for a short-lived access token:

curl -s -XPOST -H "Content-Type:application/x-www-form-urlencoded"  -d "grant_type=client_credentials&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&client_assertion=$ASSERTION"  https://oidc.nersc.gov/c2id/token

The returned json will contain the access token under the "access_token" key.

Call the SuperFacility API with the access token

Once you have the access token, you can call the API:

From bash:

curl -X POST "https://api.nersc.gov/api/v1.2/utilities/command/dtn01" -H "accept: application/json" -H "Authorization: $ACCESS_TOKEN" -H "Content-Type: application/x-www-form-urlencoded" -d "executable=hostname"

From Python, using the requests library:

import requests
access_token='<your access token goes here>'
r = requests.get("https://api.nersc.gov/api/v1.2/tasks?tags=%20", headers={ "accept": "application/json", "Authorization": access_token})
print(r.json())

Note

Make sure to check out the examples.