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:
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:
- The recommended way is to use a software library.
- Alternatively, you can use standard tools on the command line. (This is useful for quick tests.)
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.