Create a web portal driven by the YubiEnterprise API that allows your customers to order from your organization's inventory
Explore the docs »
·
Report Bug
·
Request Feature
Table of Contents
YubiEnterprise Delivery is a cloud-based service that enables streamlined distribution of YubiKeys to end-users’ offices or residential addresses, both domestic and international.
While YubiEnterprise Delivery (YED) can be driven entirely through the pre-built console, it comes with an API that allows for the ability to extend the functionality. This will allow your organization's developers to integrate the API into custom solutions that further meet the requirements of your business.
This example will demonstrate an end-to-end solution demonstrating the ability to integrate the YED API into a web application that users in your enterprise (or beyond) could use to create YubiKey orders from your organizations inventory.
In this project you will
- Stand up an environment in AWS to handle the server side operations for the YED API and for handling user authentication/authorization
- Use the YED API to create, delete, edit, and retrieve shipments as well as verify a shipment address
- Create a front end application for your end users to order a YubiKey that has been defaulted by your organization
Disclaimer - This project is not meant to act as a production ready solution for all organizations. It is meant to demonstrate a reference architecture for how the YED API can be integrated into a custom application.
Here is a description of each of the components above, and why they are included in this project
- YubiKey Ordering Web App - The client for your application which will allow your end users to create, manage, and track their personal shipment
- OpenID Connect Identity Provider - Used to establish the identity of your user. In this project it is currently used to pull the JWT token to authorize the user, and track their shipments anonymously in the database. It is expected that you will eventually use your organizations IdP - which you can extend to automatically pull user claims (email, name, address)
- API Gateway - Manages your API that your client will use to make calls to your backend service, which will relay orders to YED
- Order Management Service - This is the core of your backend logic - This is where you will configure how your app will handle user requests and send them to YED. It also provides a way to abstract away the YED API secret from the client
- Order Database - Used to track the relationship between a user and their shipment IDs
- YED API - Your organizations instance of YED
- Email / SMS Notification - An example is included that can send an email alert to an admin if the amount of inventory remaining falls under a specified threshold
- YubiEnterprise Delivery
- YubiEnterprise API
- React.js
- Material UI
- AWS Amplify
- Formik
- This tutorial and this repository are good primers for how the Form and Order Flow were created for this site
This is an example of how you may give instructions on setting up your project locally. To get a local copy up and running follow these simple example steps.
- YubiEnterprise Delivery Instance
- For an API key contact your organization's Yubico Owner or your Yubico sales contact
- Ensure you also have the API URL for your instance of YED
- AWS Account
- The AWS CLI requires specific IAM permissions to perform various actions needed to deploy your application. Please ensure your AWS account has all the permissions listed in this guide
- Install the AWS CLI v2
- Download link here
- Ensure the CLI is configured to your AWS Account
- Install the AWS Amplify CLI
- Download link here
- Ensure you have configured the Amplify CLI (Instructions here)
- AWS SNS (Simple Notification Service) Instance
- Amplify is unable to create the SNS resource required to send alerts for low inventory. Follow these instructions to create an SNS resource:
- Open AWS SNS
- In the section labeled "Topics" click Create Topic
- Name the topic inv-monitor - Keep the default settings
- Once created go to "Subscriptions"
- Set protocol to Email, and on Endpoint enter the email address of your YED Admin who will receive inventory alerts
- Ensure that you confirm the email in your inbox to begin to receive alerts from AWS SNS
- You are now ready to send alerts through this application
- Before you exit, be sure to note your SNS topics ARN, as it will be used during the deployment step below
- Amplify is unable to create the SNS resource required to send alerts for low inventory. Follow these instructions to create an SNS resource:
- Clone the repo
git clone [email protected]:YubicoLabs/yed-self-service.git
- Install NPM packages
npm install
There are a few different options for creating your backend environment using Amplify. The following sections outline the steps for creating your environment. Below is an overview of the options
- Automatically Configure Your Amplify Environment - Single button offered by Amplify to build and configure your full environment
- Using This Repository to Deploy Your Amplify Environment - This is the recommended option - Clone this repo directly, and enter a few commands to deploy the environment using CloudFormation and to configure your application secret
If the Amplify CLI detects an Amplify project in your directory, you only need to run a few commands to deploy and configure the environment. This option has less overhead than the Manual option.
- Ensure that you have cloned this repository - Open the terminal in the root of your project directory and run the following command
amplify init
- Use the following values to initialize your Amplify environment
- Do you want to use an existing environment? No
- Environment Name: yeddev
- Default Editor: Make your personal selection
- Authentication Method: AWS Profile -> Select your personal profile
- Give the terminal a moment to initialize the project, there are more prompts
- Select Update Secret Values Now
- Select yedselfsvcex
- Update a secret
- YED_API_TOKEN
- Enter your API token from the YED console
- Select 'I'm done' and perform the same steps for the resource yedselfserviceinv
- yedselfserviceinv will also require a secret variable for the AWS SNS resource ARN - Please ensure you follow the steps in the prerequisites section to create your SNS service to get the ARN
- Select I'm done
- All that is left is to publish your Amplify Env using the following command
amplify push
- In this step you will be prompted to add your environment variables. Ensure you add environment variables for the -
- yedselfserviceinv - YED_API_URL: https://api.console.yubico.com/v1
- yedselfserviceinv - INV_THRESHOLD: 500 (or whatever number works for your inventory quantities)
- yedselfserviceex - YED_API_URL: https://api.console.yubico.com/v1
- yedselfserviceex - DEFAULT_PRODUCT_ID: 5
- If your initial build fails, run the amplify push command another time
- In this step you will be prompted to add your environment variables. Ensure you add environment variables for the -
- Your website is ready to use, now run the following command (in localhost)
npm start
- If you wish to deploy the application to the web run
amplify publish
This will give you a public facing URL to test in a live environment
Caution - If you receive a 403 Error while attempting to open your application, please see this section below
This Lambda resource (yedselfserviceex) is where your backend logic to make shipments will reside - This is important as this is where your application will be calling directly to the YED API to create, manage, and get orders (and perform other operations like address validation).
The current application does not have a corresponding endpoint to every operation in YED. If additional functionality is required, use the code as a template for calling the other YED endpoints
Where is my lambada logic? - You don't need to go into the Lambda resource directly to edit your lambda, it can be done directly from your project. The Lambda index can be found in the directory amplify > backend > function > yedselfsvcex > src > index.js
At the top of the file there are some definitions that are generated based on configurations you have made using the Amplify CLI. If your code isn't working for some reason, make sure that you followed the same naming convention that was used.
There are three tiers to the entire example
- Definition of variables
- Logic to call to YED or to Storage
- exports.handler which acts as the "main" whenever this function is called
As noted about it acts as the "main" of the application. It has four primary responsibilities
- Gets the Secret Variables from the AWS SSM
- Takes the JWT token passed by the user, and gets the user_sub. This will be used to identify the user
- Switch/Case that reacts to the particular operation + path called by the user
- Returns the response to the client
Every method essentially calls to the YED API in the same manner - The call is made and the data from the response is sent directly to the client.
There are some checks on top of some of the calls to check if the user has permission to CRUD to the shipment.
There is a 1:1 relationship between the operations + paths defined in exports,handler, and a method that calls to YED. There are a few helper methods if something needs to be done with the storage resource.
The second lambda function (yedselfserviceinv) introduces the functionality to alert an administrator if your YubiKey quantity falls below a specific threshold.
The current logic compares ALL the items of your inventory from a result of a GET /inventory API call. This lambda is also set to run once a day, and on each run will send alerts to a defined administrator indicating that there may be an item with low quantity in your YED inventory.
Where is my lambada logic? - You don't need to go into the Lambda resource directly to edit your lambda, it can be done directly from your project. The Lambda index can be found in the directory amplify > backend > function > yedselfserviceinv > src > index.js
At the top of the file there are some definitions that are generated based on configurations you have made using the Amplify CLI. If your code isn't working for some reason, make sure that you followed the same naming convention that was used.
As noted about it acts as the "main" of the application. It has four primary responsibilities
- Call to the YED API to get your full inventory
- Determine which inventory items have a "low" quantity (threshold is determined by your business requirements)
- Formats an email message based on the inventory amounts
- Sends an email to AWS SNS with the message noted
Below is an example of an email sent by the AWS SNS service. If you do not initially receive this email after a test run, or timed trigger, please check your Spam folder.
There are a few things that should be noted about the React App itself - While this tutorial is more focused on the big picture architecture, it is important to know how the front end is interacting with the backend to fully understand how YED is being used.
This is where you will find the majority of the logic needed for this application
- Components - If you are familiar with React you will expect to find the various high level pages in this area, the components will be broken down in more detail shortly
- Routes - These are the routes that are specific to the order form. This project has one major route schema in the high level app (Order route). Within this folders route folder you will find the definitions for how the routes are configured for each form step
- Store - This will be extremely to understand, so be sure you peek under the hood. This is the area that will persist data through a users experience. This allows a user to jump between form stages, as well as being used by the app to determine what the user is trying to do in the form (create or edit)
In this section we will walk through what each component is responsible for, and some details to note - For further detail please go into the component and read the comment details
- address - This is the form component that allows the user to input their shipping information. This is primarily built using Formik. There are some items in here that allow you to control the form schema such as field lengths. This component is not used directly by the flow, instead it is built into the delivery component
- confirmation - This is the page where the user gets an overview of their order before they submit it. There is logic in this page that switches the context between a user creating a new order, or editing an existing order
- delivery - This is where the user performs two actions: Sets their shipping information, and ensures that their shipping address is valid. Once a user fills out the form they submit the form, but instead of routing to the next page, the form calls to the YED API's /validate-address endpoint to ensure that Yubico can deliver to the address. If the address is not valid the shipment errors are returned back to the user to make the corrections, they will need to validate the address again before continuing.
- key-default - This page is just a loading screen that calls to the backend using the /defaultinventory logic. This essentially preselects a key for your user, and moves them to the Delivery Component. Every component has a check, if a key has not been set, the user will be redirected to this component for a key to be chosen for them. You can extend this component to act as a catalog for your user to select the key they want
- order-history - This shows all of a users personal orders. If a order is below shipping state 10, then they will be able to edit and delete the order. Otherwise the buttons will disappear. When tracking information becomes available it will be displayed to the user
- order-stepper - This controls the form stepper you see at the top of the flow. It highlights what stage the user is in. Links were added to the delivery and order history step to allow a user to quickly create a new order, or see their previous order
In the code you may see references to inv-config. This was created to help your organization easily manage details that you want to use for your catalog. You can set your own custom image to be displayed, and your own custom description to guide your users into selecting the correct key. For this example there is only information about the YubiKey 5Ci, but you can follow the same schema for other keys (this is based on your requirements)
You might notice that the rendering components don't contain any actual words, but instead are filled with items that look like {t["something"]}. This is used to act as an easy way to consistently configure different languages in your application. The English values can be found in public > i18n > en-US.json
Because this application is meant to act as a demo, there are a few items that need to be considered to make your deployment "production ready".
his application will allow a user to order as many keys as they desire. Additional logic will need to be built in to limit the number of orders based on your requirements
This includes swapping the system out to use your identity provider, secrets management in AWS Lambda, and other controls used by your organization
You can extend this application to allow it to automatically pull user claims through an ID token, or a user service
Right now the application will default to the Yubikey 5Ci. You can extend this application’s flow to allow a user to select a key based on your YED inventory
If your application is purposed for external end users then your internal CX team needs to be prepared to handle YED/YubiKey specific inquiries. Either an internal team should be established and trained to handle these items OR you can determine if Yubico Professional Services is the preferred option.
The current demo is configured for a single region PO. You will need to use the proper API token for the user’s region, e.g. North America / Canada is one region, EMEA is a different region and each have their own associated API token.
More information can be found here
It should be noted that orders made through the YED API are made directly on your production inventory. YED does not currently support "sandbox" environments with fake data/inventory. During testing and development it is crucial that you not only delete orders directly from this application, but you must login to the YED Console to verify the order was removed, and to delete any lingering test shipments - Otherwise, your order will be processed and a key from your inventory will be shipped.
Orders are not processed for shipment until 3AM PST - So ensure your developers/testers are instructed to delete their shipments prior to closing their work day. This time is centrally configured across YED and cannot be edited.
It's been noted that the initial build will occasionally fail if a secret value was not provided to the service. If you get an error on your initial run, try running the amplify push command one more time. If the issue persists then please open an Issue on this repository so that the cause can be investigated.
Occasionally after a deployment you may receive a 403 Error (Access Denied) when attempting to use your application.
If this occurs, please follow the steps below
- In AWS go to the Amplify Portal - Then find your Amplify App
- In the settings panel on the side, choose Rewrites and redirects
- Click on the Edit button
- Create a new rule with the following criteria
- Click Save
- Test your application
If organizations are shipping keys to both the US/Canada and to EMEA, two API tokens are required, as both regions are treated as different organizations.
A user will not be able to perform operations in a EU YED instance while logged in to their US/CAN instance (the same is true of the inverse).
Before implementing a solution you should consider how many YED organizations your company will be utilizing, and how to guide your users to the appropriate portal with the correct API key for their region.
This site will be updated in the future with Multi-Region PO Support.
More information on this can be found here
This will occur if you initiated your environment, but did not push/publish - Make sure you call
amplify push
or
amplify publish
aws.exports.js should automatically be generated
There might be two reasons for this - You might not have configured your API secret, or your YED API URL is incorrect. See this section on configuring your Environment and Secret Variables
If you receive an error indicating that a user pool does not exist (when creating an account or logging in), ensure that you go to your aws-exports.js file in your src folder. Validate that the cognito identifiers match the identifiers in the AWS Console
This is going to be your most annoying error, I would suggest not tweaking the API very often, but if it needs to be done then ensure you do the following steps
First off, what is happening? Every time you make a local change to the API, an automatically created file is altered in amplify > backend > api > yedselfsvcex > yedselfsvcex-cloudformation-template.json
There are special configurations in this file that allow the resource to talk to Cognito, that seem to be overridden every time the API is updated. Luckily the template that we have provided will create the API resource, with the needed parameters to take in Auth values, but again these get overridden.
To troubleshoot ensure the following are in the file listed above
"Parameters": {
...
"AuthCognitoUserPoolId": {
"Type": "String",
"Description": "The id of an existing User Pool to connect. If this is changed, a user pool will not be created for you.",
"Default": "NONE"
}
}
...
"Resources": {
"paths": {
"/your-new-path": {
...
"parameters": [
...,
{
"name": "Authorization",
"in": "header",
"required": false,
"type": "string"
}
],
"security": [
{
"Cognito": []
}
],
...
},
"/your-new-path/{proxy+}": {
...
"parameters": [
...,
{
"name": "Authorization",
"in": "header",
"required": false,
"type": "string"
}
],
"security": [
{
"Cognito": []
}
],
},
},
"securityDefinitions": {
"Cognito": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"x-amazon-apigateway-authtype": "cognito_user_pools",
"x-amazon-apigateway-authorizer": {
"type": "cognito_user_pools",
"providerARNs": [
{
"Fn::Join": [
"",
[
"arn:aws:cognito-idp:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":userpool/",
{
"Ref": "AuthCognitoUserPoolId"
}
]
]
}
]
}
}
},
}
If you ever get lost, or want to revert back to before you made a breaking change then come back to this file, and replace it with your changes.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
Distributed under the Apache-2.0 License. See LICENSE
for more information.
Project Link: https://github.com/YubicoLabs/yed-self-service