NuID Auth API Endpoints


The root URL of the API is https://auth.nuid.io

Every call to the API must be authenticated by passing the X-API-Key header. Each of the examples on this page has the Root URL and API Key header in place.

POST /credential


Create a new credential from a user secret, usually during user registration.

Example POST Request Using the Fetch API

const body = {
  "nuid.credential/verfied": Zk.verifiableFromSecret('test')
};
return fetch('https://auth.nuid.io/credential', {
  method: 'POST',
  body: JSON.stringify(body),
  headers: {
    'X-API-Key': '<API-KEY>',
    'Content-Type': 'application/json'
  }
})
  .then(res => console.debug(res))
  .catch(err => console.error(err));

POST Response Body (JSON)

{
  "nu/id": "<NUID>",
  "nuid/credential": {...}
}

In the Get Credential endpoint, we'll use the 'nu/id' field to retrieve public credential data, including alternative credential addresses such as an Ethereum transaction identifier.

GET /credential/{nuid}


Retrieve public credential data. This is often utilized during user login for retrieving an authentication challenge for a given credential.

In the following examples, nuid refers to the 'nu/id' field in the response from the POST /credential endpoint found above.

Example GET Request Using the Fetch API

return fetch('https://auth.nuid.io/credential/<NUID>', {
  headers: {
    'X-API-Key': '<API-KEY>',
    'Accept': 'application/json'
  }
})
  .then(res => console.debug(res))
  .catch(err => console.error(err));

GET Response Body (JSON)

{
  "nuid/credential": {...}
}

The nuid field used in /credential/{nuid} is a durable and unique identifier within the NuID Auth API, and may always be used to retrieve the corresponding public credential data.

Credential data may also be found at alternative addresses when they are stored publicly. For example, a credential stored as a transaction within the Ethereum network can be retrieved directly from the ledger using the transaction identifier.

The addresses field in the response body above is a collection of all such addresses for the given credential. Addresses are asynchronously associated to credential data, so it's possible that the transaction is still finalizing if addresses is empty in a response shortly after creation.

In the future, the NuID Auth API may also incorporate Decentralized Identifiers and many other addresses as a way to resolve and verify their cryptographic associations.

POST /challenge


Create a challenge from a public credential, usually during user login.

The set of /challenge endpoints allow an authenticating server to authenticate users without maintaining local state. They can also be used to generate and issue bearer assets such as OAuth tokens and JSON Web Tokens (JWTs) in SSO and transitive trust environments.

The /challenge endpoint can be used to issue single-use, short-lived challenges against any public credential, simplifying secure execution of the authentication flow.

The request body may be any well-formed credential, and needn't be registered through NuID. This is useful in ephemeral authentication contexts, such as OTP.

Example POST request with a :nu/id credential using the Fetch API

const getCredential = nuid => {
  return fetch(`https://auth.nuid.io/credential/${nuid}`, {
    method: 'GET',
    headers: {
      'X-API-Key': '<API-KEY>',
      'Accept': 'application/json'
    }
  });
};

const getChallenge = credentialBody => {
  const credential = credentialBody['nuid/credential'];
  const body = JSON.stringify({'nuid/credential': credential});
  return fetch('https://auth.nuid.io/challenge', {
    method: 'POST',
    body: body,
    headers: {
      'X-API-Key': '<API-KEY>',
      'Accept': 'application/json'
    }
  });
};

const nuid = "..."; // get nuid from user
getCredential(nuid)
  .then(res => res.json())
  .then(getChallenge)
  .then(res => console.debug(res))
  .then(err => console.error(err));

POST Response Body (JSON)

{
  "nuid.credential.challenge/jwt": "...",
}

The JWT payload contains a unique, short-lived challenge that is strongly bound to the credential from which it was created, as well as its containing JWT via cryptographic signature. The embedded challenge can be used to generate a similarly unique zero knowledge proof that we can verify using both the /challenge/verify endpoint or the client library directly.

JWTs enable stateless authentication and authorization flows, transitive identity assertion, and all sorts of neat things. Here's the JWT Wikipedia article for more information.

In the future, the /challenge endpoint family will support additional bearer assets with similarly powerful properties for additional flexibility within authentication flows.

POST /challenge/verify


Verify a proof against a credential challenge, usually during user login.

Example POST Request Using the Fetch API

const challengeJWT = '...'; // from the /challenge response
const challenge = decodeJWT(challengeJWT);    // the decoded JWT payload
const body = {
  'nuid.credential.challenge/jwt': challengeJWT,
  'nuid.credential/proof': Zk.proofFromSecretAndChallenge('test', challenge)
};
return fetch('https://auth.nuid.io/challenge/verify', {
  method: 'POST',
  body: JSON.stringify(body),
  headers: {
    'X-API-Key': '<API-KEY>',
    'Content-Type': 'application/json'
  }
})
  .then(res => console.debug(res))
  .then(err => console.error(err));

The response has no body, and a status of either 200 indicating successful authentication, or 400 indicating failure. In the future, responses may include contextual authorization tokens for use in transitive trust environments.