class NuID::SDK::API::Auth

This class wraps the NuID Auth API endpoints for simpler integration into existing authentication flows.

@example User Registration

class UsersController < ApplicationController
  NUID_API = ::NuID::SDK::API::Auth.new(ENV["NUID_API_KEY"])

  # The registration form should send the verified credential to be
  # recorded in the NuID Auth API. The response to that interaction
  # will provide a `nu/id` key in the response which should be stored
  # with the newly created user record.
  #
  # The "verified credential" is generated by your client application
  # using `Zk.verifiableFromSecret(password)` from the `@nuid/zk` npm
  # package.
  def register
    credential_res = nuid_api.credential_create(params[:credential])
    unless credential_res.code == 201
      return render_error("Unable to create the credential", :bad_request)
    end

    user = User.create!({
      email: params[:email].strip.downcase,
      first_name: params[:firstName],
      last_name: params[:lastName],
      nuid: credential_res.parsed_response["nu/id"]
    })

    render(json: { user: user }, status: :created)
  rescue => exception
    render_error(exception.message, 500)
  end
end

@example User Login

class SessionsController < ApplicationController
  NUID_API = ::NuID::SDK::API::Auth.new(ENV["NUID_API_KEY"])

  # Get a challenge from the Auth API. The client form should request
  # a challenge as the first of two phases to login. Once a succesful
  # challenge has been fetched, return it to the client so a proof
  # can be generated from the challenge claims and the user's password.
  def login_challenge
    user = User.where(email: params[:email].strip.downcase).first
    return render_error("User not found", :unauthorized) unless user

    credential_res = nuid_api.credential_get(user.nuid)
    unless credential_res.code == 200
      return render_error("Credential not found", :unauthorized)
    end

    credential = credential_res.parsed_response["nuid/credential"]
    challenge_res = nuid_api.challenge_get(credential)
    unless challenge_res.code == 201
      return render_error("Cannot create a challenge", 500)
    end

    challenge_jwt = challenge_res.parsed_response["nuid.credential.challenge/jwt"]
    render(json: { challengeJwt: challenge_jwt }, status: :ok)
  rescue => exception
    render_error(exception.message, 500)
  end

  # Verify is the second part of the login process. The params
  # provided here include the user identification param (email or
  # username), the unaltered challenge_jwt retrieved in phase 1 of login
  # (see #login_challenge above), and the proof that was generated from
  # the challenge_jwt claims and the user secret.
  #
  # The "proof" is generated by your client application using
  # `Zk.proofFromSecretAndChallenge(password, challenge_jwt)` from the
  # `@nuid/zk` npm package.
  def login_verify
    user = User.where(email: params[:email].strip.downcase).first
    return render_error("User not found", :unauthorized) unless user

    challenge_res = nuid_api.challenge_verify(params[:challengeJwt], params[:proof])
    unless challenge_res.code == 200
      return render_error("Verification failed", :unauthorized)
    end

    render(json: { user: user }, status: :ok)
  rescue => exception
    render_error(exception.message, 500)
  end
end

@see www.npmjs.com/package/@nuid/zk @see www.npmjs.com/package/@nuid/cli

Attributes

api_key[R]

Public Class Methods

new(api_key) click to toggle source

Create an HTTParty instance for dispatching HTTP requests.

All endpoints return the HTTParty Response object, with `HTTParty::Response#parsed_response` containing the JSON body converted to a hash.

@param api_key [string] The Auth API Key @see portal.nuid.io

# File lib/nuid/sdk/api/auth.rb, line 108
def initialize(api_key)
  @api_key = api_key
  self.class.headers({
    "X-API-Key" => @api_key,
    "Accept"    => "application/json"
  })
end

Public Instance Methods

challenge_get(credential) click to toggle source

Get a credential `challenge` from the API, usually during login flow. The returned `challenge` can be used to generate a proof from the user's secret. Used in conjunction with challenge_verify.

@see www.npmjs.com/package/@nuid/zk @see www.npmjs.com/package/@nuid/cli

@param credential [Hash] A `credential` is usually returned by the

#credential_get method

@return [HTTParty::Response] use

HTTParty::Response#parsed_response["nuid.credential.challenge/jwt"] to
get the challenge JWT from the parsed response
# File lib/nuid/sdk/api/auth.rb, line 128
def challenge_get(credential)
  _post("/challenge", {"nuid/credential" => credential})
end
challenge_verify(challenge_jwt, proof) click to toggle source

Verify a credential challenge with a proof generated from the challenge claims and the user's secret. Generated proof from the claims contained in the `challenge_jwt` and the user's secret. This proof is generated by `Zk.proofFromSecretAndChallenge(secret, challenge)` available in the npm package `@nuid/zk`.

@see www.npmjs.com/package/@nuid/zk @see www.npmjs.com/package/@nuid/cli

@param [String] challenge_jwt the `nuid.credential.challenge/jwt` returned

by #challenge_get

@param [Hash] proof the generated proof from the challenge jwt claims and

user secret

@return [HTTParty::Response] use `Response#parsed_response` to get the

parsed JSON body
# File lib/nuid/sdk/api/auth.rb, line 147
def challenge_verify(challenge_jwt, proof)
  _post("/challenge/verify", {
    "nuid.credential.challenge/jwt" => challenge_jwt,
    "nuid.credential/proof"         => proof
  })
end
credential_create(verified_credential) click to toggle source

Create a credential from a verified credential (meaning a credential generated from the user's secret). Usually used during user registration. The parsed response body contains the new credential and the user's unique “nu/id” which should be used as a reference to the user's credential for later authentication attempts.

@see credential_get @see www.npmjs.com/package/@nuid/zk @see www.npmjs.com/package/@nuid/cli

@param verified_credential [Hash] The hash returned by calling `Zk.verifiableFromSecret(secret)` @return [HTTParty::Response] use `Response#parsed_response` to get the

parsed JSON body
# File lib/nuid/sdk/api/auth.rb, line 167
def credential_create(verified_credential)
  _post("/credential", {"nuid.credential/verified" => verified_credential})
end
credential_get(nuid) click to toggle source

Fetch a credential by it's unique `nuid`. The `nu/id` paramter is extracted from the `#parsed_response` of credential_create.

Generally you will end up storing the nuid with your user record during registration. Later during login use the nuid to fetch the credential using this method, and pass the Response#parsed_response directly to challenge_get.

@param [String] nuid unique key for the credential @return [HTTParty::Response] use `Response#parsed_response` to get the

parsed JSON body
# File lib/nuid/sdk/api/auth.rb, line 182
def credential_get(nuid)
  self.class.get("/credential/#{nuid}")
end

Private Instance Methods

_post(path, body) click to toggle source
# File lib/nuid/sdk/api/auth.rb, line 188
def _post(path, body)
  self.class.post(path, {
    headers: {"Content-Type" => "application/json"},
    body: body.to_json
  })
end