This commit is contained in:
caishi 2023-07-05 16:43:45 +08:00
parent 7f0a14ee07
commit 8679343ab4
622 changed files with 7730 additions and 22718 deletions

108
README.md
View File

@ -1,45 +1,93 @@
# Website # 确实开源帮助中心
This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. ## 贡献文档方式
#### 1.复刻主仓库
![](https://gitlink.org.cn/api/attachments/412462)
<br/>
## Installation #### 2.进入复刻仓库编辑文档
![](https://gitlink.org.cn/api/attachments/412465)
```console <br/>
npm install
可采用如下两种方式编辑:
* 克隆复刻仓库到本地后,在**gitlink_help_center/docs**文件夹下新建文件夹或markdown文档依次执行
```bash
git add <新增文件>
git commit <新增文件> -m "提交信息"
git push
```
* 在gitlink代码仓库页面进行编辑然后点击“提交变更”
![](https://gitlink.org.cn/api/attachments/412426)
<br/>
#### 3.向主仓提交合并请求
![](https://gitlink.org.cn/api/attachments/412466)
<br/>
## 页面目录——仓库目录示意图
<br/>
1.如下图左边为帮助中心侧边栏一级目录展示效果,右边为代码仓库文件夹目录:
![](https://gitlink.org.cn/api/attachments/412473)
<br/>
2.如下图左边为帮助中心侧边栏点击一级目录“Test1”后展开效果右边为点击代码仓库文件夹“test1”后md文件目录
![](https://gitlink.org.cn/api/attachments/412474)
## 创建markdown文档
* 创建第一篇文档
在**docs/test1**目录下创建hello.md
```bash
# Hello
This is my **first document**!
```
在一级标题中:#与标题内容间需要入空格(# Hello)
* 配置侧边栏
```bash
---
sidebar_label: 'Hi!' <!--定义侧边栏标签名称-->
sidebar_position: 3 <!--定义侧边栏层级位置-->
---
# Hello
This is my **first document**!
``` ```
## Local Development <br/>
```console * 链接
npm run dev
支持使用 url 路径或相对文件路径的常规 Markdown 链接
```bash
git操作 [git](/git).
```
```
git操作 [git](./git.md).
``` ```
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. <br/>
## Build * 图片
支持常规markdown图片在**static/img/gitlink_logo.png**中添加一个图像.png并在Markdown中显示它
```bash
![gitlink logo](/img/gitlink_logo.png)
```console
npm run build
``` ```
This command generates static content into the `build` directory and can be served using any static contents hosting service. ## 前端build成中文 i18n中可编辑对应中文内容
npm run build -- --locale zh-CN
启动 npm run serve
## Deployment
This website is deployed on render.com
## Contributing
Thanks for taking the time to contribute! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Any contributions you make will benefit everybody and are appreciated.
Please try to create bug reports that are:
- _Reproducible._ Include steps to reproduce the problem.
- _Specific._ Include as much detail as possible: which version, what environment, etc.
- _Unique._ Do not duplicate existing opened issues.
- _Scoped to a Single Bug._ One bug per report.
## Community
- [Discord](https://discord.gg/uyb7pYt4Pa) (For live discussion with the Community and BoxyHQ team)
- [Twitter](https://twitter.com/BoxyHQ) (Get the news fast)

View File

@ -1,30 +0,0 @@
---
slug: enterprise-readiness-made-simple
title: Enterprise Readiness made simple
author: Deepak Prabhakara
author_title: Co-founder & CEO @BoxyHQ
author_url: https://github.com/deepakprabhakara
author_image_url: https://boxyhq.com/img/team/deepak.jpg
tags_disabled: [enterprise-readiness]
image: /img/blog/xavi-cabrera-kn-UmDZQDjM-unsplash.jpg
---
I love Lego (don't we all), probably a little more than my kids. It invokes a builder's instinct. I feel the same way with code as well. When I started my career in the early 2000s building software was complex. You had to visit datacenters and set up your servers to even get started, it was the age of the ASPs; the predecessor of SaaS.
![Lego](/img/blog/xavi-cabrera-kn-UmDZQDjM-unsplash.jpg)
<div style={{fontSize: "10px", marginTop: "-20px", paddingBottom: "20px"}}>Photo by <a href="https://unsplash.com/@xavi_cabrera?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Xavi Cabrera</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></div>
Then came the Cloud; infrastructure at the click of a button. Nothing short of magic! And then over the last decade or so the Cloud enabled a lot of the re-usable services to be packaged up as APIs; enter the API Economy. If you need audio or video in your app, dial the Twilio API. If you need payments, cash in on the Stripe API. If you need authentication, sign in to the Auth0 API. The list is endless (also I ran out of puns).
Coding today is like assembling lego blocks thanks to these APIs and developers love it. There is no need to re-invent these blocks in every startup, its much better to outsource the non-core stuff.
I have spent a significant part of my career building products that were sold to the Enterprise. I have helped build out numerous Compliance and Security features, all essential to make the sale but still a big distraction from the core product. I have personally experienced the pain of balancing these Enterprise features with other core features. My co-founder Sama has spent a significant part of his career helping startups accelerate and connecting them to Enterprises. He has seen the pain of startups not being ready to sell to the Enterprise despite having fantastic products.
We both looked at all this and questioned ourselves: What if Enterprise Readiness had an API? What would that look like? How would it work? Could we create a product that will help developers at startups address the hard problems of enterprise readiness, data security, and compliance?
And we went ahead and started BoxyHQ to build this vision. BoxyHQ is a commercial open source software that helps you add enterprise features to your app in just a few lines of code. We want to make enterprise features simple, that's it. That's our focus for the next few years. We want to solve the hard things for you and give you back valuable time to focus on your core products.
If you are selling to the Enterprise, come and say hello. We'd love to give you early access and help you with other aspects of Enterprise sales as well.
_"Enterprise sales is fun!"_ - said no one ever

View File

@ -1,26 +0,0 @@
---
slug: the-ikea-effect-in-software-engineering
title: The IKEA effect in Software Engineering
author: Deepak Prabhakara
author_title: Co-founder & CEO @BoxyHQ
author_url: https://github.com/deepakprabhakara
author_image_url: https://boxyhq.com/img/team/deepak.jpg
tags_disabled: [enterprise-readiness, ikea-effect]
image: /img/blog/jay-wennington-BdeMttZx6Fs-unsplash.jpg
---
I recently had to revamp my home office setup and decided to make a trip to my closest IKEA. The wide range of choices of desks in Micke, Malm, Brusali, Alex, and Bekant was only the beginning of the journey. I knew I had to head back home with the desk, find a good place to unpack the unit, find my screwdrivers, hammer, alan keys, and finally dedicate a few hours of labor to assemble everything. I enjoy the process but it is not devoid of frustrations. In the end, I now have a desk I value more because of the labor I put into it.
![IKEA Assembly](/img/blog/jay-wennington-BdeMttZx6Fs-unsplash.jpg)
<div style={{fontSize: "10px", marginTop: "-20px", paddingBottom: "20px"}}>Photo by <a href="https://unsplash.com/@jaywennington?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Jay Wennington</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></div>
This is the IKEA effect, a cognitive bias where we place a disproportionately high value on products that we have partially created. This makes people value things they had a part in building than the ones they didnt. We face this challenge as developers every day, the classic build vs buy decisions when we build software. Wed love to build everything ourselves and in an ideal world this would be possible but we need to juggle business requirements, limited resources, and deadlines. The challenge is always in striking the right balance between building what is core to the business and finding ways to offload non-core tasks.
Just like how an IKEA desk is pretty useless if half-assembled, a feature we set out to build is pretty useless if we end up getting caught up in the implementation details and are unable to see it through. When we set out to build BoxyHQ we constantly heard about the challenges of enterprise readiness from startups. They have to support a range of compliance, security, and governance requirements from their enterprise customers and their developers end up spending 30-40% of their time bogged down in the details of implementation. These startups build teams to work on cool and exciting things that are core to their business but the reality is that non-core features start competing for attention. As a result these non-core features also end up being just good enough to check some boxes and never quite get as innovative as they can get.
We have seen software eat the world. This has led to more surface area for security exploits and leaks which in turn is driving a broader awareness of security topics in enterprises. Security has become the top priority for all companies now and is no longer seen as the sole responsibility of the CISOs team. This means a shift-left trend in compliance and data security for developers and we are taking a new approach at BoxyHQ to solve this problem. BoxyHQ provides developers with non-core building blocks (described above) that integrate easily with their products. Simple self-hosted services and APIs that they can pull into their existing technology stack. Developers no longer have to worry about correctly implementing SAML login flows, building and scaling a robust audit logs service, or figuring out the best encryption technique to safeguard PII data.
BoxyHQ will build IKEA desks for all our customers so they dont have to. Just sit at your pre-assembled desk and continue working on cool things that you set out to build in the first place.
PS: Announcing SAML Jackson (who doesnt like a bit of Pulp Fiction), a SAML SSO service that works seamlessly as an OAuth 2.0 flow and abstracts away the tedious XML bits of the SAML protocol. Check out <https://github.com/boxyhq/jackson> and the demo at <https://github.com/boxyhq/jackson-examples/tree/main/apps/next-auth>. If SAML SSO is not relevant to you at this moment dont forget to bookmark us and check back again. We are building a **"DevSecMesh"** over time so you can expect a lot of exciting features in the coming months.

View File

@ -1,51 +0,0 @@
---
slug: how-early-stage-startups-should-sell-to-enterprises
title: How early-stage startups should sell to enterprises
author: Sama - Carlos Samame
author_title: Co-founder & COO @BoxyHQ
author_url: https://www.linkedin.com/in/samame/
author_image_url: https://boxyhq.com/img/team/sama.jpg
tags_disabled:
[enterprise-readiness, startups, enterprises, corporates, sales, founder]
image: /img/blog/mulyadi-dDlvuSKUDZM-unsplash.jpg
---
You have decided to quit your job and start something on your own, congratulations! Welcome to a new way of living, as our little green friend told us some years ago “do or do not, there is no try”. Resilience and perseverance will be your two new best friends now; we all know that starting a company is not hard at all, but something hard at the beginning of the journey is finding product-market fit, especially if you are selling to enterprises (if you are an open-source founder, make sure you prioritize project-community fit first).
![Star Wars Lego](/img/blog/mulyadi-dDlvuSKUDZM-unsplash.jpg)
<div style={{fontSize: "10px", marginTop: "-20px", paddingBottom: "20px"}}>Photo by <a href="https://unsplash.com/@mullyadii?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Mulyadi</a> on <a href="https://unsplash.com/?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></div>
Having worked for companies like Amazon Web Services & O2-Telefónica connecting enterprises with startups around the world, there are some best practices that I would like to share. We just have to remember that enterprises are conformed by groups of people, and every person is different. So please, dont expect the secret sauce or the “right way” to do it. Even though each case will be unique, always look for the patterns of what works best for your company. I like to use the process DIA (Discover Imagine Act) to overcome challenges, so let me take you through it.
## Discover
First, you have to understand the problem that you are solving. Is it really a problem or are you just in love with a good idea? Asking many times “why” will help you understand the hidden problem (the real one), and it will allow you to understand the needs that the enterprise has. Once you understand the needs of the enterprise, it is time to focus on understanding the needs of your user and your buyer, most of the time these are two different stakeholders within the organization. Is the need of the user a priority for the buyer, or is it just a distraction? You will see that in some organizations they are aligned and in others, they cannot even stand each other; so you must take the time to understand the dynamics between these stakeholders, and the culture of the enterprise itself (how they make decisions).
Sales cycles are indeed long if you look at them from a startups point of view. Remember that this is the standard speed for enterprises. Startups speak AGILE and Enterprises speak SECURITY, and for many people, these two terms cant go together (dont worry, we are proving them wrong @BoxyHQ). Enterprises have got plenty of software they already depend on that needs to work with whatever your product can do for them. Their technology is usually old, I have seen many enterprises with Frankensteins, they think they need to create a third leg to run faster and they end up building unnecessary technologies that affect the quality and the speed of their solutions. You need to focus on the cost of the enterprise (time and resources) to integrate your solution, and to do that you have to make sure that the impact is big enough to be worth it.
To make sure the impact you are generating is relevant to the enterprises focus on a few potential customers, as Jason Lemkin mentions “Almost all big companies now have innovation departments of some sort, as do many divisions and groups. The general idea is to bring in 12 new vendors a year that dont risk taking the core business down but could have a material impact on the bottom line. If you truly can change the way they do business, you can often get a meeting. Ive done this in both my start-ups in the earliest days with 10+ F500 companies in the first 90 days.”
This Discovery stage is also perfect to understand what your solution needs to have to be compliant; security is key for them. Startups that are not compliant with the enterprises requirements could delay the sales cycle, or what is worse they could lose the deal.
## Imagine
With all the information that you now have, it is time to visualize the future. Does your solution need some changes? Do you need new features to be compliant? Or could it be that maybe the enterprise doesnt need all the features that you had in mind? Take some time to readjust your product as necessary, including how you are going to package it and how you are going to distribute it. Apply all the insights collected in the Discovery stage to test, measure, and iterate.
A common error that I have seen from startups is not focusing on selecting the right partners, and just moving forward with inbound opportunities. Some of them could be good but overall is a distraction to say yes to anyone that wants to resell your solution, you need to plan ahead.
Talking about planning, once you know who your internal sponsor is you need to facilitate the job for them. That is the person that will take your fights internally, so make sure you are giving them the right tools. If they see two concerns about integrating your solution, you should think of additional concerns and imagine how to mitigate each of them. You need to train your sponsor for unexpected scenarios that the decision committee will bring. Usually, enterprises ask for a “request for proposal” (RFP), the more you know about it, the better you will be prepared.
As an imagination exercise, I love Amazons Working Backwards process and the PRFAQ - you can learn more about it [here](https://www.linkedin.com/pulse/applying-amazons-working-backwards-process-leaders-ian-mcallister/). It is helpful to visualize the impact you aim to have and work backwards from your customer needs to create a solution. It is similar to the Design Thinking process, but the PRFAQ adds the manifestation piece.
## Act
Now is the time to act! But be careful, another mistake that many startups make is not executing at the right time, they spend too much time thinking (doing research) or they reach out to enterprises before making sure they are ready, burning your bridges. Timing is going to be key for you.
They need to trust you and your solution, every contact point is an opportunity for them to trust you, so make sure to go to these meetings well prepared, doing the right questions but at the same time with some insights on the market, their competitors, technologies, etc. You should be an expert in your niche but at the same time, you should be smart enough to listen. The more you know about them, the better you can adapt your solution and at the same time influence them.
Make sure you have the right metrics for your success cases, it doesnt matter if you were selling to SMEs before or if you already had a few Proof of Concepts (POCs) with enterprises. Large companies dont want to feel they are a guinea pig, if you did a POC and you didnt move forward afterward most executives will not see it as unsuccessful, period.
Be patient, agile enterprises could spend between 6 to 12 months in conversations before signing an agreement, but many could take years (Ive seen one company spending 3+ years). While you are waiting, make sure you are at the top of their mind, always adding value, not asking for unnecessary coffees. Key people will resign, will get fired, will change roles, so make sure you find a way to navigate these transitions, you dont want to start from scratch.
Each enterprise is a different world, and there are more things you will find out while spending time with them, but I hope you find this blog post insightful. If you have any comments or questions you would like to discuss, please feel free to reach out. We have free Enterprise-Ready office hours to help startups be compliant and accelerate their sales cycle with enterprises.

View File

@ -1,120 +0,0 @@
---
slug: benchmarking-fluentbit-with-clickhouse
title: Benchmarking fluent-bit with Clickhouse
author: Utkarsh Mehta
author_title: Senior Software Engineer (Open Source Dev Tools) @BoxyHQ
author_url: https://www.linkedin.com/in/utkarsh-mehta2612/
author_image_url: https://boxyhq.com/img/team/utkarsh.jpg
tags_disabled:
[
enterprise-readiness,
engineering,
audit-logs,
hermes,
fluent-bit,
clickhouse,
benchmarking,
research,
load-testing,
]
image: /img/blog/fluentbit-clickhouse.png
---
One of our products, [Hermes](https://github.com/boxyhq/hermes) is an audit logs service. Currently, Hermes is in the prototype phase and uses a [Go](https://go.dev/) REST API server to ingest audit logs and send them to [Loki](https://grafana.com/oss/loki/).
We were trying out different databases, ingesters & tools to see which are best suited for Hermes and should be able to scale with high traffic without losing a single audit log & which can search through high amount data efficiently.
![Title Image](/img/blog/fluentbit-clickhouse.png)
We decided to benchmark different combinations of ingesters (Vector, Fluentd, Fluent-Bit, etc.) and storage & query tools (Mongodb, Clickhouse, Elasticsearch, etc.).
The first round of benchmarks will be lightweight and extensive benchmarks will follow later once we pick the right tools for Hermes.
## Hardware Configuration
The following tests and benchmarks have been performed on a MacBook Pro (14-inch, 2021) with Apple M1 Pro and 16 GB RAM, the tools to be tested were dockerized with docker desktop running with 4 GB Memory, 4 CPUs & 1 GB Swap.
> Fluent Bit is a super-fast, lightweight, highly scalable logging and metrics processor and forwarder.
> It is the preferred choice for cloud and containerized environments.
> Source: [fluent-bit website](https://fluentbit.io/)
> Clickhouse is the fastest OLAP database on earth. ClickHouse works 1001000x faster than traditional approaches.
> Companies like Uber, Cloudflare, Spotify, and eBay use Clickhouse.
> Source: [Clickhouse website](https://clickhouse.com/)
So few pointers before we go ahead,
1. Fluent-bit is fast at ingesting logs/data, processing them, and sending them to a destination.
2. Clickhouse is efficient at handling and querying data.
3. Fluent-bit does not support Clickhouse by default.
4. The fluent-bit ecosystem lets users write their plugins in Golang and add additional support required.
5. For faster querying in Clickhouse, an efficient table schema with indexes, compression, etc. should be established.
## Clickhouse plugin for fluent-bit
<!-- ![Funny Gif](https://media0.giphy.com/media/bAplZhiLAsNnG/giphy.webp?cid=dda24d507bdfdacf288d461758839009285c1ed114150484&rid=giphy.webp&ct=g) -->
I developed a fluent-bit output [plugin](https://github.com/boxyhq/fluent-bit-clickhouse) for Clickhouse.
## Fluent-Bit config
![Fluent-bit Configuration](/img/blog/fluentbit-config.png)
This config makes fluent-bit ingest data via HTTP server listening on port 8888 and sends the data to Clickhouse with configuration stated.
## Clickhouse config
<!-- ![Funny Gif](https://media0.giphy.com/media/aS8ypUweGOXMA/200w.webp?cid=dda24d5064d326145a245fce898f7775bc4b7e4ce5f8f178&rid=200w.webp&ct=g) -->
I ramped up the number of concurrent requests/queries by modifying the config.xml. After multiple tests, I finalized the following config.
![Clickhouse Configuration](/img/blog/clickhouse-config.png)
## Load testing tool
<!-- ![Funny Gif](https://media1.giphy.com/media/B6SyssSlTgPXq/200w.webp?cid=dda24d50edfaf581e3165a3d10a7dd26c246ebb459fcebb5&rid=200w.webp&ct=g) -->
I developed a load testing tool with Node.js that can be used to benchmark REST API-based endpoints of Fluent-bit.
[API Benchmarking](https://github.com/boxyhq/api-benchmarking)
Another tool to load test is the querying part of Clickhouse.
[Clickhouse Load Testing](https://github.com/boxyhq/clickhouse-db-load-testing)
## The results
These results are dependent on the ram allocated to the Docker engine, in my case, it's(4 GiBs).
### Ingester
![Ingester results](/img/blog/results-ingester.png)
### Query
![Queryer result](/img/blog/results-query.png)
## Conclusion
### Ingester
1. Fluent-bit can handle loads up to 2000 req/sec but in the case of bigger batches, the speed goes down drastically. (200 X 10) & (300 X 10)
2. In the case of long-term light batches, Fluent-bit performs consistently. (10 X 1000)
3. Fluent-bit performs at average speeds in the case of average loads (50 X 50).
### Query
1. Clickhouse shows the best req/sec performance with an average load (50 X 50).
2. Also, Clickhouse's performance was pretty satisfactory for all the different variations of records in DB. (1.1 mils, 50k, 25k, 10k, 2k & 1k).
3. Clickhouse was able to manage short-term high loads and long-term light loads efficiently. (100 X 10) and (10 X 5000).
We will be posting more blogs regarding benchmarks, tools, etc., as we go on to build Hermes and many other dev tools. Please leave comments below.
Thank you!

View File

@ -1,459 +0,0 @@
---
slug: add-saml-sso-to-node-express-app
title: How to add SAML Single Sign On to an Express app
author: Kiran K
author_title: Senior Developer @BoxyHQ
author_url: https://twitter.com/tokirankrishnan
author_image_url: https://boxyhq.com/img/team/kiran.jpg
tags_disabled:
[enterprise-readiness, engineering, saml, saml-jackson, integrations, sso]
---
In this article, you'll learn how add SAML SSO login to an Express.js app. You'll use [SAML Jackson](https://boxyhq.com/docs/jackson/overview) with [Auth0](https://auth0.com/single-sign-on) to authenticate users and protect routes.
You can also access the full code at the [GitHub repository](https://github.com/boxyhq/express-jackson-auth0-demo).
Lets get started!
## Prerequisites
To follow along with this article, youll need the following:
- Node.js installed on your computer
- Basic knowledge about Node.js and Express.js
## Setting up the database
For our article, well create a free [Postgres database on Heroku](https://devcenter.heroku.com/articles/heroku-postgresql) instead of setting up a local Postgres server.
- Go to [Heroku signup page](https://signup.heroku.com/login), then create an account.
- Go to [Apps](https://dashboard.heroku.com/apps) and click **Create new app**.
- Give your app a name, and click the **Create app** button.
- Go to the **Resources** tab.
- Choose the **Heroku Postgres** from the Add-ons search box, and click **Submit Order Form**.
- Click the **Heroku Postgres** and select **Settings** tab.
- Click the **View Credentials** button and copy **URI**.
Now you have created a free PostgreSQL database and copied the database connection URI. We'll need the connection URI later.
## Configure the Identity Provider
We'll use the Auth0 as our identity provider. An Identity Provider (IdP) is a service that manage user accounts for your app.
- First, go to the [Auth0 signup page](https://auth0.com/signup), then create an account.
- Go to [Dashboard > Applications > Applications](https://manage.auth0.com/dashboard/).
- Click the **Create Application** button.
- Give your new application a name.
- Choose **Regular Web Applications** as an application type and the click **Create**.
- Go to the app you created, then click the **Addons** tab.
- In the **SAML2 Web App** box, click the slider to enable the Addon.
- Go to the **Usage** tab and download the **Identity Provider Metadata**.
- Go to the **Settings** tab and make below changes.
- Add `http://localhost:3000/sso/acs` as your **Application Callback URL** that receives the SAML response.
- Paste the following JSON for **Settings**, then click **Enable** button.
```json
{
"audience": "https://saml.boxyhq.com",
"mappings": {
"id": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
"firstName": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
"lastName": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
}
}
```
`audience` is just an identifier to validate the SAML audience. [More info](https://boxyhq.com/docs/jackson/deploy/env-variables#saml_audience).
Auth0 provides database connections to authenticate users with an email/username and password. These credentials are securely stored in the Auth0 user store.
Let's create one so that our users can register or login.
- Go to [Auth0 Dashboard > Authentication > Database](https://manage.auth0.com/dashboard/).
- Click **Create DB Connection** - [Auth0 Create DB Document](https://auth0.com/docs/authenticate/database-connections/custom-db/create-db-connection)
- Give your connection a name, then click **Create**.
- Go to the **Applications** tab and enable the application you just created.
Now we've everything ready, let's move to the next step.
## Getting started
Launch a terminal and clone the GitHub repo:
```bash
git clone https://github.com/devkiran/express-saml.git
```
```bash
cd express-saml
```
Now, install the dependencies:
```bash
npm install
```
Add the environment variables:
```bash
cp .env.example .env
```
Update the `DATABASE_URL` variable with your Heroku Postgres database connection URI.
Append `?sslmode=no-verify` to your database connection URI otherwise Heroku won't allow you to link to the database. This is a Heroku specific configuration.
For example `postgres://hcydrtasctfyth:fe001b264322d6cf794@ec2-1-2-3-4.compute-1.amazonaws.com:5432/demo?sslmode=no-verify`
## About the Express app
This is a simple express.js app created using `express-generator`. You can use any express.js app if you want.
Our express.js app has only 2 routes.
- `GET /` render a home page
- `GET /dashboard` render a dashboard
So, what's the plan? We'll add SAML SSO login (via Auth0) to our express.js app so that only authenticated users can access the `/dashboard`.
## Install SAML Jackson
Run the following command to install the latest version of the SAML Jackson.
```bash
npm i --save @boxyhq/saml-jackson
```
Once you installed Jackson, let's initialize it.
Add the following code to the `routes/index.js`.
```javascript
// routes/index.js
...
let apiController;
let oauthController;
const jacksonOptions = {
externalUrl: process.env.APP_URL,
samlAudience: process.env.SAML_AUDIENCE,
samlPath: '/sso/acs',
db: {
engine: 'sql',
type: 'postgres',
url: process.env.DATABASE_URL,
},
};
(async function init() {
const jackson = await require('@boxyhq/saml-jackson').controllers(jacksonOptions);
apiController = jackson.apiController;
oauthController = jackson.oauthController;
})();
```
## Setting up Express.js routes
### Add SAML Metadata
The first route you'll create is the `GET /config` one. This route will display a form with following fields:
- `Metadata`: Enter the XML Metadata content you've downloaded from IdP.
- `Tenant`: Jackson supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id.
- `Product`: Jackson support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using.
```javascript
// routes/index.js
router.get('/config', async (req, res) => {
res.render('config');
});
```
Add a view to display the form.
```html
<!-- views/config.ejs -->
<!DOCTYPE html>
<html>
<head>
<title>SAML Config</title>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
crossorigin="anonymous"
/>
<link rel="stylesheet" href="/stylesheets/style.css" />
</head>
<body>
<h1>SAML Config</h1>
<p>Add SAML Metadata.</p>
<form action="/config" method="POST">
<div class="form-group">
<label for="tenant">Tenant</label>
<input
type="text"
name="tenant"
id="tenant"
class="form-control col-md-6"
required="required"
/>
</div>
<div class="form-group">
<label for="product">Product</label>
<input
type="text"
name="product"
id="product"
class="form-control col-md-6"
required="required"
/>
</div>
<div class="form-group">
<label for="rawMetadata">Metadata (Raw XML)</label>
<textarea
name="rawMetadata"
id="rawMetadata"
cols="30"
rows="10"
class="form-control col-md-6"
required="required"
></textarea>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</body>
</html>
```
Now let's add another route `POST /config` that will store the form data by calling the SAML Jackson config API.
This step is the equivalent of setting an OAuth 2.0 app and generating a client ID and client secret that will be used in the login flow.
```javascript
// routes/index.js
router.post('/config', async (req, res, next) => {
const { rawMetadata, tenant, product } = req.body;
const defaultRedirectUrl = 'http://localhost:3000/sso/callback';
const redirectUrl = '["http://localhost:3000/*"]';
try {
await apiController.config({
rawMetadata,
tenant,
product,
defaultRedirectUrl,
redirectUrl,
});
res.redirect('/config');
} catch (err) {
next(err);
}
});
```
There are a few important things to note in the code above.
`defaultRedirectUrl` holds the redirect URL to use in the IdP login flow. Jackson will call this URL after completing an IdP login flow.
`redirectUrl` holds an array containing a list of allowed redirect URLs. Jackson will disallow any redirects that are not on this list.
Next, let's start the express app. The app starts a server and listens on port 3000 (by default) for connections.
```bash
npm start
```
Now, let's visit [http://localhost:3000/config](http://localhost:3000/config), you should see the page with a form.
![SAML Config](/img/blog/add-saml-sso-to-node-express-app/add-saml-config-form.png)
Here you can add the metadata you've downloaded from Auth0. Fill out the form with a Tenant, Product, and paste the metadata XML content as it is.
I'll use 'boxyhq.com' for tenant and 'crm' for product.
The response returns a JSON with `client_id` and `client_secret` that can be stored against your tenant and product for a more secure OAuth 2.0 flow.
If you do not want to store the `client_id` and `client_secret` you can alternatively use `client_id=tenant=<tenantID>&product=<productID>` and any arbitrary value for `client_secret` when setting up the OAuth 2.0 flow.
### Redirect the users to IdP
Now you have added the SAML metadata, you'll need a route to redirect the users to IdP to start the SAML authentication.
Let's add a new route `GET /sso/authorize`.
Don't forget to change the values of the tenant and product in the code.
```javascript
// routes/index.js
router.get('/sso/authorize', async (req, res, next) => {
try {
const tenant = 'boxyhq.com';
const product = 'crm';
const body = {
response_type: 'code',
client_id: `tenant=${tenant}&product=${product}`,
redirect_uri: 'http://localhost:3000/sso/callback',
state: 'a-random-state-value',
};
const { redirect_url } = await oauthController.authorize(body);
res.redirect(redirect_url);
} catch (err) {
next(err);
}
});
```
`oauthController.authorize()` will returns a `redirect_url`. You should redirect the users to this `redirect_url` to start the IdP authentication flow.
### Handle the SAML Response from IdP
This route becomes the Assertion Consumer Service (ACS) URL of your app. The ACS URL tells your IdP where to POST its SAML Response after authenticating a user.
The SAML Response contains 2 fields: `SAMLResponse` and `RelayState`.
```javascript
// routes/index.js
router.post('/sso/acs', async (req, res, next) => {
try {
const { SAMLResponse, RelayState } = req.body;
const body = {
SAMLResponse,
RelayState,
};
const { redirect_url } = await oauthController.samlResponse(body);
res.redirect(redirect_url);
} catch (err) {
next(err);
}
});
```
Call to the method `oauthController.samlResponse()` will returns a `redirect_url`. You should redirect the users to this `redirect_url`. The query parameters will include the `code` and `state` parameters.
### Code exchange
Now exchange the `code` for a `token`. The `token` is required to access the user profile.
Let's create a new route `GET /sso/callback` to handle the callback.
```javascript
// routes/index.js
router.get('/sso/callback', async (req, res, next) => {
const { code } = req.query;
const tenant = 'boxyhq.com';
const product = 'crm';
const body = {
code,
client_id: `tenant=${tenant}&product=${product}`,
client_secret: 'client_secret',
};
try {
// Get the access token
const { access_token } = await oauthController.token(body);
// Get the user information
const profile = await oauthController.userInfo(access_token);
// Add the profile to the express session
req.session.profile = profile;
res.redirect('/dashboard');
} catch (err) {
next(err);
}
});
```
In the above code, replace the value for `tenant` and `product` with yours.
### Protect the dashboard
Now is the time to fix our `GET /dashboard` route so that only authenticated users can access it.
Let's fix it by adding a condition to check if the `profile` exists in the session.
If `profile` is `undefined`, redirect the users back to the `/` otherwise display the profile on the dashboard.
Replace the `GET /dashboard` route with the below code.
```javascript
// routes/index.js
router.get('/dashboard', function (req, res, next) {
const { profile } = req.session;
if (profile === undefined) {
return res.redirect('/');
}
// Pass the profile to the view
res.render('dashboard', {
profile,
});
});
```
Replace the `views/dashboard.ejs` view with the below code.
```html
<!-- views/dashboard.ejs -->
<!DOCTYPE html>
<html>
<head>
<title>Dashboard</title>
<link rel="stylesheet" href="/stylesheets/style.css" />
</head>
<body>
<h1>Dashboard</h1>
<p>Only authenticated users should access this page.</p>
<p>Id - <%= profile.id %></p>
<p>Email - <%= profile.email %></p>
</body>
</html>
```
From the command line, let's restart the express app then visit the authorize the URL [http://localhost:3000/sso/authorize](http://localhost:3000/sso/authorize).
If you've configured everything okay, it should redirect you to the Auth0 authentication page, then click on the Sign up link and register there
If the authentication is successful, the app will redirect you to the dashboard and display the `id`, `email` of the user.
![Dashboard](/img/blog/add-saml-sso-to-node-express-app/express-dashboard.png)
## Conclusion
Congratulations, you should now have a functioning SAML SSO integrated with your express.js app using the SAML Jackson and Auth0.
## References
To learn more about SAML Jackson, take a look at the following resources:
- [SAML Jackson Documentation](https://boxyhq.com/docs/jackson/overview)
- [SAML Jackson GitHub](https://github.com/boxyhq/jackson)
- [Express web app that shows how to use SAML Jackson](https://github.com/boxyhq/jackson-examples/tree/main/apps/express)
Your feedback and contributions are welcome!

View File

@ -1,28 +0,0 @@
---
slug: understanding-saml-sso-the-basics-from-the-solution-providers-side
title: Understanding SAML SSO, the basics from the solution provider's side
author: Jay Singh
author_title: Marketing Consultant
author_url: https://www.linkedin.com/in/jaydsingh/
author_image_url: https://boxyhq.com/img/team/jay.jpg
tags_disabled: [enterprise-readiness, saml, saml-jackson, sso, single-sign on]
image: img/blog/sso/with-boxyhq.png
---
This article follows my first article in which I explain the basics of SAML from the users' side. If you haven't read that one already I would recommend reading that one first [here](./2022-06-30-understanding-saml-sso-the-basics-from-the-user-side.md). In this article, we are going to take a look at what SAML authentication and setup look like from the solution providers' perspective.
If you are a B2B solutions provider and you plan to have enterprise customers they will likely ask that your product supports SAML SSO. This is because the customer will already be using an IDP to manage user access and security to their services. Anything outside this will be a risk and not fit into their user's workflows.
Most larger solution providers have already invested a lot of time and money into building SAML integrations with IDP providers but this leaves smaller competitors with less time and resources at a disadvantage as they often haven't been able to prioritize enterprise security features over the core product build.
The main reason why smaller companies dont implement SAML as part of the standard build is that it traditionally takes a long time as they have to build a custom integration with each IDP provider their customers use. Well, this is now an old issue because we have created BoxyHQ which allows you to connect to our free product with one single integration that then connects to all the IDPs for you! Let's take a look at what the integrations with and without BoxyHQ look like first.
![Without BoxyHQ](/img/blog/sso/without-boxyhq.png)
In the diagram above we can see what it looks like when you build a custom SAML integration with each IDP. As you can see for each IDP you have to connect all the instances of your product and build a unique integration. This can take months and take the focus away from your team building your core product. We believe that enterprise readiness should be accessible and easy for businesses of all sizes so we built BoxyHQ. Let's see what that looks like.
![With BoxyHQ](/img/blog/sso/with-boxyhq.png)
As you can see from the image above with BoxyHQ you only have to connect your product with a straightforward integration to BoxyHQ and then we manage and connect you to all the IDPs! It is that simple and you can deploy SAML SSO for your clients in as little as 8 days. We are also open source and free so you don't need to worry about big maintenance bills, we will even offer you custom support during the integration.
If you are interested in becoming enterprise-ready without the hassle then let's chat! You can [book](https://meetings.hubspot.com/deepakprab/demo) a free consultation call and chat with our CEO about how we can help. Let's start the journey together.

View File

@ -1,47 +0,0 @@
---
slug: understanding-saml-sso-the-basics-from-the-user-side
title: Understanding SAML SSO, the basics from the user side
author: Jay Singh
author_title: Marketing Consultant
author_url: https://www.linkedin.com/in/jaydsingh/
author_image_url: https://boxyhq.com/img/team/jay.jpg
tags_disabled: [enterprise-readiness, saml, saml-jackson, sso, single-sign on]
image: img/blog/sso/with-saml.png
---
I have always worked in tech, so have always needed to understand the technical nature of the products we are building. This process has always been over-complicated for me so I now always try to write a guide for non-technical people like me. It turns out that once you understand it you can explain it to other non-technical people much easier! So here we go as I try to explain SAML (Security Assertion Markup Language) SSO (single sign-on) and why BoxyHQ makes it so easy to implement. Firstly you have probably heard of not only SAML but OAuth 2.0 and OIDC, these are all protocols that achieve the same result of providing SSO. There are a few nuances but those are out of scope for this article to keep things simple.
Let's start with what SAML SSO is and what it does. An example of SAML SSO in action would be a user in your company signs into a single dashboard and inside that dashboard, they have all the icons for the external services they use such as their CRM (Hubspot) and accounting software (Xero). The user can now just log in to any of their services by clicking on them rather than logging into each one individually.
But how does this work? Well, the idea behind SAML SSO is that by centralizing your access to an external system you can better manage access and permission as well as improve security. So in our example, the dashboard that allowed the user to just click an icon and log in was SAML in action. Because the company has connected to its external servicing using SAML it can now let its users access all the services from a single point. This single point of access is known as the IdP (Identity Provider) which authenticates the access to all the other services via SAML.
The diagrams below show how this access flow would work with and without SAML:
![Without SAML SSO](/img/blog/sso/without-saml.png)
In the diagram above we can see that the company is not using SAML so the user has to log into each of the services with an individual username and password. The username and password are managed by the service provider and access is also managed via an admin user on the service provider's side. The user must be given access to each of the services from each of the services and remember the login details for each one.
![With SAML SSO](/img/blog/sso/with-saml.png)
In the image above we can see that the company is using an IdP such as Okta so the user simply has to log in once and then can access all the external services from a single dashboard. This also means that the company admins can manage access to the different services as they control the access directly from their IdP.
Now, remember that this is just a high-level overview of SAML and the technical aspects behind the scenes can get a lot more complicated.
We have been looking at SAML from a company user's perspective but it's also important to remember that these service providers also have to build a SAML integration to enable them to connect to their clients IdPs. This can be a very long and time-consuming process for service providers and this is where BoxyHQ comes in. Instead of service providers building a custom integration for each IdP their customers use which can take months, the service providers can use BoxyHQ and have all the connections to IdPs they need with a single integration! You can be SAML-ready in as little as 8 days! To understand how this looks check out my other blog [here](./2022-06-30-understanding-saml-sso-the-basics-from-the-solution-providers-side.md).
So what are the main benefits of SAML? Here are three of the most important ones I have identified.
#### Increased Security
SAML is at its heart a security standard and as it provides a single point of authentication that takes place in a secure environment it adds an extra layer of security to your service that most enterprise customers will ask for.
#### Improved user experience
As a user using SAML is very simple and pleasant to use as you only have to log in once and then you can access all your external services on a dashboard with a single click. This saves the user time and makes their overall experience of your product better.
#### Reduces cost
Without SAML you have to maintain account information across multiple services but when you use SAML this is all managed by the IdP.
BoxyHQ is open source and our SAML SSO product, SAML Jackson is just the first product we have built to help companies become enterprise-ready. If you are interested in discussing your authentication strategy or deploying SAML SSO you can book a call with our CEO [here](https://meetings.hubspot.com/deepakprab/demo) to discuss how we can support you.
I hope you have found this high-level explanation of SAML and its use cases helpful. If you have any questions please don't hesitate to reach out to us on our live chat on our website https://boxyhq.com/

View File

@ -1,45 +0,0 @@
---
slug: three-reasons-not-to-build-enterprise-features
title: 'Be enterprise-ready: Three reasons not to build enterprise features!'
author: Sama - Carlos Samame
author_title: Co-founder & COO @BoxyHQ
author_url: https://www.linkedin.com/in/samame/
author_image_url: https://boxyhq.com/img/team/sama.jpg
tags_disabled:
[enterprise-readiness, startups, enterprises, corporates, sales, founder]
image: /img/blog/dontbuild/security-risks-meme.jpeg
---
If you are thinking about building features to be enterprise-ready, there are typically two paths that brought you here:
1. Your team has initially focused on smaller customers and is now looking to expand, or
2. Your team is building a new product and targeting enterprise customers from day 1
Either way, you need to be aware that selling to enterprises is super exciting, especially if you like to play golf and you are ok with a long sales cycle - it could easily take you up to three years to close a deal.
Enterprises can be scared to give startups a chance and startups often lose out to more established businesses. However, there are two great ways to make sure your business doesn't miss out:
- List of other enterprise customers (“show me more logos, we are not a guinea pig”)
- Compliance requirements (“a checklist to show my boss you are safe”)
![Security risks everywhere](/img/blog/dontbuild/security-risks-meme.jpeg)
But what is enterprise readiness? From a product perspective, [EnterpriseReady.io](https://www.enterpriseready.io) identified common features that set enterprise software apart. You can do a free self-assessment [here](https://www.enterprisegrade.io/). The basics mean that your business meets the standards that enterprises look for in solution providers.
Now, the good news is that to be enterprise-ready you dont need to build these common undifferentiated features which can drain your resources and bank account. Here is why:
1. Customer Obsession You need to forget about product development and narrow your attention to customer development. You need to talk to potential enterprise customers and understand their current needs, pains, motivations, processes, etc. Remember that theyve got plenty of software they already depend on that will need to work smoothly with yours. On top of learning how to navigate the enterprise, you need to identify Infosec barriers and consider how to mitigate them; if your solution needs to process internal data, things will be more complex.
2. Time to market Instead of spending months building in-house enterprise-grade features, there are off-the-shelf enterprise readiness solutions that you can integrate into your SaaS app with just a few lines of code. There is no need to wait months to build Single Sign-On (SSO), Directory Sync, Audit Logs, Privacy Vault, and other boring stuff that enterprises ask for anymore, now you could plug them within hours. And your team can spend more time building your core product instead of non-core features that wont add value to your customers main needs.
3. Cut engineering costs Out-of-the-box solutions will help your company save developers time. If you consider the learning curve, coding, fixing bugs, and all the hassle that your tech team needs to go through, you will realize that peoples time is more expensive than developer tools. And the good news is that there are reliable open source solutions that you could use at no cost. Free and trustworthy? Thats the beauty of open source communities. Self-hosting these solutions will allow your company to maintain a level of control that will simplify things if you need to be certified (SOC2, ISO 27001, HIPAA, etc).
Here are 3 open-source solutions that could be interesting for you - BoxyHQ (**disclaimer, I'm a Co-Founder here**), [Supertokens](https://supertokens.com), and [Oso](https://www.osohq.com). There are plenty of other solutions that are relevant, we are building a list and would love to learn about other projects you use, please share them with me.
Lets be sincere, will your engineers focus on building the best SAML SSO feature or will they just focus on checking the box? Compliance security could be expensive in the long term when working with large enterprises. Especially if things go wrong because being compliant doesnt mean your SaaS app is unhackable.
Remember that not all enterprises are the same. But working with a few design partners will help your team to define an efficient product roadmap, build a robust go-to-market strategy, and you will close more enterprise deals.
Deals, deals, deals!
If you know anyone that needs to build enterprise features we would love to hear from them and see how could we help, please feel free to share my email: sama@boxyhq.com - Thank you!

View File

@ -1,55 +0,0 @@
---
slug: developer-first-security-sucks-automate-product-security
title: 'Developer-first Security sucks! Why is it essential to automate product security?'
author: Sama - Carlos Samame
author_title: Co-founder & COO @BoxyHQ
author_url: https://www.linkedin.com/in/samame/
author_image_url: https://boxyhq.com/img/team/sama.jpg
tags_disabled: [developer, security, cybersecurity, devsecops, appsec]
image: /img/blog/security-sucks-meme.jpeg
---
Lets start with some facts to understand why it sucks!
On one hand:
- Cybercrime went up 600% due to the COVID-19 Pandemic
- Data breaches and cyber attacks in 2021 were 5.1 billion breached records, this is 11% more than in 2020
- 79% of companies have experienced at least one cloud data breach in the past 18 months
- Software supply chain attacks jumped over 300% in 2021
- It is estimated that worldwide, cyber crimes will cost $10.5 trillion annually by 2025.
(Data from Purplesec, IT Governance, VentureBeat)
On the other hand:
- 70% of development teams always or frequently skip security steps due to time pressures when completing projects
- Almost 60% of devs are releasing code 2x faster, thanks to DevOps.
- In 2021, only 20% of organizations have fully integrated security into the development
- Security has low priority. 67% of developers surveyed by Secure Code Warrior admitted that they routinely left known vulnerabilities and exploits in their code
- Github expects the number of software developers using its platform (56 million in 2020), to grow to 100 million developers in 2025
(Invicti Security, Gitlab, GitHub, VentureBeat)
**Security vs Developers**
Security teams focus on planning secure IT environments, but developers are asked to focus on productivity while they are also tasked with implementing these security plans. The main issue is that developers are often left out of security planning processes, creating a strained relationship between these two teams.
It is important to build a healthy relationship where trust, communication, and collaboration are key to moving toward the organizations north star. But traditional security teams sometimes see themselves as inspectors of the developer's work. And that attitude needs to change - “when youre a hammer, everything is a nail”.
Did you know that in “Gartner's Top Strategic Technology Trends for 2022: Cybersecurity Mesh”, the word "developer" is not included not even once? We were shocked about it; developers need to have a leading role in cybersecurity!
**Its “Shift Left Security” time!**
With shift left security we mean moving security sooner in the development process.
Teams should provide developers with the right tools to do their job securely; this is why it is essential to automate product security.
But most of the new security solutions are focused on selling to the CISOs and their security teams, maybe because they are the ones with the budget for “security”; but what about developers? Most of their new solutions are oriented toward productivity, which makes sense since we live in an agile world, but what if there were new developer-first security solutions? Well, it is about time; a recent survey from Forrester shows that last year 27% of organizations had their development teams holding the budget for application security tools and that number has increased to 37% this year.
**Developer-first security Tools**
While some security tools for developers have started to appear, it is still early days. The ecosystem needs solutions to automate security for developers and most importantly, that is reliable. Our hypothesis is that the most important products will come from the open-source community; they have a genuine interest in supporting and empowering developers.
We are consolidating a list of reliable open source developer-first security tools for security, if you know of a project we should consider, or if you would like to have access to this list, please send me an email: sama@boxyhq.com or/and help us spread the word! 🙌
![Security risks everywhere](/img/blog/security-sucks-meme.jpeg)

View File

@ -1,87 +0,0 @@
---
slug: understanding-scim-and-directory-sync
title: Understanding SCIM and Directory Sync
author: Kiran K
author_title: Senior Developer @BoxyHQ
author_url: https://twitter.com/tokirankrishnan
author_image_url: https://boxyhq.com/img/team/kiran.jpg
tags_disabled:
[enterprise-readiness, engineering, saml-jackson, directory-sync, scim]
image: /img/blog/directory-sync-flow.png
---
This article will walk you through everything you should know about SCIM and Directory Sync.
## What is SCIM?
System for Cross-domain Identity Management (SCIM) is an open standard that allows for the automation of user provisioning (Directory Sync).
SCIM facilitates user identity data communication between Identity Providers (Okta, OneLogin, etc.) and Service Providers (Enterprise SaaS apps).
## Why should you care about SCIM?
Many companies manually onboard and offboard users, which consumes many IT resources and time.
User lifecycle management (ULM) begins when employees start their job and continue until they leave the company. ULM is all about provisioning and de-provisioning users when they join an organization.
For IT departments, this means creating an account for the new employees in the cloud apps they need to use after starting their job. Also, IT departments must ensure that when those employees leave, they revoke access to those accounts.
Smaller organizations might address these procedures manually, but the process can become error-prone and time-consuming when done at scale. This is where the SCIM and Directory Sync come to the organization's rescue.
## What is Directory Sync?
Directory sync helps organizations automate the provisioning and de-provisioning of their users.
As a result, it streamlines the user lifecycle management process by saving valuable organizational hours, creating a single truth source of the user identity data, and facilitating them to keep the data secure.
## How does the Directory Sync work?
Directory sync allows programmatic access to the user identity data via a standard protocol (SCIM).
Directory sync implementation typically involves a client and a server. A client is an identity provider (IDP) with a directory of user identities. A service provider (SP) is an enterprise SaaS app that needs a subset of data from those identities.
When you make changes to the user identities, the changes are automatically synced to the SP according to the SCIM protocol. SP can now process this data according to the way they want.
Some common user identity changes include adding new users to the organization, updating existing users, removing users from the organization, adding users to groups, etc.
Technically, SCIM is a set of APIs that allows you to manipulate the users and group objects and expose these data as JSON through the REST endpoints.
## How to add Directory Sync to your SaaS app?
Building Directory sync implementation yourself can be tedious and time-consuming for any engineering team.
Below are some questions the engineering team should answer before starting building Directory sync.
- How do we support multiple identity providers?
- How much effort should the team put into support & maintenance?
- Do we have developers with good knowledge of SCIM and its security?
- Is it worth building the Directory sync ourselves?
In short, building Directory sync yourself is not a good idea. It requires a lot of tedious engineering work and ongoing maintenance.
The best alternative is an open-source dedicated Directory Sync implementation provider like SAML Jackson from BoxyHQ.
## Directory Sync from BoxyHQ
BoxyHQ can help enterprises to add Directory Sync to any SaaS app with just a few lines of code.
Enterprise SaaS apps can provide a Webhook endpoint to SAML Jackson, and Jackson will notify the Webhook every time a change occurs in the user identity data within the IDP.
![Directory Sync Flow](/img/blog/directory-sync-flow.png)
In short, Jackson hides all the complexities involved with Directory Sync implementation and makes your integration easier.
BoxyHQ's Directory Sync implementation supports identity providers such as Okta, OneLogin, Azure AD, and JumpCloud. We're looking forward to adding more identity providers in future releases.
Here are a few critical aspects that make [BoxyHQ's Directory Sync implementation](/docs/directory-sync/overview) stand out.
- An open-source solution.
- Allows you to keep control of your data.
- Support multiple identity providers.
- Allows you to listen to six critical SCIM events.
## Final Thoughts
Directory Sync is a valuable investment for every organization seeking efficiency and security in their user lifecycle management system.
If you are interested in becoming enterprise-ready without the hassle, then let's chat! You can book a free consultation call and talk with our CEO about how we can help. So let's start the journey together.

View File

@ -1,126 +0,0 @@
---
slug: enterprise-ready-saas-starter-kit
title: Enterprise-ready SaaS Starter Kit
author: Kiran K
author_title: Senior Developer @BoxyHQ
author_url: https://twitter.com/tokirankrishnan
author_image_url: https://boxyhq.com/img/team/kiran.jpg
tags_disabled: [enterprise-readiness, nextjs-template, saas-starter-kit]
---
Enterprise-ready SaaS Starter Kit is a **Next.js** based SaaS Starter Kit that can save hundreds of development hours while building [enterprise-ready SaaS apps](/blog/enterprise-readiness-made-simple).
[Kickstart your enterprise app development with Next.js SaaS Starter Kit](https://github.com/boxyhq/saas-starter-kit)
Check out the [video tutorial](https://youtu.be/oF8QIwQIhyo) that walks through setting up your local environment and running enterprise-ready features the SaaS kit offers.
## SAML SSO
SAML stands for Security Assertion Markup Language. It is an XML-based open standard for transferring identity data between an identity provider (IdP) and a service provider (SP).
[Single Sign On (SSO)](/blog/understanding-saml-sso-the-basics-from-the-solution-providers-side) allows your customers to manage their team's users outside your built-in user table.
SAML SSO is integrated with the help of [SAML Jackson](https://github.com/boxyhq/jackson)
## Directory Sync (SCIM)
[Directory sync](/blog/understanding-scim-and-directory-sync) helps organizations automate the provisioning and de-provisioning of their users.
As a result, it streamlines the user lifecycle management process by saving valuable organizational hours, creating a single truth source of the user identity data, and facilitating them to keep the data secure.
Directory Sync is integrated with the help of [SAML Jackson](https://github.com/boxyhq/jackson#directory-sync)
## Audit Logs
Provide enterprise customers with the ability to record and search events that happen within your application. With our simple integration, you can become compliant fast and save your team from building complex solutions from scratch.
Organizations gain the ability to monitor the flow of data and be alerted to any breaches. Audit logs help to pinpoint any misuse of information and ensure that data policies are followed.
## Webhooks & Events
Webhooks are a way for systems to notify external applications that a specific event has occurred in your SaaS app without receiving a request.
Webhooks are a great solution if the client does not know when an event will occur and wants to be notified in real-time.
Webhook is integrated with the help of [Svix](https://github.com/svix/svix-webhooks)
## Team Management
Teams describe the functionality that enables modern software to be coordinated and managed.
Through Teams, SaaS app users invite others to collaboratively use the application with them by creating an account.
## Other Features
Let's also look at other standard features the SaaS kit offers.
- Create account
- Sign in with Email and Password
- Sign in with Magic Link
- Update account
- Manage team
- Manage team members
- Invite users to the team
- Accept invitation
## Getting Started
Please follow these simple steps to get a local copy up and running.
### 1. Setup
Clone or fork this GitHub repository
```bash
git clone https://github.com/boxyhq/saas-starter-kit.git
```
### 2. Go to the project folder
```bash
cd saas-starter-kit
```
### 3. Install dependencies
```bash
npm install
```
### 4. Set up your .env file
Duplicate `.env.example` to `.env`.
```bash
cp .env.example .env
```
### 5. Set up database schema
```bash
npx prisma db push
```
### 6. Start the server
In a development environment:
```bash
npm run dev
```
### 7. Start the Prisma Studio
Prisma Studio is a visual editor for the data in your database.
```bash
npx prisma studio
```
## Contributing guide
Contributions make the open-source community a fantastic place to learn, inspire, and create. Any contributions are greatly appreciated by the whole community.
We encourage and invite users and community members to contribute to the [saas-starter-kit](https://github.com/boxyhq/saas-starter-kit) repository.
For more help or if you have a question about getting started building a SaaS app please join our [Community Discord.](https://discord.boxyhq.com)

View File

@ -1,83 +0,0 @@
---
slug: sso-building-blocks
title: SSO Building blocks - SAML, OAuth 2.0 and OpenID Connect
author: Aswin V
author_title: Senior Developer @BoxyHQ
author_url: https://twitter.com/av__2021
author_image_url: https://boxyhq.com/img/team/aswin.jpg
tags_disabled: [sso, engineering, saml-jackson, oauth-2.0]
image: /img/sso-flow.png
---
We have already covered SAML at a high level from both [user](2022-06-30-understanding-saml-sso-the-basics-from-the-user-side.md) and [application provider](2022-06-30-understanding-saml-sso-the-basics-from-the-solution-providers-side.md) points of view.
In this post, we'll dive into the technicalities of SAML, OAuth 2.0 and OpenID Connect and how these come together to serve as building blocks for Jackson SSO.
## SAML
SAML was designed for traditional web applications in the early 2000s. The goal was to provide a seamless user experience for applications by federating authentication to an IdP. As a result, applications no longer had to maintain identities for users. All they had to do was to redirect the browser to the IdP which would then authenticate the user and return an assertion about the logged-in user. This assertion in effect was a token, asserting to the app that the user authenticated at the IdP and the assertion is valid for the set period contained within it.
While SAML gave us a solution to the problem of SSO or federated identity, it does not address the issue of authorization.
The need for authorization arose with the dawn of Single Page Apps (SPA) and native platforms such as mobile. More and more logic started moving from backend to frontend and an ecosystem of apps that could talk to one another (via HTTP(S)) sprung up. For eg:- You could reserve movie tickets and send invitations to your Facebook friends. This meant that applications started acting on behalf of the end-user, requesting data (friend list) from other services (Facebook). One way we could solve it was by sharing our credentials (for services) with the app. Nothing could be more dangerous than this, because now the application can virtually do anything the user could do. This paved the path for standards like OAuth that provides us with a mechanism to grant controlled and limited access to resources on behalf of the user.
## OAuth 2.0
The OAuth 2.0 Authorization framework enables a third-party application/client to obtain limited access to an HTTP service on behalf of the resource owner (or user). In the final step of this process, the client receives a short-lived access token that can be used to access the protected resources.
The flow starts with the app redirecting the user agent to an intermediary Authorization server (AS). The AS authenticates the user and obtains permission from the user to access resources. Once that's done, AS redirects back to the client with an Authorization code. The Authorization code is a grant or a credential representing the user's authorization to be used by the client. In the final step, the client uses this code to obtain an access token. This flow otherwise called Authorization Code grant is one of 4 grant types that are supported. For sake of simplicity, we can omit the others for now.
The above-mentioned flow offers a few benefits:
- The user only authenticates with the authorization server and the credentials are never shared with the app.
- The access token is not transmitted<sup>\*</sup> via the user agent but directly to the client via an HTTP request.
- The Client can be authenticated by the authorization server by using a client secret.
**\*** _It's worth mentioning the fact that another grant type 'implicit grant' does return an access token via the user agent in the redirect URL fragment_
#### Using OAuth 2.0 for authentication
Since authentication usually occurs before issuing the access token, it is usually assumed that possession of an access token is proof that authentication happened. The access token is then used to query the Identity API to obtain user details.
However, this does not fully serve as proof of authentication and has several pitfalls:
- The access token is opaque to the client and its intended audience is the protected resource server.
- There is no way to know if the user is still around because information about the authentication event is not exposed.
- In situations where clients get an access token directly in the return URL (implicit grant), there is a high chance that an attacker can inject their malicious token. This can be mitigated by using the Authorization code flow as the token is retrieved from the token endpoint directly.
- OAuth does not define a standard set of fields for the Identity API. For eg:- While one IdP could use `user_id` for the user identifier, the same could be `subject` in another one. This requires different handling on the client side from one IdP to another.
A new standard called 'OpenID Connect' which builds on top of OAuth 2.0 brings new artifacts like ID tokens that can serve as reliable proof of authentication and also standardizes things like `scope` and `claims`.
## OpenID Connect (OIDC)
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It supports 3 flows of which Authorization code and implicit flow are similar to the ones defined in OAuth 2.0. The notable difference here is the return of an ID Token in JWT format (JSON Web Token). The claims in the ID Token help the client reliably confirm the identity of the user. The audience(`aud`) claim will be set to the client id which means the ID token is intended to be consumed by the client alone. Conforming to the OAuth 2.0 spec, an access token is still returned which can be used to obtain information about the user from the "userinfo" endpoint. OIDC also standardizes the claims in the ID Token as well as the "userinfo" response.
## Assembling the SSO puzzle
Now that we have all the pieces of the SSO puzzle, bringing it together in Jackson would look something like the one below.
![SSO Flow](/img/sso-flow.png)
Allow me to explain.
We need to support two kinds of SSO Identity Providers - SAML and OIDC. For the sake of discussion, consider the scenario of two apps where one (CRM) needs to log in with Azure AD via SAML and another (HRM) needs to log in with Google Workspace via OIDC.
#### Setup SSO Connection
The preliminary step (marked by the green arrow above) is to add the SSO Connection to Jackson. For SAML IdP, this would mean saving the XML metadata from the IdP. The metadata would contain the SSO URL to send the SAML request to plus the public key to verify the SAML assertion signature. In the case of OIDC IdP, we need the discovery URL and client credentials (clientID and clientSecret of the registered app). The discovery URL can be used to query metadata about IdP such as authorization and token endpoints while the client credentials will be used to authenticate the Jackson client orchestrating the OIDC flow.
#### Login flow
Jackson supports both OAuth 2.0 and OpenID flows. The OAuth 2.0 flow is made secure by supporting Authorization Code flow with PKCE. By including the scope `openid` in the client request Jackson will switch to OpenID flow.
The login process follows the below steps:
1. The Client (Browser app) initiates the login by redirecting to Jackson's `authorize` endpoint. Jackson will parse the tenant/product in the request and use it to redirect the user to the configured IdP.
2. Step 2 varies based on the Identity Provider type. For SAML IdP, Jackson would construct the SAML request, sign it and send it to IdP. The IdP validates the request and authenticates the user. For OIDC IdP, Jackson constructs an OpenID Connect request and redirects the user to the OIDC Provider authorization endpoint.
3. Once the user is logged in successfully, the IdP redirects back to Jackson. For SAML, the response contains the user profile. In the case of OIDC, the response contains the authorization code that is used by Jackson to obtain the token and user profile from the OIDC IdP. Jackson generates a short-lived `authorization code` and stores the user profile against it.
4. The `authorization code` generated in the previous step is sent to the client app.
5. The client exchanges the code for the token and uses it to query the userInfo endpoint of Jackson to get the complete user profile. In the case of OpenID flow, ID Token is returned by Jackson and contains the basic user profile.
## Final thoughts
So in a nutshell, Jackson acts as a proxy between the client app and the IdP doing the heavy lifting of orchestrating SAML/OIDC flows with the configured IdPs. This way you can quickly scale your app auth to any number of providers allowing you to focus on your core product.

View File

@ -1,46 +0,0 @@
---
slug: what-is-dev-ops-and-how-has-it-evolved-into-dev-sec-ops
title: What is DevOps and how has it evolved into DevSecOps
author: Jay Singh
author_title: Marketing Consultant
author_url: https://www.linkedin.com/in/jaydsingh/
author_image_url: https://boxyhq.com/img/team/jay.jpg
tags_disabled: [devops, devsecops, developer security]
image: /img/blog/devsecops.png
---
## What is DevOps
Let's first take a look at what DevOps (Developer Operations) is so we can better understand why it has now evolved into DevSecOps (Developer Security Operations). DevOps is a combination of philosophies, practices, and tools that increases a business's ability to deliver better development in less time (Higher velocity). This can be applied to building a new product or the process of continuous improvement that applies to most products we see today.
If we look at the old way of development, typical teams worked on their own and would do their bit and then just pass it on to the next team to do theirs, a bit like an assembly line. This meant that development cycles were very long, communication between teams was limited, handover processes were not in place and if anything went wrong it would take a long time to identify and fix issues. If we compare that to today's agile development process we use DevOps to work in sprints and deliver results in a much faster and more efficient way. This has been made possible by not only the way we look at the development cycle but also by tools and automation.
DevOps has come a long way already and we have seen it evolve with the agile methodology of working but security, in particular, was always still the last step of the development process and not thought about as a necessity. In some cases when security was only looked at by a specific team at the end of the process.
## Why has security been integrated into DevOps
The rise in cybercrime and the sophistication of attacks has made security a crucial part of the development process and not just an afterthought. This has led to security being integrated into the development process at each stage and becoming a shared responsibility. It has also led to security being thought about and planned right from the start of each process rather than at the end. This has resulted in more development velocity, more layers of integrated security and higher collaboration around security as a major aspect of the development cycle.
The integration of security in the development cycle at each stage from start to finish while also automating some of the security steps is what has led to the evolution of DevOps becoming DevSecOps, a go-to practice today. One of the main reasons the term was adjusted to include security is to make each person in the process think about and take accountability for secure building practices.
## Benefits of DevSecOps
Lastly, let's take a quick look at the main benefits of having solid DevSecOps in place
1. **Security**
By thinking about and implementing security at each stage of the development process and particularly in the early stages organizations are proactively mitigating cyber threats. This combined with automated security testing means that dev teams can perform security checks and audits without slowing down development cycles.
2. **Improved Collaboration**
DevSecOps pushes for development and security and operations teams to collaborate more and especially in the early stages of the process. This increases innovation and leads to better cross-team buy-in. It also makes sure that everyone is responsible for security.
3. **Streamlines process that limits vulnerabilities**
Having security in every stage of the development process limits the chance of finding vulnerabilities much later, vulnerabilities which could delay the release. The process of streamlining the process with automated security testing as part of the development process also ensures that possible vulnerabilities are caught at each stage.
4. **Cost**
Cost is also always a major benefit and by having a good DevSecOps process in place you will find bugs and issues much faster which will result in less time and cost required to fix them.
![DevSecOps](/img/blog/devsecops.png)

View File

@ -1,42 +0,0 @@
---
slug: how-low-code-solutions-are-changing-how-we-build-products-and-workflows
title: How low-code solutions are changing how we build products and workflows
author: Jay Singh
author_title: Marketing Consultant
author_url: https://www.linkedin.com/in/jaydsingh/
author_image_url: https://boxyhq.com/img/team/jay.jpg
tags_disabled: [low-code, no-code, speed of development]
image: /img/blog/lowcode-graph.png
---
We have all heard the terms low-code or no-code being thrown around as buzzwords over the last few years but what does this mean and how is it changing the way businesses and individuals solve problems? I am going to use our product SAML Jackson to explain how low-code solutions are changing the way we build products.
Low-code solutions are essentially products that provide you with building blocks so instead of building a solution from scratch you can simply combine the relevant building blocks to make a relevant solution for your business. Lets take BoxyHQ and our SAML Jackson product as an example. Without the low-code product (SAML Jackson) the alternative for businesses would be to build a custom SAML integration which takes months and a ton of resources. This sounds ridiculous tho right? With the number of businesses who are deploying SAML for their customer, there must be some reusable parts that can be shared to reduce the time it takes each business. This is where low-code products like SAML Jackson come in. By building the SAML integrations as a reusable component, businesses only need to create one simple connection to the SAML Jackson to deploy SAML.
Still with me? If not, don't worry. Essentially what low-code is taking advantage of is building in a way that can be shared so the amount of custom building is limited (or low) for common use cases.
## So what is the difference between low-code and no-code?
Well while a lot of people would still group them together, the obvious difference is that low-code still needs some code to integrate the building blocks, whereas no-code doesn't. If we look at a product like Zapier for example, that requires no code at all and a non-technical person can use visual blocks to connect different data sources and outputs to build workflows. An example of this is as a non-technical person I can take data from forms such as Hubspot forms that are submitted on our website and create notifications for the team on Slack. Doing all of this without code and just using Zapier is what makes this a no-code solution.
## Why is low-code so important?
Lastly, let's take a quick look at the main benefits of having solid DevSecOps in place
1. **Speed speed speed**
In today's world businesses need to be agile and fast. With competitors springing up every day and customer expectations high the last thing a business wants to do is to have to make specialist hires for each element of their build or spend precious time on auxiliary features that also have their learning curve. The birth of plug-and-play has meant that businesses can operate faster and more efficiently than ever before. Can you imagine if a business had to build all its tools from scratch? No neither can I.
2. **Cost**
Cost is always a major element that businesses and individuals look at when finding a solution and in the case of low-code it comes down to the question of build V buy. For larger enterprises who have not fully adopted the trust and efficiency of low-code they might still choose to build their own solution which will cost them a lot more in resources and time but that might be something, they have spare. Smaller businesses who want to focus on their core offerings will always look for reliable plug-and-play solutions such as low-code which allow them to quickly deploy solutions and stay competitive while saving on the large number of resources needed to build from scratch.
![DevSecOps](/img/blog/lowcode-graph.png)
## Are there any negatives to using low-code and no-code platforms?
The only main negative of these solutions I have identified is that because of the ease and speed of the platforms it can create a lack of transparency and some shadow IT as lots of people in the organization can be building solutions and data can be moving around without accountability. However, with the right IT processes and policies in place, this can be easily fixed.
## Why are we so excited about low-code and no-code?
We are very excited about low-code solutions because it drives innovation! We at BoxyHQ are building low-code solutions for enterprises to implement the important but standard features they need to be competitive and compliant with ease so they can focus on what they do best which is innovate. We have some great clients already and cant wait to see what they do next without the hassle of building standard features such as SSO and Directory Sync.

View File

@ -1,40 +0,0 @@
---
slug: why-does-your-saas-application-need-audit-logs
title: Why does your SaaS application need audit logs?
author: Deepak Prabhakara
author_title: Co-founder & CEO @BoxyHQ
author_url: https://github.com/deepakprabhakara
author_image_url: https://boxyhq.com/img/team/deepak.jpg
tags_disabled: [audit-logs, enterprise-readiness]
image: /img/blog/audit-logs-widget.png
---
Audit logs are an important tool for keeping track of activity within your SaaS application. These logs provide a detailed record of the actions taken by users and can be used to monitor for potential security breaches, compliance violations, and other issues. Lets explore some of the key reasons why you need audit logs for your SaaS app.
1. **Compliance:** Many industries are subject to strict regulations that require organizations to maintain detailed records of their activities. Audit logs can be used to demonstrate compliance with these regulations, and to provide evidence in the event of an audit or investigation.
The retention period requirements of some well-known compliance frameworks are listed below:
- ISO 27001: 3 years
- GDPR: Not very specific, as long as necessary
- HIPAA: 6 years
- PCI DSS: 1 year
- NIST: 3 years
- SOX: 7 years
- GLBA: 6 years
2. **Cyber Insurance:** Obtaining cyber insurance usually comes with requirements around recording and retaining audit logs. These logs help with forensics during insurance claims, otherwise making investigation expensive and time-consuming for both insurers and the affected companies.
3. **Security:** Audit logs can be used to detect and prevent security breaches. By monitoring for suspicious activity, such as repeated failed login attempts or changes to sensitive data, you can quickly identify and respond to potential threats. Additionally, audit logs can be used to reconstruct the events leading up to a security incident, which can help you identify the cause and prevent similar incidents in the future.
4. **Accountability:** Audit logs make it possible to track the actions of individual users, which can be useful for identifying issues such as data breaches, compliance violations, and other problems. This information can be used to hold users accountable for their actions and to help you identify and address any issues that arise.
5. **Troubleshooting:** Audit logs can be used to identify and diagnose issues that occur within your SaaS application. By reviewing the logs, you can see exactly what happened when a problem occurred, which can help you quickly identify the root cause and develop a solution.
6. **Auditing:** Audit logs provide a record of the activities that occur within your SaaS application, which can be useful for internal audits. This information can be used to assess the effectiveness of your security controls and identify areas for improvement.
![Audit Logs](//img/blog/audit-logs-widget.png)
Audit logs are a powerful tool that can be used to improve the security, compliance, and overall performance of your SaaS application. By keeping detailed records of user activity, you can monitor for potential issues and quickly respond to problems as they arise. If your SaaS app doesn't have audit logs, you should consider implementing them as soon as possible to ensure the safety and security of your data and users. It is also becoming an important part of enterprise readiness.
## Introducing our Audit Logs product
We are extremely thrilled to introduce our new Audit Logs product in collaboration with our friends at [Replicated](https://replicated.com). Retraced is a fully open-source audit log service that comes with an embeddable UI that's easily deployed to an infrastructure of your choice. We have spent years building and fine-tuning audit logs systems and think we have finally discovered an optimal solution to this nagging problem.
Its yet another important enterprise readiness feature to tick as you scale your offerings to the enterprise segment and complements our Enterprise SSO and Directory Sync products to give you a one-stop solution. Come check out the product at our [GitHub repo](https://github.com/retracedhq/retraced), wed love to hear your feedback.

View File

@ -1,66 +0,0 @@
---
slug: exploring-the-open-source-business-model-and-how-companies-monetize-it
title: Exploring the open-source business model and how companies monetize it
author: Deepak Prabhakara
author_title: Co-founder & CEO @BoxyHQ
author_url: https://github.com/deepakprabhakara
author_image_url: https://boxyhq.com/img/team/deepak.jpg
tags_disabled: [open-source]
image: /img/blog/christine-roy-ir5MHI6rPg0-unsplash.jpg
---
With the rise of open-source solutions and solution providers, one of the biggest questions asked is, how do businesses monetize while giving away the source code for free?
## What is an open-source company?
An open-source company is an organization that develops software but makes the source code freely available to the public. This means that others can copy the code and engine, deploy it themselves, develop it, fix bugs and more. This allows the software not only to be widely accessible for free but also to evolve in a very collaborative way.
## If everything is free then how can it be monetized?
We don't have to look very far to find examples of open-source companies that have become unicorns and continue to grow. Some great examples are Elastic ($608 million in revenue, 2021), HashiCorp ($320 million in revenue, 2021), and RedHat ($3.4 billion in revenue, 2021). All these companies operate an open-source business model but have huge revenues and valuations. This is what we are going to look at.
There are many different ways that open-source companies can monetize - ultimately this comes down to the goals of the business. We are going to explore a few of the options available but keep in mind that these are just some of the ways it can be done and open-source continues to develop and grow at a rapid pace.
### Donations
One of the most popular models is to offer the source code and documentation completely free and let its users donate at their discretion. This is normally done for smaller projects and donations can be solicited in various ways, such as a button on the website, a link in a newsletter, a Github donation, or one that I like - buymeacoffee.com. The latter allows you to embed an option into your website or interface and donate at the value of a coffee. Although donations are a great way to monetize some projects, this method is not feasible for bigger companies that have complex solutions and large overheads.
### Support
Paid Support or Premium Care, as its commonly termed, is a very common business model that has done very well for larger commercial companies. This model allows users to still access the code and deploy it for free but also enables an option for companies/users to pay for additional support. This monetized plan often includes perks such as help deploying the software, customization and ongoing support for general use. Just because the source code of a project is open, it doesnt mean it's easy to deploy or manage. This is where companies such as Red Hat have been successful and use this particular model to great effect.
The benefits of this model are, as Red Hat has demonstrated, you can build a revenue-generating company that can be scaled effectively. The drawback is, some companies only make the open-source code available with a paid plan, which goes against the open-source ethos. To truly use this model effectively, companies should offer the source code for free regardless of an option for additional support.
![OSS Monetization](/img/blog/christine-roy-ir5MHI6rPg0-unsplash.jpg)
<div style={{fontSize: "10px", marginTop: "-20px", paddingBottom: "20px"}}>Photo by <a href="https://unsplash.com/fr/@agent_illustrateur?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Christine Roy</a> on <a href="https://unsplash.com/images/things/money?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a></div>
### Licensing
Open-source companies can also license their open-source software, which applies rules to how their software can be used, edited, distributed and copied. Some open-source companies will allow individuals and smaller organizations to use their software for free while charging larger companies a fee to deploy it. Normally a license fee comes with additional benefits, such as support and training, etc. There are also two main types of licensing that open-source companies can utilize.
-Copyleft license
This is a type of license in which, if code is copied and modified it still retains the original license terms
-Permissive license
This grants licenses based on different needs and is much more diverse.
Licensing and open-source licensing is a huge topic in itself and Snyk has done a fantastic job at explaining this. You can read more about it here.
### Cloud-hosted Services
Finally, the last model we will look at is hosting. While open-source organizations can still offer their code for free, some may offer a hosted version which is much easier to set up and maintain. This means customers can effectively use their product like any other SaaS and they typically charge on a subscription basis.
The hosted model is very popular as it now allows quick deployment but also reduces the level of maintenance and custom work developers need to carry out. The main limitation of offering a hosted model is, it will require the open-source company to offer web hosting and everything that goes along with it. This can require an enormous amount of maintenance and development.
### The open-core model
The open core model is when a company releases the core software for anyone to use but then also controls things such as the roadmap and what commits are accepted into it. By doing this, the company can also charge for extra features which customers may want. Some examples could be functionality features or even security/compliance modules. This model has been very popular with open-source companies and is widely seen as a very fair way to operate. It is also very important to make sure that the open-core has enough value that developers will rally around the product from the get-go. Companies that offer very little value from the free version and charge for additional features, do not see great traction in the open-source community.
## Controversial opinion
I personally believe that OSS is not a business model but a development model. We are debating this internally, so we would love to hear your feedback and opinions on this subject.
## Summary
Although open-source code is widely free and available to use, it has become a popular choice for companies who also want to commercialize. The benefits of open-source are vast and with the variety of business models we discussed you can understand the various options to create a successful, revenue-generating business.

View File

@ -1,51 +0,0 @@
---
slug: sbom-explained-an-enterprise-guide-to-security-risk-management
title: 'SBOM Explained: An enterprise guide to security risk management'
author: Nathan Tarbert
author_title: Community Success Engineer @BoxyHQ
author_url: https://github.com/NathanTarbert
author_image_url: https://boxyhq.com/img/team/nathan.jpg
tags_disabled: [open-source]
image: /img/blog/security-lock.jpg
---
In this age of technology, software companies are quickly shifting towards a strict compliance posture. You may ask yourself, why is that and what has changed over the last several years? This can be due to multiple factors but can mainly be boiled down into four categories.
- Security
- Product Development
- Compliance
- Supply Chain & Risk Management
## What is an SBOM or Software Bill of Materials?
You can think of your modern application as a cake you are baking. The list of ingredients you use to bake that cake would be the SBOM (Software Bill of Materials). In the case of software, it's open-source or private dependencies and third-party components. This list can be massive and can range from hundreds to thousands, especially when you factor in transitive dependencies (an indirect dependency of the component it relies on). This list gets very complex and is impossible to manage at scale at the enterprise level. Gone are the days when most enterprises or smaller-scale organizations would write applications from scratch. Rather, most applications are assembled using pre-built software packages, i.e open-source. Over the past decade, this has led to the rise and use of publicly available software components and agile development at an enormous rate.
## Security
More organizations now have security top-of-mind due to cyber attacks on business infrastructure becoming almost a daily occurrence. Companies are faced with major decisions that affect cost, efficiency, and productivity. There is an enormous risk and liability where a companys code base lives in the cloud. This could be private or public but a good rule of thumb when you think about risk is not if were breached, but when. So precautions need to be taken to add layers of protection to software infrastructure.
An SBOM would provide better visibility to companies in identifying and tracking security vulnerabilities that could enable timely patches. Updates in code should prompt a newly generated report (SBOM).
We could go a lot deeper around all the various ways precautions could be taken like scanning your application for vulnerabilities or penetration testing. A [minimum viable secure product](https://mvsp.dev/) is of course recommended for all enterprise-ready organizations. It could be as simple as having [audit logs](https://boxyhq.com/audit-logs) in place to record and search events internally on your application.
## Product Development
SBOMs can improve and help software development processes by providing a comprehensive list of all open-source dependencies and components used in a product. From an organizational standpoint, it is crucial to ensure that all software and related components are up-to-date and licensed correctly. Having this clear understanding is key to risk mitigation when it comes to understanding what is in a product and how it is constructed.
Therefore, development teams can quickly improve transparency, communication, and collaborative decision-making with a faster time-to-market while ensuring industry compliance standards and regulations.
![matrix finger](/img/blog/matrix-finger.jpg)
## Compliance
In 2021 the US Government issued an [executive order](https://www.whitehouse.gov/briefing-room/presidential-actions/2021/05/12/executive-order-on-improving-the-nations-cybersecurity/) mandating all software companies that do business with the US government must provide a detailed inventory list (software bill of materials or SBOM) of all components related to the software they have produced and sold to any federal agency. The legislation is geared towards transparency with a view to the enhancement of security for our supply chain infrastructure. This has quickly prompted other countries to consider similar legislation.
## Supply Chain & Risk Management
Its vital to take a proactive approach and have a top-down understanding of all software components that live in a software ecosystem. With that in mind, SBOMs are quickly becoming a standard for software supply chain risk management. With the expansion of sophisticated attacks, its more important than ever to take a systematic approach when it comes to the security of your organization.
The ecosystem is growing with tools that help you verify, scan and monitor all your components and manifest files.
If you have an open-source product to sell to enterprises or the public sector, you will need to anticipate compliance and build an SBOM into your product. Especially if you are targeting entities in heavily regulated industries. Taking this into consideration, thats what we did at BoxyHQ for each of our four products with guides that will help you navigate these decisions (Enterprise Single Sign On, Directory Sync, Audit Logs, and Data Privacy Vault). We chose to build [Cosign](https://www.sigstore.dev/) right into our tool - but many more are available. Here is a [curated list of SBOM-related tools.](https://github.com/awesomeSBOM/awesome-sbom)
Please visit BoxyHQs website to learn more about producing an SBOM for your products. E.g. SBOM for our enterprise SSO: [BoxyHQ](https://boxyhq.com/docs/jackson/sbom)

View File

@ -1,39 +0,0 @@
---
slug: sso-wall-of-shame-vs-wall-of-fame
title: 'SSO "Wall of Shame" vs "Wall of Fame"'
tags_disabled:
[developer, security, cybersecurity, devsecops, appsec, sso, open-source]
image: /img/blog/shame-vs-fame.png
authors:
- name: Sama - Carlos Samame
title: Co-founder & COO @BoxyHQ
url: https://www.linkedin.com/in/samame
image_url: https://boxyhq.com/img/team/sama.jpg
- name: Deepak Prabhakara
title: Co-founder & CEO @BoxyHQ
url: https://github.com/deepakprabhakara
image_url: https://boxyhq.com/img/team/deepak.jpg
---
Unless you have been living under a rock, you have probably heard of the SSO Wall of Shame. This is a list of vendors that treat single sign-on as a luxury feature, not a core security requirement. There have been numerous complaints regarding the companies that have made it onto this list, and rightfully so. In a downturn economy and in times when security and privacy are critical, many organizations see an opportunity to generate even more revenue.
This is a small example, listed in alphabetical order of some of the most well-known companies that have ended up on the “Wall of Shame” (see the screenshot below). You can find more information and the full list at [sso.tax](https://sso.tax). It is clear that raising prices for enterprise SSO and other security features, such as Audit Logs (to track critical events), is just part of their revenue model.
![sso tax list](/img/blog/sso-tax-list.png)
But is this the right thing to do? Its hard to judge from the outside, and clearly companies need to make a profit while showing growth, especially when you are backed by Venture Capital. Having said that, at BoxyHQ we believe that we can all do better (we are also Venture funded). Nonetheless, cybersecurity taxes should stop, and we should all focus on increasing our security posture and making a positive impact. Take for example, Hubspot charging 6300% more for SSO functionality! That is a clear example of how absurd and abusive some companies can be.
Now, we ask ourselves, how about the “Wall of Fame”? This is a separate list of companies that lead by example and dont take advantage of their customer base. If you do a quick search, you will find some interesting companies listed. Grafana, Cal.com, and Sumo Logic, just to name a few.
To understand why startups normally lean this way, its important to consider the enterprise deal process. With RFPs, security questionnaires, and other compliance-related procedures, closing an enterprise deal becomes all-consuming for a startup. This can justify an enterprise pricing tier. Given a startups early evolution of products, , Enterprise SSO becomes an easy candidate to distinguish the pricing tier gap between charging SMBs and what they can charge enterprises. But building and maintaining SSO is expensive and time-consuming. SAML is not necessarily the easiest protocol implementation to get right. And add to this the customer support issues that come with onboarding large enterprise teams onto the product. But as a startup matures the product needs to have enough core enterprise features and not merely depend on undifferentiated features like SSO.
To take it full circle, it would be nice to see a full list of the SSO Wall of Fame. Then we could ensure support for the companies with integrity, who have clearly not been overtaken by greed. Unfortunately because of our bandwidth, we can not commit to full ownership of this initiative, but can offer some practical advice on how companies could start offering SSO pricing tiers for free or at a nominal price increase:
- Charge for other core enterprise features instead of SSO. If your product is not quite to that level of maturity, please read on.
- Instead of charging for SSO, charge for the security processs that comes with enterprise deals. If a company wants you to go through its security and compliance process, rather pay a premium to enhance its security posture and reduce compliance risk from its vendors.
- If that scenario isnt possible then consider segmenting SSO pricing based on the number of users or seats. SMBs will not have a very large number of seats so this could be a possible way to separate your pricing.
- If your Enterprise tier is not based on seats, a natural progression is to base pricing on usage.
We are trying to do our part by providing a free opensource enterprise-grade SSO (called SAML Jackson), that any developer, team, or organization can plug into with just a few lines of code. Check out the GitHub repo [here](https://github.com/boxyhq/jackson). Feedback is much appreciated and a star will help us raise security awareness. 🙂
Stay safe, do good, and avoid the dark side of the SSO tax!

View File

@ -1,63 +0,0 @@
---
slug: build-enterprise-software-with-no-code-thanks-to-bubble-io
title: 'Build Enterprise Software with No-Code Thanks to Bubble.io'
author: Nathan Tarbert
author_title: Community Success Engineer @BoxyHQ
author_url: https://github.com/NathanTarbert
author_image_url: https://boxyhq.com/img/team/nathan.jpg
tags_disabled: [open-source, sso, enterprise-ready]
image: /img/blog/bubble-small.jpg
---
Building your enterprise applications on Bubble is now easier than ever with BoxyHQ, a single API to connect to enterprise Single Sign-On (SSO), and multiple security compliance features.
## What is Bubble.io?
Bubble is a visual drag-and-drop programming language. Instead of scripting code, users can leverage a visual interface to build applications - simple or complex. This makes building apps accessible to people (or teams) with a big idea - but no programming skills.
## What is a Bubble.io Plugin?
Plugins are third-party Bubble.io components that are not part of the Bubble core platform functionality. They can be freely provided by the creators or available as a paid plugin.
## Bubble Makes It Simple
One of the benefits of using a no-code platform like Bubble is that not only can you build an application quickly, but you also have the ability to architect complex features. If we look back just a few years, this was not possible. You would have 2 options:
- Hire a developer or development team
- Delegate to a developer or team
But we live in an era where technology is continually evolving and individuals' or teams' creativity has no limits. We can put ourselves in the shoes of someone who doesnt write code but wants to build a professional application - with Bubble.io this is now a possibility.
## Top 3 reasons small businesses or enterprises should switch to a no-code platform
_This comes with a caveat that [Bubble does have a learning curve](https://coachingnocodeapps.com/how-long-does-it-take-to-learn-bubble-and-how-much-does-it-cost) but once you get familiar with the platform its much easier to build applications._
## 1. Using a no-code solution like Bubble saves money on IT:
Typical app development workflow costs for SMBs (small to medium businesses) from design to implementation can range from $75,000 to $750,000. This can be crippling for startups which opens up a no-code solution as a better alternative. If we are talking about enterprise development, this number can reach up to millions.
## 2. Time to value:
This depends on what type of app you want to build. Some estimations are up to [80% in development time saved](https://medium.com/swlh/could-i-build-my-product-on-bubble-io-75923a41b9b6). Lets take into consideration there is no need to set time-consuming tasks for a developer such as basic features and environment setup. This is all taken care of for you when building in Bubbles platform.
## 3. Built-in SEO:
Whether you are a startup or an enterprise team, but inexperienced in the art of Search Engine Optimization (SEO), not to worry, Bubble has built-in [SEO tools](https://manual.bubble.io/help-guides/customizing-an-application/seo#bubbles-seo-tools) that allow you to the ability to modify and customize how your application is seen by search engine crawlers. This would be in the advanced settings and great care should be taken when enabling or modifying these settings because, by default, your application will not be indexed.
This brings a lot of value when you dont necessarily need a professional marketing division to start with. Right out of the gate, you can build an application that has professional capabilities to successfully reach your target persona.
## Can I add enterprise features on Bubble?
One of the foundational needs of any new business app is the ability for users to securely log in to password-protected areas - like a shopping cart or protected content. If we look at enterprise features like SAML SSO for instance, you may think this is a feature that is out of reach for a no-code platform, but you can simply search within the Bubble marketplace and a list of plugin creators has made this possible. Instantly you get a short list of plugins available for the functionality you would like to implement.
![BoxyHQ plugin](/img/blog/bubble-plugin.png)
BoxyHQ is one of those creators. By simply installing the plugin into your Bubble.io app, you can be up and running with little configuration effort. We have written a step-by-step [guide](https://boxyhq.com/guides/jackson/integrations/bubble) to help you properly configure setting up SAML single sign-on for your small to medium business (SMB) or enterprise application.
Once you have BoxyHQs plugin properly configured, you now have an application that will handle secure login access to your users using SAML single sign-on that will connect to any IdP (Identity Provider) like Okta, OneLogin, Azure AD, etc.
This is when you can breathe a sigh of relief because there is now no need to remember usernames and passwords. BoxyHQs plugin easily provides that solution for you. If you would like to test a [demo application](https://boxyhq-saml-sso.bubbleapps.io/version-test) click here to see the flow and enjoy the seamless experience you will have inside the Bubble platform.
If you are interested in understanding whats happening on the backend, we have a [guide](https://boxyhq.com/blog/understanding-saml-sso-the-basics-from-the-user-side) available that will walk you through the technical aspects of single sign-on.
SSO can be complicated but BoxyHQ makes it simple to understand.

View File

@ -1,34 +0,0 @@
---
slug: ignite-your-saas-journey-with-the-best-free-and-open-source-saas-starter-kit
title: 'Ignite Your SaaS Journey with the Best Free and Open-Source SaaS Starter Kit'
author: Sama - Carlos Samame
author_title: Co-founder & COO @BoxyHQ
author_url: https://www.linkedin.com/in/samame/
author_image_url: https://boxyhq.com/img/team/sama.jpg
tags_disabled: [developer, security, saas, devsecops, appsec]
image: /img/blog/enterprise-ready-saas.jpg
---
![testimonial quote](/img/blog/testimonial-kubeworkz.png)
Discover the Game-Changing Power of an Enterprise-Ready Solution that will help you save thousands of dollars in development costs.
Are you a SaaS founder striving for accelerated success in the highly competitive landscape? Look no further! At BoxyHQ we've curated a revolutionary tool that will supercharge your SaaS journey like never before. Introducing the Best Free and Open-Source SaaS Starter Kit, designed to ignite your growth and transform your startup dreams into reality.
## Enterprise-Ready Powerhouse
We understand that conquering the enterprise market is a key milestone for many SaaS founders. That's why this Starter Kit is not just another ordinary tool—it's an enterprise-ready powerhouse. Equipped with robust security features and compliance readiness, it's tailored to meet the stringent requirements of corporate clients. It includes SAML/OIDC Single Sign-On (SSO), Directory Sync, Audit Logs, and Data Privacy Vault (PII, PCI, PHI compliant) that would cost tens of thousands of dollars in developer time. Empower your startup to take on the biggest players in the industry with confidence.
## Supercharge Your Development Journey
Leave the tedious and time-consuming development tasks behind. The SaaS Starter Kit empowers founders to supercharge their development journey. Its intuitive, no-code capabilities streamline the entire process, enabling you to focus on your unique value proposition. Join the ranks of successful SaaS startups who have harnessed the power of this kit to achieve rapid growth and customer acquisition.
## Get Started Today
Ready to unlock your SaaS potential? Getting started is a breeze. Simply access the Starter Kit's source code and documentation on GitHub, available at [here](https://github.com/boxyhq/saas-starter-kit)
For additional guidance and insider tips, head over to this other [blog post](https://boxyhq.com/blog/enterprise-ready-saas-starter-kit) and watch our [full demo](https://www.youtube.com/watch?v=oF8QIwQIhyo). It's time to embark on your journey toward SaaS greatness.
Don't let your SaaS dreams remain stagnant—ignite them with the best free and OSS enterprise-grade SaaS Starter Kit. This game-changing tool is set to revolutionize the way startups grow and succeed. Seize the opportunity, join our thriving community, and accelerate your path to SaaS stardom. The possibilities are limitless, and your success awaits!
![landing page](/img/blog/ssk-landing-page.png)

View File

@ -1,41 +0,0 @@
---
slug: senior-software-engineer
title: Senior Software Engineer - Open Source, Dev Tools
author: Deepak Prabhakara
author_title: Co-founder & CEO @ BoxyHQ
author_url: https://github.com/deepakprabhakara
author_image_url: https://avatars.githubusercontent.com/u/357991?s=400&v=4
tags_disabled: [careers, senior-software-engineer, engineering]
---
#### TLDR
Join our well-funded remote-first team if you love building open source API driven developer tools. We are just getting started so it is a chance to be part of the founding team and influence adoption of our products! Join us on our mission to help startups simplify development of compliance and data security related features in their products. Reach out to us at careers@boxyhq.com.
#### About us
- Open source-first company - your work will be visible and you will be able to influence hundreds of developers!
- Our team will be distributed remotely worldwide.
- BoxyHQ is still small - just us 2 founders for now. You will be one of the first employees and can drive major parts of the product.
- Highly competitive salary and stock options.
- Experienced founders with strong engineering, commercial and open source experience.
- Engineering team will be involved in product discussions and planning. We do it openly via GitHub.
- We encourage and support the team in attending conferences, giving talks, writing blog-posts, and other activities.
- We believe in constantly iterating and improving; you will get to influence our internal processes as well.
#### About you
- Strong software engineering background. We are language agnostic but will be using Go and Javascript in our initial projects. Excellent coding practises (standards, unit tests, docs, etc) are essential.
- Remote work self-discipline. A lot of our processes are built on trust - we don't like to micro-manage. You get to take full ownership of the products.
- Excellent communication skills - clear, constructive, and respectful dialog with other team members, community.
- Ability to write technical docs, blogs. Team is responsible to keep documentation up to date.
### The Offer
- Competitive salary and stock options
- Flexible work schedule
- Choice of Mac, Windows or Linux laptop
- Stipend for home office set up
- Stipend for career development and learning
_Were committed to be the place where a culturally diverse mix of talented people get together to do their best work. We strongly encourage you to apply regardless of your location, background, race, gender, sexual orientation or any other personally defining attribute that make us different._

View File

@ -0,0 +1,4 @@
{
"label": "Bot市场",
"position": 8
}

View File

@ -0,0 +1,20 @@
---
sidebar_label: 'bot安装'
sidebar_position: 1
---
# bot安装
Bot安装是进行bot安装和管理控制的重要模块主要包括bot安装、安装查询、安装管理等功能。
在bot详情页用户点击“安装此Bot”按钮后可以看到该bot工作所需的各项权限信息。若用户同意授予bot所需的相关权限即可进行安装。用户可选择将bot安装到所有仓库用户拥有的所有仓库也可以选择指定的仓库进行安装。
![botinstall1](../../static/img/bot/botinstall1.png)
在个人“设置”或者“仓库设置”中用户可以看到目前已经安装的Bot情况点击“配置”按钮可以对bot安装情况进行配置点击“卸载”按钮可以进行卸载。
![botinstall2](../../static/img/bot/botinstall2.png)
在bot安装配置页中用户可以掌握该bot的安装位置和工作状态。若用户需要更改bot的工作仓库时可以进行更改安装位置。bot的工作状态包括激活和挂起用户可根据需要对bot的状态进行调整将其挂起或者激活会影响到bot对仓库数据的访问权限。
![botinstall3](../../static/img/bot/botinstall3.png)

View File

@ -0,0 +1,24 @@
---
sidebar_label: 'bot市场'
sidebar_position: 4
---
# Bot市场
Bot市场是进行Bot分享与复用的重要模块主要包括bot的搜索发现详情查看等功能。
Bot市场主页中展示了目前所有已经上架市场的bot简要信息包括bot的头像名称开发者简介和安装次数等信息用户可根据这些基本信息初步判断该bot是否符合自己的项目需求。
在bot市场主页中用户可以选择指定的bot种类筛选出特定分类的bot在这个种类范围内进行搜索与选择。
此外用户通过在搜索栏中输入关键字进行搜索可检索出内容包含指定关键字的相关bot。
用户可结合种类筛选和关键字搜索缩小范围在市场中快速找到符合项目相关需求的bot。
![botmarket1](../../static/img/bot/botmarket1.png)
在bot市场页中用户点击指定的bot卡片即可进入该bot的详情页。Bot的详情页包含bot的头像名称开发者种类和详细介绍等信息用户可在此掌握该bot的各项介绍进一步判断是否将其安装到指定仓库中。
![botmarket2](../../static/img/bot/botmarket2.png)
在bot详情页中若用户认为该bot满足自己的项目需求可点击“安装此Bot”按钮了解该bot的权限信息将其安装到指定的仓库中关于安装的更多介绍可见“Bot安装”部分。

View File

@ -0,0 +1,22 @@
---
sidebar_label: 'bot开发'
sidebar_position: 3
---
# Bot开发
Bot开发是开发者进行bot注册的重要模块。
在个人“设置”中用户可以看到目前已经注册的bot列表点击对应bot的“编辑”按钮可以对已注册的bot进行配置点击“Bot注册”按钮开始注册新的bot。
![botcreate1](../../static/img/bot/botcreate1.png)
在注册页中开发者需要填写bot注册的相关信息包括bot的名称、Webhook 地址详细介绍等系统将对开发者输入的信息进行合法性校验确保bot各项信息的完整性和有效性。此外系统将自动生成bot的唯一标识同时调用 GitLink 平台的相关接口生成bot的身份凭证信息包括客户端密钥和私钥等。
开发者需通过这些身份信息结合平台接口进行bot身份认证后调用相关接口完成bot的相关功能。
平台开发API链接待完善https://www.gitlink.org.cn/docs/api#introduction
![botcreate2](../../static/img/bot/botcreate2.png)
![botcreate3](../../static/img/bot/botcreate3.png)

View File

@ -0,0 +1,23 @@
---
sidebar_label: 'bot配置'
sidebar_position: 2
---
# Bot配置
Bot配置是开发者进行bot维护和配置的重要模块主要包括bot基本信息维护、权限&订阅事件管理、高级选项配置等功能。
Bot的基本信息维护中开发者可以看到bot的各项基本信息并可以根据需要对bot的头像名称Webhook地址等进行修改。
![botconfig1](../../static/img/bot/botconfig1.png)
Bot的权限&订阅事件管理中开发者可根据对仓库资源的访问需要为bot分配不同的权限和等级比如增加代码库权限将拉取请求的写权限变为读权限等。开发者还能更改当前bot订阅的事件列表比如订阅代码库推送取消拉取请求分配订阅等以实现bot功能的更新与升级。
![botconfig2](../../static/img/bot/botconfig2.png)
Bot高级选项配置中开发者可以改变bot的公私有状态从而影响到bot的使用范围。需要注意的是公开状态下的bot在已有其他仓库安装的情况下不能变成私有。开发者可选择将bot上架到市场需要填写上架信息包括市场简介主要功能次要功能等各项信息。
开发者还能进行bot的删除和转让操作发起转让意味着更改bot的所有权需要输入接受者的用户名。在接受者确定接受后即可完成bot的所有权变更拒绝则会取消本次的转让操作。
![botconfig3](../../static/img/bot/botconfig3.png)

View File

@ -0,0 +1,4 @@
{
"label": "DevOps引擎(Engine)",
"position": 6
}

View File

@ -0,0 +1,12 @@
---
sidebar_label: '代码流水线'
sidebar_position: 5
---
# 代码流水线
可以通过代码的形式(YAML格式)来配置流水线,首先选择代码流水线和对应的分支:
![code_workflow1](../../static/img/engine/code_workflow1.jpg)
编辑流水线代码,其流水线名称描述、触发器、全局参数、执行串行/并发和流水线编排等概念同图形流水线,具体描述如下:
![code_workflow2](../../static/img/engine/code_workflow2.png)

View File

@ -0,0 +1,15 @@
---
sidebar_label: '参数配置'
sidebar_position: 2
---
# 参数配置
可在流水线中使用,实现动态参数配置;有字符串、数字、布尔三种类型。
![parameter1](../../static/img/engine/parameter1.png)
在流水线的配置中通过如下方式获取参数:
![parameter2](../../static/img/engine/parameter2.png)

View File

@ -0,0 +1,50 @@
---
sidebar_label: '图形流水线'
sidebar_position: 4
---
# 图形流水线
## 基本信息
可以编辑流水线的名称、描述
同一仓库下的流水线名称不能重复
![vis_workflow1](../../static/img/engine/vis_workflow1.png)
## 触发器
注:流水线编排时,触发器要放在开始节点之前;目前一条流水线仅添加支持一个触发器
* 定时触发器cron可通过填写cron表达式设置触发的具体时间
![vis_workflow2](../../static/img/engine/vis_workflow2.png)
* 事件触发器GitLink_Webhook给出了常见的代码变更事件触发包括推送代码、合并请求、创建标签
![vis_workflow3](../../static/img/engine/vis_workflow3.png)
## 全局参数
添加后可在当前流水线中使用
![vis_workflow4](../../static/img/engine/vis_workflow4.png)
使用实例
![vis_workflow5](../../static/img/engine/vis_workflow5.png)
## 并发执行
![vis_workflow6](../../static/img/engine/vis_workflow6.png)
开启后同一流水线可同时并发执行n个流水线实例每触发一次我们得到一个流水线实例
![vis_workflow7](../../static/img/engine/vis_workflow7.png)
若未开启则当前流水线实例执行中后面的实例处于排队状态最多可排队5个实例。当前实例执行完成下一个实例开始执行。
![vis_workflow8](../../static/img/engine/vis_workflow8.png)
## 流水线编排
每条流水线必须要有一个开始节点、结束节点,至少一个任务节点。支持串行编排和并行编排。

View File

@ -0,0 +1,16 @@
---
sidebar_label: '密钥设置'
sidebar_position: 3
---
# 密钥设置
将账号密码、密钥、证书等存放到密钥管理里,配置后可直接在流水线中使用,避免因直接填写引起的泄露风险。
![secret1](../../static/img/engine/secret1.png)
使用示例
注:节点输入参数中,下拉选项为密钥类型,需要提前配置好密钥在流水线中选择使用
![secret2](../../static/img/engine/secret2.png)

View File

@ -0,0 +1,13 @@
---
sidebar_label: '引擎简介'
sidebar_position: 1
---
# 引擎
引擎(Engine)是GitLink提供的一款DevOps工具通过简单的节点编排来构建开发、测试、部署流水线从而创建自动化的软件交付流程。
它可以实现持续的代码集成,让开发者能尽早发现质量问题,快速定位修复,提升软件开发效率和质量;自动化的代码扫描、编译打包、单元测试,把研发团队从重复的工作中解放出来,聚焦到更有价值的事情上。
![engine_intro](../../static/img/engine/engine_intro.jpg)
在引擎页面中,用户可以创建和编辑图形流水线或代码流水线、设置外部参数、管理密钥等操作。

View File

@ -0,0 +1,10 @@
---
sidebar_label: '执行记录查询'
sidebar_position: 6
---
# 执行记录查询
用户可以查看流水线的运行状态
![result](../../static/img/engine/result.png)

View File

@ -1,91 +0,0 @@
---
title: Manage Audit logs Admin Portal
sidebar_label: Audit Logs
---
# Admin Portal
Retraced can be accessed using Admin interface that allows you to manage Projects & Environments via UI. To enable the Admin Portal, make sure you deploy [Retraced with Docker Compose](../retraced/self-host/docker.md)
You can open the Admin Portal on port `5225`.
## Sign into Admin Portal
We use [Magic Links](https://next-auth.js.org/providers/email) to authenticate users to the UI.
You'll need to set the following configuration in the [environment](../jackson/deploy/env-variables.md#admin-ui-configuration):
1. SMTP Server details, so we can send you the email with the magic link.
2. Access Control List which is an array of emails or glob patterns. Only these users will be allowed access to the Admin Portal. Example: `tonystark@gmail.com,*@marvel.com`.
Follow the below steps to login into the Admin dashboard.
- Visit the path `/api/auth/signin` on your app. The page will display a sign-in page with a text box to enter the email address.
- Enter the email address that matches the `NEXTAUTH_ACL` and click the button **Sign in with Email**.
- Open the inbox and you'll see an email from Jackson.
- Open that email and click the button **Sign in**. Now you've successfully logged into the BoxyHQ Admin Portal.
- Click on the Audit Logs menu from the sidebar on the left to access the Retraced service.
## Fresh Start
When you are setting up the Audit logs for the first time with Retraced, you won't have any **Projects** in the system or in case you run bootstrap script as a part of your deployment you will have **dev** project.
![fresh start](/images/product_images/admin-ui-retraced/fresh-start.png)
## Create Project
Just click on **Create Project** or **Add Project** button to initiate new Project creation.
You just need to enter the name of the project and click on **Create Project** button.
![create project](/images/product_images/admin-ui-retraced/create-project.png)
## Project Information
You will get see the **Project Information** after the Project is created.
This page shows,
1. Project ID
2. Production Token
3. Staging Token
4. Publisher API Base URL
5. POST request URL to ingest your events
6. Example CURL command to send test events
![project info](/images/product_images/admin-ui-retraced/project-info.png)
## Send test event with CURL
You can copy and paste the curl command in terminal or command prompt.
After execution of command you should see **id & hash** as output.
![curl request](/images/product_images/admin-ui-retraced/curl-request.png)
## Project List
Now if you click on Audit Logs you should see newly created Project there.
You can perform following actions:
- You can click on first button under actions the **tools** button to open the **Project Information** page.
- You can click on second button under actions, the button with **magnifying glass** to see the **logs**.
![project list page](/images/product_images/admin-ui-retraced/project-list-page.png)
## Select Environment & Group
When you create a Project by default following environments are created
- Production
- Staging
Every Environment can have multiple Tenants.
![select environment](/images/product_images/admin-ui-retraced/select-environment.png)
## View Logs
Once you select the Environment you will see the Tenants listed in the dropdown.
For this example you will see **BoxyHQ** listed in the dropdown for **Staging Environment**.
Once you select the **Tenant** you will the logs listed down on the page.
![select groups](/images/product_images/admin-ui-retraced/select-groups.png)

View File

@ -1,81 +0,0 @@
---
title: Manage Directory Sync using Admin Portal
sidebar_label: Directory Sync
---
# Manage Directories
On the Admin Portal **Directory Sync** menu, you can see the Directory connections.
## Create Directory Sync connection
1. From your Admin Portal, go to **Directory Sync**.
2. Click **Create New**.
3. Enter the following information:
- Enter **Directory name**
- Select the **Directory provider** from the list of [available providers](../directory-sync/providers/).
- Add the **Tenant**
- Add the **Product**
- Enter the **Webhook URL**
- Enter the **Webhook secret**
![Create Directory](/img/dsync/admin/create-directory.png)
---
## Update Directory Sync connection
1. From your Admin Portal, go to **Directory Sync**.
2. From the list of directory sync connections, click edit icon.
3. You can update the following information:
- Enter **Directory name**
- Enter the **Webhook URL**
- Enter the **Webhook secret**
- Toggle **Enable Webhook events logging**
![Update Directory](/img/dsync/admin/update-directory.png)
---
## View directory users
1. From your Admin Portal, go to **Directory Sync**.
2. From the list of directory sync connections, click database icon.
3. Click the tab **Users**.
4. Click the eye icon to view the user raw JSON data.
![Users](/img/dsync/admin/users.png)
---
## View directory groups
1. From your Admin Portal, go to **Directory Sync**.
2. From the list of directory sync connections, click database icon.
3. Click the tab **Groups**.
4. Click the eye icon to view the group raw JSON data.
![Groups](/img/dsync/admin/groups.png)
---
## View webhook events
1. From your Admin Portal, go to **Directory Sync**.
2. From the list of directory sync connections, click database icon.
3. Click the tab **Webhook Events**.
4. Click the eye icon to view the event raw JSON data.
![Logs](/img/dsync/admin/logs.png)
Click the button **Clear Events** to delete all events from the database.
---
## Enable webhook events logging
1. From your Admin Portal, go to **Directory Sync**.
2. From the list of directory sync connections, click edit icon.
3. You can enable or disable the **Enable Webhook events logging**.
By default, the webhook events are not logged.

View File

@ -1,90 +0,0 @@
---
title: Manage Enterprise SSO using Admin Portal
sidebar_label: Enterprise SSO
---
# Manage SSO Connections
On the Admin Portal **Enterprise SSO** menu, you can see the SSO Connections details.
## Add SAML Connections
Once you've set up the SAML app on your Identity Provider, the Identity Provider will generate a SAML Metadata file.
The SAML metadata file contains information about the various SAML Authorities that can be used in SAML 2.0 protocol message exchanges.
Download the SAML Metadata file from your IdP and follow the below steps for adding the SAML connection.
- Click the button **New Connection**.
- Choose **SAML** as the type.
- Give your new connection a **name**.
- Add your **Tenant** (Eg: boxyhq.com) and **Product** (Eg: flex).
- Add **Allowed redirect URLs**.
- Add **Default redirect URL**.
- Paste the **Raw IdP XML**.
- If **ForceAuthn** is checked, it means that the user will be forced to re-authenticate at SAML IdP, even if they have an active session.
- Click the button **Save Changes**.
Now you've successfully added your first SAML connection.
## Add OIDC Connections
Once you've registered the OIDC app on your Identity Provider, the Identity Provider will generate a clientId and clientSecret.
The `clientSecret` will be used to authenticate the oidc client (in this case jackson) and obtain the `access_token`.
Also get the OpenID provider [discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig) endpoint (usually ending in `/.well-known/openid-configuration`) and follow the below steps for adding the OIDC connection.
- Click the button **New Connection**.
- Choose **OIDC** as the type.
- Give your new connection a **name**.
- Add your **Tenant** (Eg: boxyhq.com) and **Product** (Eg: flex).
- Add **Allowed redirect URLs**.
- Add **Default redirect URL**.
- Enter the URL for OpenID Provider discovery which exposes the Provider Metadata.
- Paste the **clientId** and **clientSecret** values into Client ID [OIDC Provider]/Client Secret [OIDC Provider] fields in the UI.
- Click the button **Save Changes**.
Now you've successfully added your first OIDC connection.
## SAML Federation
SAML Federation is an enterprise feature and you need to have an enterprise license to use this feature.
From the **Admin Portal** go to **Enterprise SSO** > **SAML Federation**.
### Create SAML Federation App
- Click **New App**.
- Enter the following information:
- **Name**
- **Tenant**
- **Product**
- **ACS URL** (ACS URL of the SP)
- **Entity ID** (Entity ID of the SP)
![Create SAML Federation App](/img/saml-federation/admin/create-saml-federation-app.png)
---
### Update SAML Federation App
- From the list of SAML Federation Apps, click on the **Edit** icon of the app you want to update.
- You can update the following information:
- **Name**
- **ACS URL** (ACS URL of the SP)
- **Entity ID** (Entity ID of the SP)
![Update SAML Federation App](/img/saml-federation/admin/update-saml-federation-app.png)
---
### View IdP Configuration
Click **View IdP Configuration** button to view the IdP configuration for the SAML Federation App. You need to provide the SP with the following information:
- **SSO URL**
- **Entity ID / Audience URI / Audience Restriction**
- **X.509 Certificate**
![View IdP Configuration](/img/saml-federation/admin/view-idp-configuration.png)

View File

@ -1,77 +0,0 @@
---
title: Get Started with Admin Portal
sidebar_label: Get Started
---
# Get Started with Admin Portal
SAML Jackson comes with an Admin Portal that allows you to manage **Enterprise SSO**, **Directory Sync**, **Setup Links**, and **Audit Logs** products via an easy to use web interface.
Our future products (where relevant) will also be available in the Admin Portal.
To enable the Admin Portal, make sure you deploy [Jackson as a service](../jackson/deploy/service).
## Authentication Methods
BoxyHQ SAML Jackson supports multiple authentication methods. You can choose to use any of the following methods to authenticate users to the Admin Portal.
We use [NextAuth](https://next-auth.js.org) to handle authentication. Set the following environment variables to configure the authentication.
- `NEXTAUTH_URL`: The URL of your app.
- `NEXTAUTH_SECRET`: A secret used to encrypt the session cookie. You can generate one using `openssl rand -base64 32`
### 1. Magic Links
With Magic Links, you can sign in to the Admin Portal without having to enter a password. The app will send you an email with a link to sign in. You'll need **SMTP server credentials** to send emails.
Configure the following environment variables to enable Magic Links.
- `SMTP_HOST`: SMTP server host
- `SMTP_PORT`: SMTP server port
- `SMTP_USER`: SMTP server username
- `SMTP_PASSWORD`: SMTP server password
- `SMTP_FROM`: From email address to use when sending Magic Link emails
- `NEXTAUTH_ACL`: An array of emails or glob patterns. Only these users will be allowed access to the Admin Portal. For example: `NEXTAUTH_ACL=tonystark@gmail.com,*@marvel.com`
Follow the below steps to login into the Admin Portal.
- Visit the path `/api/auth/signin` on your app.
- Enter the email address that matches the `NEXTAUTH_ACL` and click the button **Send Magic Link**.
- Open the inbox and you'll see an email from SAML Jackson.
- Open that email and click the button **Sign in**.
### 2. Email and Password
With Email and Password, you can sign in to the Admin Portal using an email address and password. You can use it as an alternative to Magic Links or SAML Single Sign-On. This is the easiest way to get started with the Admin Portal.
Configure the environment variable to enable Email and Password authentication.
- `NEXTAUTH_ADMIN_CREDENTIALS`: A comma separated list of email and password pairs. For example: `david@acme.com:secretpassword,john@acme.com:anotherpassword`
At the moment, set the password as plain text. We'll add support for encrypted passwords soon.
Follow the below steps to login into the Admin Portal.
- Visit the path `/api/auth/signin` on your app.
- Enter the email address and password that matches the `NEXTAUTH_ADMIN_CREDENTIALS` and click the button **Sign In**.
### 3. SAML/OIDC Single Sign-On
With SAML/OIDC Single Sign-On, you can sign in to the Admin Portal using your Identity Provider. The app will redirect you to your Identity Provider to sign in. Once you've signed in, you'll be redirected back to the Admin Portal.
Configure the following environment variables to enable SAML/OIDC Single Sign-On.
- `ADMIN_PORTAL_SSO_TENANT`: This will be used as the tenant for the SSO connections. Set this to a value that is less likely to conflict with the main Enterprise SSO connections.
- `ADMIN_PORTAL_SSO_PRODUCT`: This will be used as the product for the SSO connections. Set this to a value that is less likely to conflict with the main Enterprise SSO connections.
If not set, the default values will be used which are `_jackson_boxyhq` and `_jackson_admin_portal`.
To enable SAML/OIDC Single Sign-On, you'll need to access the Admin Portal using either [Magic Links](#1-magic-links) or [Email and Password](#2-email-and-password). Once you've logged in, you can configure SAML/OIDC Single Sign-On from the Admin Portal.
Go to **Settings** > **SSO for Admin Portal** and add a new SSO connection. We support both SAML and OIDC protocols.
Follow the below steps to login into the Admin Portal.
- Visit the path `/api/auth/signin` on your app.
- Click the button **Login with SSO**.
- You'll be redirected to your SAML Identity Provider to sign in for the authentication and then redirected back to the Admin Portal.

View File

@ -1,64 +0,0 @@
---
title: Setup Link (Directory-Sync)
sidebar_label: Directory Sync
description: Setup Link to create a Directory Sync
---
# Setup Link (Directory Sync)
The Setup link is used to create a shareable link that can be used to create an Directory Sync without exposing any sensitive information.
Let's go through the steps to create a new Setup link
## Create Setup Link
You can create a new Setup link for Directory Sync from the Connections page using `New Setup Link` button
![dsync connections page](/images/product_images/setup-link/dsync/dsync-connections-page.png)
Another way is to go to the `Setup Links` section under `Directory Sync` menu and Click on Create New/New Setup Link button
![dsync setup link list empty](/images/product_images/setup-link/dsync/dsync-setup-link-list-empty.png)
The create Setup Link for Directory Sync page looks like below
![dsync setup link create page](/images/product_images/setup-link/dsync/dsync-setup-link-create-page.png)
Once the link is created you can see the the link info section at the bottom
![setup link created](/images/product_images/setup-link/dsync/setup-link-created.png)
You can copy the link by clicking on the `Copy` button
![setup link copied](/images/product_images/setup-link/dsync/setup-link-copied.png)
### Regenerate Link
You can regenerate the link by clicking on `Regenerate` button
![setup link regenerate init](/images/product_images/setup-link/dsync/setup-link-regenerate-init.png)
Once you confirm Regenerate action you will see the new setup link in the link info section
![setup link regenerated](/images/product_images/setup-link/dsync/setup-link-regenerated.png)
### Actions from Setup Link list page
You can perform `ACTIONS` like `Copy`, `View`, `Regenerate` & `Delete` from this page
![setup link list page](/images/product_images/setup-link/dsync/setup-link-list-page.png)
### Setup Link Page
When you open the setup link you will see the following
![setup link page dsync](/images/product_images/setup-link/dsync/setup-link-page-dsync.png)
### Create Directory Sync Connection
You can open create Directory Sync by clicking on `New Directory` button & filling the correct details
![dsync setup link created](/images/product_images/setup-link/dsync/dsync-setup-link-created.png)
After creation of the directory sync you will see the info section
![dsync created info](/images/product_images/setup-link/dsync/dsync-created-info.png)

View File

@ -1,9 +0,0 @@
# Setup Link
Admin portal can be used to create setup links for
- [Enterprise SSO](./jackson)
- [Directory-Sync](./directory-sync)
Setup links can be shared with anyone to let them set up connections for the products.
These links come in handy for admins to facilitate setup by non-admin users without revealing any sensitive information or giving admin access unnecessarily.

View File

@ -1,68 +0,0 @@
---
title: Setup Link (Enterprise SSO)
sidebar_label: Enterprise SSO
description: Setup Link to create a SSO Connection
---
# Setup Link (Enterprise SSO)
The Setup link is used to create a shareable link that can be used to create an SSO Connection without exposing any sensitive information.
Let's go through the steps to create a new Setup link
## Create Setup Link
You can create a new Setup link for SSO from the Connections page using `New Setup Link` button
![connections page](/images/product_images/setup-link/sso/connections-page.png)
Another way is to go to the `Setup Links` section under `Enterprise SSO` menu and Click on Create New/New Setup Link button
![setup link list empty](/images/product_images/setup-link/sso/setup-link-list-empty.png)
The create Setup Link for SSO page looks like below
![create setup link page](/images/product_images/setup-link/sso/create-setup-link-page.png)
Once the link is created you can see the the link info section at the bottom
![link created](/images/product_images/setup-link/sso/link-created.png)
You can copy the link by clicking on the `Copy` button
![link copied](/images/product_images/setup-link/sso/link-copied.png)
### Regenerate Link
You can regenerate the link by clicking on `Regenerate` button
![link regenerate](/images/product_images/setup-link/sso/link-regenerate.png)
Once you confirm Regenerate action you will see the new setup link in the link info section
![link regenerated](/images/product_images/setup-link/sso/link-regenerated.png)
### Actions from Setup Link list page
#### You can perform `ACTIONS` like `Copy`, `View`, `Regenerate` & `Delete` from this page
Regenerate
![link regenerate from list](/images/product_images/setup-link/sso/link-regenerate-from-list.png)
Delete
![link delete](/images/product_images/setup-link/sso/link-delete.png)
### Setup Link page
When you open the setup link you will be landed on SSO Connection create section as there are no connections to show
![setup link sso setup](/images/product_images/setup-link/sso/setup-link-sso-setup.png)
### Create SSO Connection with Setup Link
You can create SSO Connection by filling the correct details
![setup link sso oidc](/images/product_images/setup-link/sso/setup-link-sso-oidc.png)
As you can see that setup link makes it super easy & safe to create SSO Connections.

View File

@ -1,648 +0,0 @@
---
title: Directory Sync API Reference
sidebar_label: API Reference
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# API Reference
The following guides provide information about the APIs and SDKs that are available for the Directory Sync service.
### Directory
#### Properties
- `name`: The name of the directory
- `tenant`: The tenant ID of the tenant you want to create the directory for.
- `product`: The product ID of the product you want to create the directory for.
- `type`: The directory provider type. See the [Directory Providers](./providers) for more information.
- `webhook_url`: The webhook URL to which the directory connection will POST the events.
- `webhook_secret`: The webhook secret used to sign the webhook payload.
:::info
The `tenant` and `product` should not contain the `:` character since we use it as a delimiter internally.
:::
### Initialize Directory Sync
```javascript
const opts = {
externalUrl: 'https://my-cool-app.com',
db: {
engine: 'mongo',
url: 'mongodb://localhost:27017/my-cool-app',
},
};
let directorySyncController;
// Please note that the initialization of @boxyhq/saml-jackson is async, you cannot run it at the top level.
async function init() {
const jackson = await require('@boxyhq/saml-jackson').controllers(opts);
directorySyncController = jackson.directorySyncController;
}
```
### Create a new directory
Create a new directory connection.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const { data, error } = await directorySyncController.directories.create({
name: 'App',
tenant: 'boxyhq',
product: 'jackson',
type: 'onelogin-scim-v2',
webhook_url: 'https://my-cool-app.com/webhook',
webhook_secret: 'my-secret',
});
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request POST \
--url http://localhost:5225/api/v1/directory-sync \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json' \
--data '{
"name": "App",
"tenant": "boxyhq",
"product": "jackson",
"type": "onelogin-scim-v2",
"webhook_url": "https://my-cool-app.com/webhook",
"webhook_secret": "my-secret"
}'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": {
"id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"name": "App",
"tenant": "boxyhq",
"product": "jackson",
"type": "onelogin-scim-v2",
"log_webhook_events": false,
"scim": {
"path": "/api/scim/v2.0/58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"secret": "IJzAoevjD_liiiy-VkDtXg",
"endpoint": "http://localhost:5225/api/scim/v2.0/58b5cd9dfaa39d47eb8f5f88631f9a629a232016"
},
"webhook": {
"endpoint": "https://my-cool-app.com/webhook",
"secret": "my-secret"
}
},
"error": null
}
```
---
### Get directories
Get the list of directories for the given tenant and product. A tenant can have multiple directories for same or different products.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const tenant = 'boxyhq';
const product = 'jackson';
const { data, error } =
await directorySyncController.directories.getByTenantAndProduct(
tenant,
product
);
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request GET \
--url 'http://localhost:5225/api/v1/directory-sync?tenant=boxyhq&product=jackson' \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": [
{
"id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"name": "App",
"tenant": "boxyhq",
"product": "jackson",
"type": "onelogin-scim-v2",
"log_webhook_events": false,
"scim": {
"path": "/api/scim/v2.0/58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"secret": "IJzAoevjD_liiiy-VkDtXg",
"endpoint": "http://localhost:5225/api/scim/v2.0/58b5cd9dfaa39d47eb8f5f88631f9a629a232016"
},
"webhook": {
"endpoint": "https://my-cool-app.com/webhook",
"secret": "my-secret"
}
}
],
"error": null
}
```
---
### Get a directory
Get the details of a directory by its unique id.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const directoryId = '58b5cd9dfaa39d47eb8f5f88631f9a629a232016';
const { data, error } = await directorySyncController.directories.get(
directoryId
);
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request GET \
--url 'http://localhost:5225/api/v1/directory-sync/58b5cd9dfaa39d47eb8f5f88631f9a629a232016' \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": {
"id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"name": "App",
"tenant": "boxyhq",
"product": "jackson",
"type": "onelogin-scim-v2",
"log_webhook_events": false,
"scim": {
"path": "/api/scim/v2.0/58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"secret": "IJzAoevjD_liiiy-VkDtXg",
"endpoint": "http://localhost:5225/api/scim/v2.0/58b5cd9dfaa39d47eb8f5f88631f9a629a232016"
},
"webhook": {
"endpoint": "https://my-cool-app.com/webhook",
"secret": "my-secret"
}
},
"error": null
}
```
---
### List directory users
List all the users in a directory.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const tenant = 'boxyhq';
const product = 'jackson';
const { data, error } = await directorySyncController.users
.setTenantAndProduct(tenant, product)
.getAll();
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request GET \
--url 'http://localhost:5225/api/v1/directory-sync/users?tenant=boxyhq&product=jackson' \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": [
{
"id": "6296f71e-15fd-4af4-86ee-d6623b3ef1a4",
"first_name": "Aswin",
"last_name": "Venugopal",
"email": "aswin@boxyhq.com",
"active": true,
"raw": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User"
],
"userName": "aswin@boxyhq.com",
"name": {
"givenName": "Aswin",
"familyName": "Venugopal",
"honorificPrefix": "Sir"
},
"emails": [
{
"primary": true,
"value": "aswin@boxyhq.com",
"type": "work"
}
],
"displayName": "Aswin Venugopal",
"addresses": [
{
"primary": true,
"postalCode": "123"
}
],
"locale": "en-US",
"externalId": "00u34iw1hm16RmjS95d7",
"groups": [],
"active": true,
"id": "6296f71e-15fd-4af4-86ee-d6623b3ef1a4"
}
},
{
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"first_name": "Kiran",
"last_name": "Krishnan",
"email": "kiran@boxyhq.com",
"active": true,
"raw": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User"
],
"userName": "kiran@boxyhq.com",
"name": {
"givenName": "Kiran",
"familyName": "Krishnan"
},
"emails": [
{
"primary": true,
"value": "kiran@boxyhq.com",
"type": "work"
}
],
"displayName": "Kiran Krishnan",
"addresses": [
{
"primary": true,
"region": "Kerala"
}
],
"locale": "en-US",
"externalId": "00u3e3cmpdDydXdzV5d7",
"groups": [],
"active": true,
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92"
}
}
],
"error": null
}
```
---
### Get a directory user
Get the details of a directory user.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const tenant = 'boxyhq';
const product = 'flex';
const userId = 'ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92';
const users = await directorySyncController.users
.setTenantAndProduct(tenant, product)
.get(userId);
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request GET \
--url 'http://localhost:5225/api/v1/directory-sync/users/ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92?tenant=boxyhq&product=jackson' \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": {
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"first_name": "Kiran",
"last_name": "Krishnan",
"email": "kiran@boxyhq.com",
"active": true,
"raw": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User"
],
"userName": "kiran@boxyhq.com",
"name": {
"givenName": "Kiran",
"familyName": "Krishnan"
},
"emails": [
{
"primary": true,
"value": "kiran@boxyhq.com",
"type": "work"
}
],
"displayName": "Kiran Krishnan",
"addresses": [
{
"primary": true,
"region": "Kerala"
}
],
"locale": "en-US",
"externalId": "00u3e3cmpdDydXdzV5d7",
"groups": [],
"active": true,
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92"
}
},
"error": null
}
```
---
### List directory groups
List all the groups in a directory.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const tenant = 'boxyhq';
const product = 'jackson';
const users = await directorySyncController.groups
.setTenantAndProduct(tenant, product)
.getAll();
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request GET \
--url 'http://localhost:5225/api/v1/directory-sync/groups?tenant=boxyhq&product=jackson' \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": [
{
"id": "44d08c0e-d185-4a5e-80a6-b47a717ffaa5",
"name": "Developers",
"raw": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:Group"
],
"displayName": "Developers",
"members": [
{
"value": "6296f71e-15fd-4af4-86ee-d6623b3ef1a4",
"display": "aswin@boxyhq.com"
},
{
"value": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"display": "kiran@boxyhq.com"
}
],
"id": "44d08c0e-d185-4a5e-80a6-b47a717ffaa5"
}
}
],
"error": null
}
```
---
### Get a directory group
Get the details of a directory group.
#### Request
<Tabs>
<TabItem value="01" label="Node.js" default>
```javascript showLineNumbers
const tenant = 'boxyhq';
const product = 'jackson';
const groupId = '44d08c0e-d185-4a5e-80a6-b47a717ffaa5';
const users = await directorySyncController.groups
.setTenantAndProduct(tenant, product)
.get(groupId);
```
</TabItem>
<TabItem value="02" label="Shell">
```bash
curl --request GET \
--url 'http://localhost:5225/api/v1/directory-sync/groups/44d08c0e-d185-4a5e-80a6-b47a717ffaa5?tenant=boxyhq&product=jackson' \
--header 'Authorization: Api-Key secret' \
--header 'Content-Type: application/json'
```
</TabItem>
</Tabs>
#### Response
```javascript
{
"data": {
"id": "44d08c0e-d185-4a5e-80a6-b47a717ffaa5",
"name": "Developers",
"raw": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:Group"
],
"displayName": "Developers",
"members": [
{
"value": "6296f71e-15fd-4af4-86ee-d6623b3ef1a4",
"display": "aswin@boxyhq.com"
},
{
"value": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"display": "kiran@boxyhq.com"
}
],
"id": "44d08c0e-d185-4a5e-80a6-b47a717ffaa5"
},
"members": [
{
"group_id": "44d08c0e-d185-4a5e-80a6-b47a717ffaa5",
"user_id": "6296f71e-15fd-4af4-86ee-d6623b3ef1a4"
},
{
"group_id": "44d08c0e-d185-4a5e-80a6-b47a717ffaa5",
"user_id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92"
}
]
},
"error": null
}
```
---
### Handle the Requests from Identity Providers
Make sure your application can handle the requests from Identity Providers.
#### Routes
Typically, you will want to add the following routes to your application to handle the requests. However, the `Methods` can vary for some Identity Providers.
| Route | Methods | Event |
| ----------- | ---------- | ---------------------------------------------- |
| /Users | POST | A new user has been assigned to a SCIM app |
| /Users/:id | PUT, PATCH | A user information has been updated |
| /Users/:id | DELETE | A user has been removed from a SCIM app |
| /Groups | POST | A new group has been pushed |
| /Groups/:id | PUT | Group name has been changed |
| /Groups/:id | PATCH | User has been added to or removed from a group |
| /Groups/:id | DELETE | Group has been removed |
#### User Requests
```javascript showLineNumbers
const { data, status } = await directorySyncController.requests.handle(request);
```
The shape of the `request` should be as follows:
```javascript
{
method: HTTPMethod;
body?: any;
directoryId: string;
resourceId: string;
resourceType: "users",
apiSecret: string;
query: {
count?: number;
startIndex?: number;
filter?: string;
};
};
```
#### Group Requests
Handling the group requests is similar to handling the user requests.
```javascript showLineNumbers
const { data, status } = await directorySyncController.requests.handle(request);
```
The shape of the `request` should be as follows:
```javascript
{
method: HTTPMethod;
body?: any;
directoryId: string;
resourceId: string;
resourceType: "groups",
apiSecret: string;
query: {
count?: number;
startIndex?: number;
filter?: string;
};
};
```
#### Callback Function
You can optionally pass a callback function as a second parameter to the handle method `requests.handle`. Jackson will invoke the callback with the event object as the first argument after handling the request. You can use the event object to determine the action to take.
```javascript showLineNumbers
const callback = (event: DirectorySyncEvent) => {
console.log(event);
};
const { data, status } = await directorySyncController.requests.handle(
request,
callback
);
```

View File

@ -1,476 +0,0 @@
---
title: Directory Sync Webhook Events
sidebar_label: Events
---
# Events
SAML Jackson uses webhooks to notify your application any time changes are made to directory, users, groups, and memberships.
## User Events
We'll notify you of the following 3 events related to users. Each event will be sent to the webhook URL you've configured in the Directory Sync app.
<details>
<summary>user.created - New user has been assigned to the app.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "user.created",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "038e767b-9bc6-4dbd-975e-fbc38a8e7d82",
"first_name": "Deepak",
"last_name": "Prabhakara",
"email": "deepak@boxyhq.com",
"active": true,
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "deepak@boxyhq.com",
"name": {
"givenName": "Deepak",
"familyName": "Prabhakara"
},
"emails": [
{
"primary": true,
"value": "deepak@boxyhq.com",
"type": "work"
}
],
"title": "CEO",
"displayName": "Deepak Prabhakara",
"locale": "en-US",
"externalId": "00u1ldzzogFkXFmvT5d7",
"groups": [],
"active": true,
"id": "038e767b-9bc6-4dbd-975e-fbc38a8e7d82"
}
}
}
```
</p>
</details>
<details>
<summary>user.updated - A user's properties has been updated.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "user.updated",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"first_name": "Kiran",
"last_name": "Krishnan",
"email": "kiran@boxyhq.com",
"active": true,
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "kiran@boxyhq.com",
"name": {
"givenName": "Kiran",
"familyName": "Krishnan"
},
"emails": [
{
"primary": true,
"value": "kiran@boxyhq.com",
"type": "work"
}
],
"displayName": "Kiran Krishnan",
"addresses": [
{
"primary": true,
"region": "Kerala"
}
],
"locale": "en-US",
"externalId": "00u3e3cmpdDydXdzV5d7",
"active": true,
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"groups": []
}
}
}
```
</p>
</details>
<details>
<summary>user.deleted - A user has been removed from the Directory Provider.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "user.deleted",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"first_name": "Kiran",
"last_name": "Krishnan",
"email": "kiran@boxyhq.com",
"active": false,
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "kiran@boxyhq.com",
"name": {
"givenName": "Kiran",
"familyName": "Krishnan"
},
"emails": [
{
"primary": true,
"value": "kiran@boxyhq.com",
"type": "work"
}
],
"displayName": "Kiran Krishnan",
"addresses": [
{
"primary": true,
"region": "Kerala"
}
],
"locale": "en-US",
"externalId": "00u3e3cmpdDydXdzV5d7",
"active": false,
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"groups": []
}
}
}
```
</p>
</details>
## Group Events
We'll notify you of the following 5 events related to groups and memberships. Each event will be sent to the webhook URL you've configured in the Directory Sync app.
<details>
<summary>group.created - New group has been added to the app.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "group.created",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6",
"name": "dev",
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "dev",
"members": [],
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6"
}
}
}
```
</p>
</details>
<details>
<summary>group.updated - A group's properties has been updated.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "group.updated",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6",
"name": "developers",
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "developers",
"members": [],
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6"
}
}
}
```
</p>
</details>
<details>
<summary>group.deleted - A group has been removed from the app.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "group.deleted",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6",
"name": "developers",
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "developers",
"members": [],
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6"
}
}
}
```
</p>
</details>
<details>
<summary>group.user_added - A user has been added to a directory group.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "group.user_added",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"first_name": "Kiran",
"last_name": "Krishnan",
"email": "kiran@boxyhq.com",
"active": true,
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "kiran@boxyhq.com",
"name": {
"givenName": "Kiran",
"familyName": "Krishnan"
},
"emails": [
{
"primary": true,
"value": "kiran@boxyhq.com",
"type": "work"
}
],
"displayName": "Kiran Krishnan",
"addresses": [
{
"primary": true,
"region": "Kerala"
}
],
"locale": "en-US",
"externalId": "00u3e3cmpdDydXdzV5d7",
"active": true,
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"title": "Developer",
"groups": []
},
"group": {
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6",
"name": "developers",
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "developers",
"members": [],
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6"
}
}
}
}
```
</p>
</details>
<details>
<summary>group.user_removed - A user has been removed from a directory group.</summary>
<p>
```json
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "group.user_removed",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"first_name": "Kiran",
"last_name": "Krishnan",
"email": "kiran@boxyhq.com",
"active": true,
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "kiran@boxyhq.com",
"name": {
"givenName": "Kiran",
"familyName": "Krishnan"
},
"emails": [
{
"primary": true,
"value": "kiran@boxyhq.com",
"type": "work"
}
],
"displayName": "Kiran Krishnan",
"addresses": [
{
"primary": true,
"region": "Kerala"
}
],
"locale": "en-US",
"externalId": "00u3e3cmpdDydXdzV5d7",
"active": true,
"id": "ebc31d6e-7d62-4f81-b9e5-eb5f1a04ee92",
"title": "Developer",
"groups": []
},
"group": {
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6",
"name": "developers",
"raw": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"displayName": "developers",
"members": [],
"id": "29e3adde-b4bb-45fc-bf65-2b44f29fd6f6"
}
}
}
}
```
</p>
</details>
## Directory Events
We'll notify you of the following 4 events related to the directory connections.
To configure the webhook, you have to set the following environment variables.
- `WEBHOOK_URL` - The URL to which the webhook events will be sent.
- `WEBHOOK_SECRET` - The secret key used to sign the webhook events.
<details>
<summary>
dsync.created - New connection has been created.
</summary>
<p>
```json
{
"event": "dsync.created",
"tenant": "boxyhq",
"product": "demo",
"data": {
"id": "d8aa6c93-c960-4925-9b31-4a4d2ad3bb44",
"name": "Okta Directory",
"type": "okta-scim-v2"
}
}
```
</p>
</details>
<details>
<summary>
dsync.deactivated - A connection has been deactivated.
</summary>
<p>
```json
{
"event": "dsync.deactivated",
"tenant": "boxyhq",
"product": "demo",
"data": {
"id": "d8aa6c93-c960-4925-9b31-4a4d2ad3bb44",
"name": "Okta Directory",
"type": "okta-scim-v2"
}
}
```
</p>
</details>
<details>
<summary>
dsync.activated - A connection has been activated.
</summary>
<p>
```json
{
"event": "dsync.activated",
"tenant": "boxyhq",
"product": "demo",
"data": {
"id": "d8aa6c93-c960-4925-9b31-4a4d2ad3bb44",
"name": "Okta Directory",
"type": "okta-scim-v2"
}
}
```
</p>
</details>
<details>
<summary>
dsync.deleted - A connection has been deleted.
</summary>
<p>
```json
{
"event": "dsync.deleted",
"tenant": "boxyhq",
"product": "demo",
"data": {
"id": "d8aa6c93-c960-4925-9b31-4a4d2ad3bb44",
"name": "Okta Directory",
"type": "okta-scim-v2"
}
}
```
</p>
</details>
## Frequently Asked Questions
### How to determine whether a user has been deleted if the Identity Provider does not send a webhook event for user deletion?
To receive notifications when a user is deleted, it's important to note that not all Identity Providers send requests for this. However, you can listen for the `user.updated` event from SAML Jackson and examine the `active` property to determine whether a user has been deleted. In case the user is deleted, the `active` property will be assigned the value `false`.
### Which Identity Providers do not send an event for user deletion?
Following Identity Providers do not send `user.deleted` event:
- Okta
- Azure AD
### Which SCIM version does SAML Jackson support?
At the moment, SAML Jackson supports SCIM version 2.0.

View File

@ -1,16 +0,0 @@
---
title: Examples & Resources (Directory Sync)
sidebar_label: Examples & Resources
description: Examples & Resources for our Directory Sync product
---
# Examples & Resources (Directory Sync)
## Examples
- [Directory Sync with Next.js](https://github.com/boxyhq/jackson-examples/tree/main/apps/directory-sync)
- [Directory Sync (embedded as a library) with Next.js](https://github.com/boxyhq/jackson-examples/tree/main/apps/directory-sync-embedded)
## Resources
- [SCIM 2.0 Protocol](https://datatracker.ietf.org/doc/html/rfc7644)

View File

@ -1,29 +0,0 @@
---
title: Getting Started
sidebar_label: Getting Started
---
There are two ways to integrate the Directory Sync within your application.
## As a service
The advantage of running a separate service is that you get all of our UI tooling (like the Admin Portal) with the service. The disadvantage is that you have to manage the operations of a separate service.
**If you are not using Node.js then this is the only option available to you.**
Read more about [how to run the Jackson service](/docs/jackson/deploy/service)
Jackson use webhooks to notify your application any time changes are made to directory users and groups. You can use webhooks to trigger actions in your application, such as creating a new user in your application, or updating a user in your application based on the changes made in the directory.
## As an NPM library
This is available if you are already developing your application using Node.js.
The advantage of embedding Jackson as an NPM library is that you do not have to manage operations of a separate service.
The disadvantage is that you do not readily get our UI tooling (like the Admin Portal) with this method.
```bash
npm i --save @boxyhq/saml-jackson
```
See the [API Reference](/docs/directory-sync/api-reference) to understand more about the available methods.

View File

@ -1,23 +0,0 @@
---
title: Directory Sync Docs
---
# Directory Sync
Directory sync helps organizations automate the provisioning and de-provisioning of their users. It is based on the System for Cross-domain Identity Management (SCIM) protocol.
As a result, it streamlines the user lifecycle management process by saving valuable organizational hours, creating a single truth source of the user identity data, and facilitating them to keep the data secure.
Directory Sync is part of our SAML Jackson service (and npm library) from v1.2.1 onwards. Follow the instructions in [SAML Jackson](../jackson/deploy/index.md) for details on deployment. Or check out our [GitHub repo](https://github.com/boxyhq/jackson#directory-sync).
We currently only support SCIM 2.0 protocol because SCIM 1.1 is deprecated and support will be discontinued on December 2nd, 2022. If you still need support for SCIM 1.1 and are unable to move away from it then please contact us.
![Directory Sync Flow](/img/dsync/directory-sync-flow.png)
## Overview
- [API Reference](api-reference)
- [Admin Portal](../admin-portal/directory-sync)
- [Webhook](webhooks)
- [Events and Types](events)
- [Directory Sync Providers](providers)

View File

@ -1,74 +0,0 @@
---
title: Azure AD SCIM v2.0
sidebar_label: Azure SCIM v2.0
---
# Azure AD SCIM v2.0
The following guide will walk you through the process of configuring SAML Jackson to use the Azure AD SCIM v2.0 directory provider.
---
### Create Azure Application
Click **Azure Active Directory** from the Microsoft Azure Portal.
![img alt](/img/dsync/providers/azure/1.png)
Click **Enterprise Applications** from the left navigation menu.
![img alt](/img/dsync/providers/azure/2.png)
If your application is already created, choose it from the list and move to the section [Enable SCIM Provisioning](#enable-azure-scim-provisioning)
If you haven't created your application yet, click **New application** button.
![img alt](/img/dsync/providers/azure/9.png)
From the next screen, click **Create your own application**, give your application a **name** and click the **Create** button.
![img alt](/img/dsync/providers/azure/3.png)
---
### Enable Azure SCIM Provisioning
Click **Provisioning** from the left navigation menu then click **Get started**.
![img alt](/img/dsync/providers/azure/4.png)
Select **Automatic** from the **Provisioning Mode** dropdown and enter the following information under **Admin Credentials** section:
- Tenant URL
- Secret Token
Next, click the **Test Connection** button to test the connection to see if the credentials are correct, then click **Save** to save the credentials.
![img alt](/img/dsync/providers/azure/5.png)
Expand the **Mappings** section and ensure group and user attribute mappings are enabled for your app. The default mapping should work.
![img alt](/img/dsync/providers/azure/7.png)
Expand the **Settings** section and make the following changes:
- Select **Sync only assigned users and groups** from the **Scope** dropdown.
- Confirm the **Provisioning Status** is set to **On**.
![img alt](/img/dsync/providers/azure/8.png)
At this stage, you've successfully configured the Azure AD SCIM API integration.
---
### Assign Users
From your application, click the **Users and groups** from the left navigation menu and click **Add user/group**.
![img alt](/img/dsync/providers/azure/11.png)
Select **None Selected** under the **Users**.
From the right side of the screen, select the users you want to assign to the app and click the **Select** button, then click **Assign** to those users to the app.
![img alt](/img/dsync/providers/azure/12.png)

View File

@ -1,8 +0,0 @@
# Providers
SAML Jackson supports the following directory providers:
- [Azure SCIM v2.0](./azure)
- [OneLogin SCIM v2.0](./onelogin)
- [Okta SCIM v2.0](./okta)
- [JumpCloud SCIM v2.0](./jumpcloud)

View File

@ -1,60 +0,0 @@
---
title: JumpCloud SCIM v2.0
sidebar_label: JumpCloud SCIM v2.0
---
# JumpCloud SCIM v2.0
The following guide will walk you through the process of configuring SAML Jackson to use the JumpCloud SCIM v2.0 directory provider.
---
### Create JumpCloud SAML Application
JumpCloud only support configuring SCIM provisioning in an existing SAML application.
Choose an existing SAML application or create a new one. Click **SSO** from the left navigation menu and select your custom SAML application.
![img alt](/img/dsync/providers/jumpcloud/1.png)
Click the tab **Identity Management** within your SAML application.
Unde the **SCIM Version**, choose **SCIM 2.0** and enter the following information:
- Base URL
- Token Key
- Test User Email
Click **Test Connection** to test the connection to see if the credentials are correct then click **Activate**.
Next click **Save** to save the settings.
![img alt](/img/dsync/providers/jumpcloud/2.png)
At this stage, you've successfully configured the JumpCloud SCIM app.
---
### Assign Users & Push Groups
![img alt](/img/dsync/providers/jumpcloud/3.png)
Click the tab **User Groups** within your SAML application.
You can see the all the groups that are available, select the groups you want to sync and click **Save**.
If no existing groups are available, click **User Groups** from the left navigation menu and click plus icon to create a new group.
Give the group a name.
![img alt](/img/dsync/providers/jumpcloud/4.png)
Select the **Users** tab and choose the users you want to assign to the group.
![img alt](/img/dsync/providers/jumpcloud/5.png)
Next select the **Applications** tab and choose the app you want to assign the group to.
![img alt](/img/dsync/providers/jumpcloud/6.png)
At this stage, you've successfully assigned users and pushed the groups.

View File

@ -1,81 +0,0 @@
---
title: Okta SCIM v2.0
sidebar_label: Okta SCIM v2.0
---
# Okta SCIM v2.0
The following guide will walk you through the process of configuring SAML Jackson to use the Okta as a directory sync provider.
---
### Create Okta Application
Click **Applications** from the left navigation menu and click **Browse App Catalog** button.
![img alt](/img/dsync/providers/okta/1.png)
Search for **SCIM 2.0 Test App (Oauth Bearer Token)** from the search box and choose the app called **SCIM 2.0 Test App (Oauth Bearer Token)**.
![img alt](/img/dsync/providers/okta/2.png)
From the app page, click the **Add Integration** button.
![img alt](/img/dsync/providers/okta/3.png)
Give the app a name and click the **Next** button. Click **Done** to finish the creation of the app.
![img alt](/img/dsync/providers/okta/4.png)
---
### Enable Okta SCIM Provisioning
In your application, click the **Provisioning** tab and click **Configure API Integration**.
![img alt](/img/dsync/providers/okta/5.png)
Check the **Enable API Integration** checkbox and enter the following information:
- SCIM 2.0 Base URL
- OAuth Bearer Token
You'll receive these information from Jackson when you create the directory sync connection either via the API or the Admin Portal.
Click **Test API Creditentials** to test the connection to see if the credentials are correct then click the **Save** to save the credentials.
![img alt](/img/dsync/providers/okta/6.png)
You'll see a new setting page, click **To App** and enable the following settings:
![img alt](/img/dsync/providers/okta/7.png)
At this stage, you've successfully configured the Okta SCIM API integration.
---
### Assign Users
In your application, click the **Assignments** tab and select **Assign to People** from the dropdown **Assign**.
![img alt](/img/dsync/providers/okta/8.png)
Select users you want to assign to the app and click the **Assign** button.
![img alt](/img/dsync/providers/okta/9.png)
After you click the **Assign** button, you'll see a new popup window with various fields. Confirm the field values and click the **Save and Go Back** button.
![img alt](/img/dsync/providers/okta/10.png)
---
### Push Groups
Navigate to the tab **Push Groups** and select **Find group by name** from the dropdown **Push Groups**.
![img alt](/img/dsync/providers/okta/11.png)
Find the group you want to assign to the app and click the **Save** button.
![img alt](/img/dsync/providers/okta/12.png)

View File

@ -1,121 +0,0 @@
---
title: OneLogin SCIM v2.0
sidebar_label: OneLogin SCIM v2.0
---
# OneLogin SCIM v2.0
The following guide will walk you through the process of configuring SAML Jackson to use the OneLogin SCIM v2.0 directory provider.
---
### Create OneLogin Application
Click **Applications** from the top navigation menu and click **Add App** button.
![img alt](/img/dsync/providers/onelogin/1.png)
Search for **SCIM** from the search box and choose the app called **SCIM Provisioner with SAML (SCIM V2 Enterprise)** from the list of apps.
![img alt](/img/dsync/providers/onelogin/2.png)
Give the app a name and click the **Save** button.
![img alt](/img/dsync/providers/onelogin/3.png)
At this stage, you've successfully created the OneLogin SCIM app.
---
### Enable OneLogin SCIM Provisioning
In your application, click the **Configuration** tab on the left.
Enter the following information:
- SCIM Base URL
- SCIM Bearer Token
You'll receive these information from Jackson when you create the directory sync connection either via the API or the Admin Portal.
Click the button **Enable** to test the connection to see if the credentials are correct and click the button to **Save** to save the creditentials.
![img alt](/img/dsync/providers/onelogin/4.png)
Next click the **Provisioning** tab and check the **Enable provisioning** checkbox. Click the **Save** button to save the changes.
![img alt](/img/dsync/providers/onelogin/5.png)
Next click the **Parameters** tab and select the row **Groups** from the table.
![img alt](/img/dsync/providers/onelogin/6.png)
In the popup window, check the box **Include in User Provisioning** and click the **Save** button.
![img alt](/img/dsync/providers/onelogin/7.png)
---
### Assign Users
In order to assign users to your app, select **Users** from the top navigation menu and choose the user you want to assign to the app.
From the user page, click the **Application** tab on the left and click the plus sign.
![img alt](/img/dsync/providers/onelogin/8.png)
A popup window will show you the list of apps that you can assign the user to. Select the app you created earlier and click the **Continue** button.
![img alt](/img/dsync/providers/onelogin/9.png)
Click **Save** on the next modal window to confirm the assignment.
![img alt](/img/dsync/providers/onelogin/10.png)
Depending on your configuration, You may have to approve the assignment.
If you see a text **Pending** in the table, click that text. That'll bring up a modal window, click the button **Approve** to approve the assignment.
![img alt](/img/dsync/providers/onelogin/11.png)
At this point, the user will be assigned to the app.
---
### Push Groups
In order to push groups to your app, you've to create a new **Role** in your app.
In the top navigation, select **Users** and then **Roles** from the dropdown.
Click **New Role** to create a new role.
![img alt](/img/dsync/providers/onelogin/12.png)
Enter a name for the role, select the app you created earlier and click the **Save** button.
![img alt](/img/dsync/providers/onelogin/13.png)
Click the **Users** tab for the role and search for the user you want to assign the role to.
Click the button **Add To Role** to assign the user to the role and click the **Save** button.
![img alt](/img/dsync/providers/onelogin/14.png)
Click **Save** in the next modal to confirm the assignment.
![img alt](/img/dsync/providers/onelogin/15.png)
Go back to your app and click the **Rule** tab on the left and click the **Add Rule** button.
Give the rule a name. Under the **Actions**, select the **Set Groups in your-app-name** from the dropdown, then select for each **role** with values that matches **your-app-name**. Click the **Save** button.
![img alt](/img/dsync/providers/onelogin/16.png)
Click the **Users** tab on the left, you may see **Pending** provisions in the table. Click that text to approve the assignment.
![img alt](/img/dsync/providers/onelogin/17.png)
Click **Approve** in the next modal to confirm the assignment.
![img alt](/img/dsync/providers/onelogin/18.png)

View File

@ -1,120 +0,0 @@
---
title: Directory Sync Webhooks
sidebar_label: Webhooks
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Webhooks
A webhook is an HTTP request, triggered by an event in a source system and sent to a destination system (Eg: your app), often with a payload of data.
SAML Jackson use webhooks to notify your application any time changes are made to directory users and groups. You can use webhooks to trigger actions in your application, such as creating a new user in your application, or updating a user in your application based on the changes made in the directory.
## Configure Webhooks
SAML Jackson allows you to configure a webhook and secret while creating a directory sync connection either in the Admin Portal or the API. You can change the webhook and secret at any time.
- [Admin Portal](../admin-portal/directory-sync)
- [API Reference](api-reference#create-a-new-directory)
## Receive Events
SAML Jackson will make a POST request to your webhook endpoint when a change is made to a directory user or group. Your webhook endpoint should be able to receive the webhook request and respond with a 200 status code.
You can start receiving events in your app using the below steps:
- Create a webhook endpoint as an HTTP endpoint (URL) on your server.
- Create a directory sync connection and configure a webhook endpoint.
- Configure the SCIM app on your Identity Provider.
- Handle the webhook request and respond with a 200 status code.
To see the full list of events, please see the [Events and Types](events) page.
Here is a sample webhook request look like:
```json
POST /your-webhook-endpoint
Content-Type: application/json
BoxyHQ-Signature: t=xxx,s=xxxx
{
"directory_id": "58b5cd9dfaa39d47eb8f5f88631f9a629a232016",
"event": "user.created",
"tenant": "boxyhq",
"product": "jackson",
"data": {
"id": "038e767b-9bc6-4dbd-975e-fbc38a8e7d82",
"first_name": "Deepak",
"last_name": "Prabhakara",
"email": "deepak@boxyhq.com",
"active": true,
"raw": {...}
}
}
```
:::caution
If the webhook request fails, SAML Jackson will not retry the webhook request. A log will be created in the SAML Jackson Admin Portal if the you've enabled the webhook event logging.
:::
## Secure Webhooks
Use the webhook signature (**BoxyHQ-Signature**) to verify the webhook request is from SAML Jackson. The signature is generated using the **webhook secret** you configured in the directory sync connection.
Signature contains comma separated values of the following:
- **t** The timestamp of the webhook request.
- **s** The signature of the webhook request.
An example of the webhook signature is below:
```
BoxyHQ-Signature: t=1545010989801,s=xxxx
```
## Verify Webhooks Signature
You can verify the webhook signature by using the following steps:
- Extract the **t** and **s** values from the webhook signature.
- Create the signed payload string by concatenating:
- The timestamp (t)
- The character `.`
- The actual JSON payload
- Compute the `HMAC-SHA256` hash of the signed payload string using your webhook secret.
- Compare the signature in the request header with the computed signature.
Once the signature is verified, you can use the webhook payload to perform any action in your application.
```javascript showLineNumbers
// Your webhook secret
const secret = 'your-secret-here';
// The signature header from the webhook request.
const signatureHeader =
't=1657016083300,s=9ece981128a8f2a96f95e3d0be68c37b825d5c15f5b8982e0b7e198a76621866';
// JSON body from the webhook request.
const body = {...}
const [t, s] = signatureHeader.split(',');
const signature = t.split('=')[1];
const timestamp = s.split('=')[1];
const signedPayload = `${timestamp}.${JSON.stringify(body)}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Compare the expectedSignature to the signature
if(signature === expectedSignature) {
// The webhook request is valid
} else {
// The webhook request is invalid
}
```

View File

@ -1,80 +0,0 @@
---
title: Docs
description: Check out our documentation to see how you can deploy our enterprise-ready solutions into your application with ease. Check out our SAML Jackson for Single sign-on.
hide_table_of_contents: true
---
import Link from '@docusaurus/Link';
Security Building Blocks for Developers
Reduce Time to Market without sacrificing your security posture! BoxyHQs suite of APIs for security and privacy helps engineering teams build and ship compliant cloud applications faster. Integrate Single Sign-On (SSO), Audit Logs, Privacy Vault and Role Based Access in minutes. Open source and free.
<div className="container" style={{ padding: 0 }}>
<div className="row is-multiline">
<div className="col col--6 margin-bottom--sm">
<Link
className="card"
to="/docs/jackson/overview"
style={{ height: '100%' }}
>
<div className="card__body">
<h4>Enterprise SSO</h4>
<p>
A SAML/OIDC SSO service designed as an OAuth 2.0 flow. Integrate SSO
with just a few lines of code.
</p>
</div>
</Link>
</div>
<div className="col col--6 margin-bottom--sm">
<Link
className="card"
to="/docs/directory-sync/overview"
style={{ height: '100%' }}
>
<div className="card__body">
<h4>Directory Sync</h4>
<p>
Directory sync helps organizations automate the provisioning and
de-provisioning of their users. It is based on the SCIM 2.0
protocol.
</p>
</div>
</Link>
</div>
</div>
<div className="row is-multiline">
<div className="col col--6">
<Link
className="card"
to="/docs/retraced/overview"
style={{ height: '100%' }}
>
<div className="card__body">
<h4>Audit Logs</h4>
<p>
Retraced is the easiest way to integrate a compliant audit log into
your application. It provides a searchable, exportable record of
read/write events.
</p>
</div>
</Link>
</div>
<div className="col col--6 margin-bottom--sm">
<Link
className="card"
to="/docs/admin-portal/overview"
style={{ height: '100%' }}
>
<div className="card__body">
<h4>Admin Portal</h4>
<p>
Manage our Enterprise SSO and Directory Sync products via an easy to
use web interface
</p>
</div>
</Link>
</div>
</div>
</div>

74
docs/intro.md Normal file
View File

@ -0,0 +1,74 @@
---
sidebar_label: "介绍"
label: "介绍"
sidebar_position: 1
slug: /
---
# 关于GitLink
GitLink确实开源是CCF官方指定的开源创新服务平台旨在以“为开源创新服务”为使命以“成为开源创新的汇聚地”为愿景秉承“创新、开放、协作、共享”的价值观致力于为大规模开源开放协同创新助力赋能打造创新成果孵化和新工科人才培养的开源创新生态
![](/img/ccf_gitlink.png)
# 平台功能
- **分布式协作开发**:支持在线文件编辑、分支管理、贡献统计、仓库复刻、合并请求;
- **一站式过程管理**支持疑修、里程碑、通知提醒、标签归档、Wiki文档、组织管理
- **高效流水线运维**:提供轻量级工作流引擎,并支持自定义配置、静态扫描、制品构建;
- **多层次代码分析**:支持代码溯源分析、许可证风险分析、开源漏洞检测和加固建议;
- **多维度用户画像**:支持开发活动统计、贡献日历、能力建模、角色与专业定位分析。
# 帮助文档
帮助文档有助于您全面了解GitLink平台让我们一起为开源创新贡献力量
<div class="row">
<div class="col col--12">
<section class="row list">
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/快速开始/注册GitLink账号">
<h2 class="text--truncate cardTitle" title="快速开始">快速开始</h2>
<p>帮助用户快速注册使用平台[5个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/代码库管理/仓库创建">
<h2 class="text--truncate cardTitle" title="代码库管理">代码库管理</h2>
<p>代码库使用及设置[8个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/组织管理/组织简介">
<h2 class="text--truncate cardTitle" title="组织管理">组织管理</h2>
<p>组织使用及设置[5个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/疑修/疑修简介">
<h2 class="text--truncate cardTitle" title="疑修">疑修</h2>
<p>疑修(Issue)使用及设置[7个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/合并请求/合并请求简介">
<h2 class="text--truncate cardTitle" title="合并请求">合并请求</h2>
<p>合并请求(Pull Request)使用及设置[5个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/DevOps引擎/引擎简介">
<h2 class="text--truncate cardTitle" title="DevOps引擎">DevOps引擎</h2>
<p>DevOps引擎(Engine)使用及设置[6个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/维基/模板导入及导出">
<h2 class="text--truncate cardTitle" title="维基">维基</h2>
<p>维基(Wiki)使用及设置[2个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/Bot市场/bot安装">
<h2 class="text--truncate cardTitle" title="Bot市场">Bot市场</h2>
<p>Bot市场使用及设置[4个文档]</p>
</a></article>
<article class="col col--6 margin-bottom--lg">
<a class="card padding--lg cardContainer" href="/docs/第三方服务/跨平台代码同步">
<h2 class="text--truncate cardTitle" title="第三方服务">第三方服务</h2>
<p>第三方服务使用及设置[3个文档]</p>
</a></article>
</section>
</div>
</div>

View File

@ -1,21 +0,0 @@
# Container Signing and Verification
Jackson container images are signed and can be verified using [cosign](https://github.com/sigstore/cosign).
## Fetching our public key
You can use [oras](https://oras.land/docs/category/cli) (or a similar OCI artifacts tool) to fetch our public key or download it from our website [here](https://boxyhq.com/.well-known/cosign.pub).
```bash
oras pull ghcr.io/boxyhq/cosign.pub:latest
```
## Container verification
**Note:** This is supported for all versions >=1.6.0
Our container images are hosted on [Docker Hub](https://hub.docker.com/r/boxyhq/jackson/tags). You can verify it by using the following command.
```bash
cosign verify --key cosign.pub boxyhq/jackson:<version>
```

View File

@ -1,374 +0,0 @@
---
title: Environment Variables (Enterprise SSO)
sidebar_label: Environment Variables
description: Environment Variables for Enterprise SSO
---
# Environment Variables
The env vars are only applicable to the Jackson service. If you are using the npm library then look for the options below when initializing the library.
## General configuration
### **HOST_URL**
The URL to bind to.
Default: `localhost`
### **PORT**
The port to bind to.
Default: `5225`
### **EXTERNAL_URL**
The public URL to reach this service. This is used internally to construct the callback url at which the SAML/OIDC IdP sends back the authorization response.
Default: `http://{HOST_URL}:{PORT}`
NPM library option: `externalUrl`
### **JACKSON_API_KEYS**
A comma separated list of API keys that will be validated when serving the API requests for SSO connection (`/api/v1/connections`) and Directory Sync (`/api/v1/directory-sync`).
For example `JACKSON_API_KEYS=key1,key2,key3`
The API requests will then need to specify an `Authorization` header which contains one of the API keys above in this format: `Api-Key key1`
### **SAML_AUDIENCE**
The value of this setting (same as SP EntityID of Jackson) allows the Jackson instance to verify that it is the intended recipient of a SAML response. The same value is also set in the SAML App created on the IdP end by your customers. Once set do not change this value unless you get your customers to reconfigure their SAML App again. It is case-sensitive. This does not have to be a real URL.
Default: `https://saml.boxyhq.com`
NPM library option: `samlAudience`
### **samlPath**
> **_NOTE:_** This is only applicable to our npm library.
The ACS path at which the [saml response](./npm-library#handle-saml-response) is sent back from the SAML IdP. Set this when using the npm package.
NPM library option: `samlPath`
For example: `/api/oauth/saml`
### **oidcPath**
> **_NOTE:_** This is only applicable to our npm library.
The `redirect_uri` at which the Authorization response is sent back from the OpenID Connect IdP. Set this when using the npm package.
NPM library option: `oidcPath`
For example: `/api/oauth/oidc`
### **IDP_DISCOVERY_PATH**
This is the path for showing the IdP Selection screen in case there are multiple SSO Connections for the same `tenant` and `product`.
This path is also used to show the App Selection screen in the case of IdP-initiated SAML login (Different apps using the same SAML IdP).
Set this when using the npm package.
NPM library option: `idpDiscoveryPath`
For example: `/idp/select` - You can find an implementation of IdP/App Selection at https://github.com/boxyhq/jackson/blob/main/pages/idp/select.tsx.
### **CLIENT_SECRET_VERIFIER**
When `tenant` and `product` are used for the SAML flow (and PKCE is not being used) then we use `dummy` as placeholders for `client_id` and `client_secret`. This is not a security issue because SAML is tenanted and hence your Identity Provider will block access to anyone trying to log into your SAML tenant. However for additional security you should set `CLIENT_SECRET_VERIFIER` to a random secret and use that value as the `client_secret` during the OAuth 2.0 flow.
Default: `dummy`
NPM library option: `clientSecretVerifier`
### **IDP_ENABLED**
Set to true to enable IdP initiated login for SAML. SP initiated login is the only recommended flow but you might have to support IdP login at times.
Default: `false`
NPM library option: `idpEnabled`
### **PUBLIC_KEY**
This is the public key of the private key used to sign the SAML requests. Jackson expects the public key to be base64 encoded.
NPM library option: `certs.publicKey`
### **PRIVATE_KEY**
This is the private key used to sign the SAML requests. Jackson expects the private key to be base64 encoded.
NPM library option: `certs.privateKey`
To generate a private key and public key pair you can use the following command:
```bash
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out public.crt -sha256 -days 365 -nodes
# Convert the public key to base64
cat public.crt | base64
# Convert the private key to base64
cat key.pem | base64
```
## OpenID configuration
For supporting OpenID flow, we need to set the algorithm and keys used to sign the ID token JWT.
### **OPENID_JWS_ALG**
The algorithm used to sign the id_token. Jackson uses [jose](https://github.com/panva/jose) to create the ID token. Supported algorithms can be found at https://github.com/panva/jose/issues/114#digital-signatures.
Default: `RS256`
NPM library option: `openid.jwsAlg`
### **OPENID_RSA_PRIVATE_KEY**
Base64 value of private key.
To generate one:
```bash
openssl genrsa -out private-key.pem 3072
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private-key.pem -out private_key.pem
cat private_key.pem | base64
```
NPM library option: `openid.jwtSigningKeys.private`
### **OPENID_RSA_PUBLIC_KEY**
Base64 value of public key.
You can generate the public key from the private key as shown below:
```bash
openssl rsa -in private_key.pem -pubout -out public_key.pem
cat public_key.pem | base64
```
NPM library option: `openid.jwtSigningKeys.public`
## Database configuration
### **DB_ENGINE**
Supported values are `redis`, `sql`, `mongo`, `mem`, `planetscale`, `dynamodb`
Default: `sql`
NPM library option: `db.engine`
> **_NOTE:_** If you are using DynamoDB then you also need to set `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. For additional options like region and capacity units check [this section](#db_dynamodb_region)
> **_NOTE:_** `mem` DB (In memory database) is useful to test the Jackson setup locally and is not intended for production. In a serverless deployment like Vercel, the mem DB won't persist across API calls since each call is a fresh lambda invocation with an entirely new context.
### **DB_TYPE**
Only needed when DB_ENGINE is sql. Supported values are `postgres`, `mysql`, `mariadb`, `mssql`
Default: `postgres`
NPM library option: `db.type`
### **DB_URL**
The database URL to connect to. If you are using self-signed certificates then pass `sslmode=noverify` instead of `sslmode=require` in the `DB_URL`. This is because self-signed certs will be rejected as unauthorized in strict mode. Also, set `DB_SSL=true` and `DB_SSL_REJECT_UNAUTHORIZED=false` (see env vars below for more details).
Example: `postgres://postgres:postgres@localhost:5432/postgres` or `postgres://postgres:postgres@localhost:5432/postgres?sslmode=no-verify`
For `mssql` the URL takes the form of `sqlserver://localhost:1433;database=<db name>;username=<username>;password=<password>;encrypt=true`
> **_NOTE:_** If you are using DynamoDB then you also need to set `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. For additional options like region and capacity units check [this section](#db_dynamodb_region)
NPM library option: `db.url`
### **DB_SSL**
This needs to be set to `true` if you are using SSL with your database (You should definitely be using SSL if the database needs to be access via a public url).
Default: `false`
### **DB_SSL_REJECT_UNAUTHORIZED**
If you are using a self-signed certificate then set this to `false`, otherwise it will be rejected due to Certificate Authority checks.
Default: `true`
### **DB_TTL**
TTL for the code, session and token stores (in seconds)
Default: `300`
NPM library option: `db.ttl`
### **DB_CLEANUP_LIMIT**
Limit cleanup of TTL entries to this number
Default: `1000`
NPM library option: `db.cleanupLimit`
### **DB_ENCRYPTION_KEY**
To encrypt data at rest specify a 32 character key
You can use openssl to generate a random 32 character key:
```bash
openssl rand -base64 24
```
NPM library option: `db.encryptionKey`
### **PGSSLMODE**
If you use Heroku to deploy Postgres (or use self-signed certs for Postgres) then set this to `no-verify`. See [Heroku docs](https://devcenter.heroku.com/articles/connecting-heroku-postgres#connecting-in-node-js) for more details
### **DB_DYNAMODB_REGION**
If you are using DynamoDB then you can specify the region.
Default: `us-east-1`
NPM library option: `db.dynamodb.region`
### **DB_DYNAMODB_RCUS**
If you are using DynamoDB then you can specify the read capacity units. Check [AWS docs](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.ReadWriteCapacityMode.html) for more details
Default: 5
NPM library option: `db.dynamodb.readCapacityUnits`
### **DB_DYNAMODB_WCUS**
If you are using DynamoDB then you can specify the write capacity units.
Default: 5
NPM library option: `db.dynamodb.writeCapacityUnits`
## Webhook configuration
### **WEBHOOK_URL**
Specify a webhook URL to receive events about sso and directory connections.
NPM library option: `webhook.endpoint`
### **WEBHOOK_SECRET**
Specify a secret to be used to sign the webhook payload. This is used to verify the authenticity of the webhook payload.
NPM library option: `webhook.secret`
Both the `WEBHOOK_URL` and `WEBHOOK_SECRET` are required to enable webhook events.
## Pre-loaded Connections
### **PRE_LOADED_CONNECTION**
If you only need a single tenant or a handful of pre-configured tenants then this config will help you read and load IdP (both OpenID and SAML)connections. It works well with the mem DB engine so you don't have to configure any external databases for this to work (though it works with those as well). This is a path (absolute or relative) to a directory that contains files organized in the format described in the next section. Check [this section](./pre-loaded-connections.md) for more details
NPM library option: `preLoadedConnection`
## Opentelemetry configuration
Jackson supports observability via OpenTelemetry. The following env vars are available for configuration (along with the rest of the [supported ones](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md))
### **OTEL_EXPORTER_OTLP_ENDPOINT** or **OTEL_EXPORTER_OTLP_METRICS_ENDPOINT**
Target URL to which the exporter is going to send metrics.
Example: `https://ingest.lightstep.com:443/metrics/otlp/v0.6`
### **OTEL_EXPORTER_OTLP_HEADERS** or **OTEL_EXPORTER_OTLP_METRICS_HEADERS**
Headers relevant for the endpoint, useful for specifying authentication details for providers.
Example: `lightstep-access-token=<token>,...`
### **OTEL_EXPORTER_OTLP_PROTOCOL** or **OTEL_EXPORTER_OTLP_METRICS_PROTOCOL**
The transport protocol. Options MUST be one of: `grpc`, `http/protobuf` or `http/json`.
### **OTEL_EXPORTER_DEBUG**
Set this to `true` to enable debug logs for Opentelemetry. This is only meant for purposes of debugging otel locally.
## Admin Portal configuration
Below variables are used to enable [Magic link](https://next-auth.js.org/providers/email) based authentication for Admin Portal. The **SMTP\_** variables are used for sending email which contain the magic link (one-time use) for sign in.
### **SMTP_HOST**
The SMTP host like `smtp.example.com`.
### **SMTP_PORT**
The SMTP server port like `587`.
### **SMTP_USER**
Username for the SMTP server.
### **SMTP_PASSWORD**
Password for the SMTP server.
### **SMTP_FROM**
_From_ address used to send mail like: `noreply@example.com`.
### **NEXTAUTH_URL**
When running locally this will point to the local server: `http://localhost:5225`. When deploying to production, set this to the canonical URL of the site. More details [here](https://next-auth.js.org/configuration/options#nextauth_url).
### **NEXTAUTH_SECRET**
Set this to a random string. You can use `openssl rand -base64 32` to get one. This secret is used to encrypt JWT and hash the email verification token. More details [here](https://next-auth.js.org/configuration/options#nextauth_secret).
### **NEXTAUTH_ACL**
Set this to a comma separated string of email addresses or glob patterns like: `tonystark@gmail.com,*@marvel.com`. Access will be denied to email addresses which don't match. If you don't specify any value access is denied to all.
### **NEXTAUTH_ADMIN_CREDENTIALS**
Set this to a comma separated string of the pattern `email:password` to enable login to the Admin Portal, for example `NEXTAUTH_ADMIN_CREDENTIALS=deepak@boxyhq.com:Password123`. If you don't specify any value access is denied to all.
### **ADMIN_PORTAL_SSO_TENANT**
This will be used as the tenant for the SSO connections (added from Settings tab) used to login into the Admin portal itself. Set this to a value that is less likely to conflict with the main Enterprise SSO connections.
Default: `_jackson_boxyhq`
### **ADMIN_PORTAL_SSO_PRODUCT**
This will be used as the product for the SSO connections (added from Settings tab) used to login into the Admin portal itself. Set this to a value that is less likely to conflict with the main Enterprise SSO connections.
Default: `_jackson_admin_portal`
### **RETRACED_HOST_URL**
If you'd like to use the Admin Portal to manage our Audit Logs service ([Retraced](https://github.com/retracedhq/retraced)) then set this env var to the URL of the service.
### **RETRACED_EXTERNAL_URL**
If you'd like to use the Admin Portal to manage our Audit Logs service ([Retraced](https://github.com/retracedhq/retraced)) then set this env var to the Public URL of the service. If this is the same as `RETRACED_HOST_URL` above then you can skip this and it will default to the value of `RETRACED_HOST_URL`.
Default: It is set to `RETRACED_HOST_URL` if `RETRACED_EXTERNAL_URL` is not defined.
### **RETRACED_ADMIN_ROOT_TOKEN**
you need to set the admin root token for Retraced so that we can connect to Retraced and fetch projects and audit logs.
## Anonymous Analytics
### **BOXYHQ_NO_TELEMETRY** or **DO_NOT_TRACK**
Set one of these to `1` or `true` to turn off our anonymous analytics. We only track usage events once per day and it does not contain any information that can identify you in any form.

View File

@ -1,19 +0,0 @@
---
title: Getting Started with SAML Jackson
description: Getting Started with SAML Single Sign-On authentication
sidebar_label: Overview
---
SAML Jackson can be used with any web application to integrate the **Single Sign-On (SSO) authentication**.
There are two ways to integrate SAML Jackson with an application. Depending on your use case, you can choose either one of them.
## As a [separate service](./service.md)
The advantage of running a separate service is that you get all of our UI tooling (like the Admin Portal) with the service. The disadvantage is that you have to manage the operations of a separate service. If you are not using Node.js then this is the only option available to you.
## As an [NPM library](./npm-library.md)
This is available if you are already developing your application using Node.js.
The advantage of embedding Jackson as an npm library is that you do not have to manage operations of a separate service. The disadvantage is that you do not readily get our UI tooling (like the Admin Portal) with this method.

View File

@ -1,442 +0,0 @@
# NPM Library
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
SAML Jackson is available as an [npm package](https://www.npmjs.com/package/@boxyhq/saml-jackson) that can be integrated into any **Node.js** based web application framework.
Install the SDK using the command below.
```bash
npm install @boxyhq/saml-jackson
```
---
## Configuration Options
Please note that the initialization of `@boxyhq/saml-jackson` is async, you cannot run it at the top level.
```js
import jackson, {
type IConnectionAPIController,
type IOAuthController,
} from '@boxyhq/saml-jackson';
let oauth: IOAuthController;
let connection: IConnectionAPIController;
(async function init() {
const jackson = await require('@boxyhq/saml-jackson').controllers({
externalUrl: 'https://your-app.com',
samlAudience: 'https://saml.boxyhq.com',
oidcPath: '/api/oauth/oidc',
samlPath: '/api/oauth/saml',
db: {
engine: 'sql',
type: 'postgres',
url: 'postgres://postgres:postgres@localhost:5432/postgres',
},
});
oauth = jackson.oauthController;
connection = jackson.connectionAPIController;
})();
```
---
## Single Sign-On Connections
### Create SAML Connection
Create a new SAML Single Sign-On connection.
<Tabs>
<TabItem value="01" label="Request" default>
```js
await connection.createSAMLConnection({
tenant: 'boxyhq',
product: 'your-app',
rawMetadata: '<raw-saml-metadata>', // Visit https://mocksaml.com to download Metadata
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"defaultRedirectUrl": "https://your-app.com/sso/callback",
"redirectUrl": ["https://your-app.com/*"],
"tenant": "boxyhq",
"product": "your-app",
"clientID": "f7c909a5c72a5535847acf32558b2429a5172dd6",
"clientSecret": "cc6ba07bc42c2f449c9b0a3cc41c256dea08f705e1b44fdc",
"forceAuthn": false,
"idpMetadata": {
"sso": {
"postUrl": "https://mocksaml.com/api/saml/sso",
"redirectUrl": "https://mocksaml.com/api/saml/sso"
},
"slo": {},
"entityID": "https://saml.example.com/entityid",
"thumbprint": "d797f3829882233d3f01e49643f6a1195f242c94",
"validTo": "Jul 1 21:46:38 3021 GMT",
"loginType": "idp",
"provider": "saml.example.com"
},
"certs": {
"publicKey": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----\r\n",
"privateKey": "-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----\r\n"
}
}
```
</TabItem>
</Tabs>
### Update SAML Connection
Update a SAML Single Sign-On connection.
```js
await connection.updateSAMLConnection({
tenant: 'boxyhq',
product: 'your-app',
rawMetadata: '<raw-saml-metadata>',
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback-updated',
clientID: '<clientID of the SAML SSO Connection>',
clientSecret: '<clientSecret of the SAML SSO Connection>',
});
```
### Create OIDC Connection
Create a new OIDC Single Sign-On connection.
<Tabs>
<TabItem value="01" label="Request" default>
```js
await connection.createOIDCConnection({
tenant: 'boxyhq',
product: 'your-app',
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback',
oidcDiscoveryUrl:
'https://accounts.google.com/.well-known/openid-configuration',
oidcClientId: '<OpenID Client ID>',
oidcClientSecret: '<OpenID Client Secret>',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"defaultRedirectUrl": "https://your-app.com/sso/callback",
"redirectUrl": ["https://your-app.com/*"],
"tenant": "boxyhq",
"product": "your-app",
"clientID": "749f95c4bd02b4adb6c0633249e70d5ad45b75e2",
"clientSecret": "2d730ac71c74e7d49dccf362c9a61005b6246cc65d6d0fa4",
"oidcProvider": {
"discoveryUrl": "https://accounts.google.com/.well-known/openid-configuration",
"clientId": "<OpenID Client ID>",
"clientSecret": "<OpenID Client Secret>",
"provider": "accounts.google.com"
}
}
```
</TabItem>
</Tabs>
### Update OIDC Connection
Update an OIDC Single Sign-On connection.
```js
await connection.updateOIDCConnection({
tenant: 'boxyhq',
product: 'your-app',
redirectUrl: ['https://your-app.com/*'],
defaultRedirectUrl: 'https://your-app.com/sso/callback',
oidcDiscoveryUrl:
'https://accounts.google.com/.well-known/openid-configuration',
oidcClientId: '<OpenID Client ID>',
oidcClientSecret: '<OpenID Client Secret>',
clientID: '<clientID of the OIDC SSO Connection>',
clientSecret: '<clientSecret of the OIDC SSO Connection>',
});
```
### Get SAML/OIDC Connections
Get the details of an existing SAML or OIDC Single Sign-On connection.
<Tabs>
<TabItem value="01" label="Request" default>
```js
// Using tenant and product
await connection.getConnections({
tenant: 'boxyhq',
product: 'your-app',
});
// Using the client ID
await connection.getConnections({
clientID: '<clientID of the SSO Connection to be retrieved>.',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
[
{
"defaultRedirectUrl": "https://your-app.com/sso/callback",
"redirectUrl": ["https://your-app.com/*"],
"tenant": "boxyhq",
"product": "your-app",
"clientID": "...",
"clientSecret": "...",
"forceAuthn": false,
"idpMetadata": {
"sso": {
"postUrl": "https://mocksaml.com/api/saml/sso",
"redirectUrl": "https://mocksaml.com/api/saml/sso"
},
"slo": {},
"entityID": "https://saml.example.com/entityid",
"thumbprint": "d797f3829882233d3f01e49643f6a1195f242c94",
"validTo": "Jul 1 21:46:38 3021 GMT",
"loginType": "idp",
"provider": "saml.example.com"
},
"certs": {
"publicKey": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----\r\n",
"privateKey": "-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----\r\n"
}
}
]
```
</TabItem>
</Tabs>
### Delete SAML/OIDC Connection
Update a SAML or OIDC Single Sign-On connection.
```js
// Using tenant and product
await connection.deleteConnections({
tenant: 'boxyhq',
product: 'your-app',
});
// Using client ID and client secret
await connection.deleteConnections({
clientID: '<clientID of the SSO Connection>',
clientSecret: '<clientSecret of the SSO Connection>',
});
```
---
## Single Sign-On Authentication
### Handle OAuth 2.0 (or OIDC) Authorization request
To initiate the flow, the application must trigger an OAuth 2.0 (or OIDC) redirect to the authorization endpoint of your app. You'll use the `authorize` method within the authorization handler.
`authorize` will resolve the SSO URL (`redirect_url`) based on the connection configured for the tenant/product. The app needs to redirect the user to this URL. Keep in mind that the SSO URL structure is different based on the type of SSO Connection. For a SAML Connection, this will contain the `SAMLRequest` whereas for an OIDC Connection the SSO URL will be the Authorization endpoint with the OIDC request params (scope, response_type, etc.) attached.
<Tabs>
<TabItem value="01" label="Request" default>
```ts
await oauth.authorize({
tenant: 'boxyhq',
product: 'your-app',
redirect_uri:
'<app redirect URI to which Jackson sents back the authorization code after authentication>',
state:
'<opaque value from the app which will be returned back from Jackson, this is need to prevent CSRF attacks>',
response_type: 'code',
code_challenge:
'<transformed value of code_verifier used to prevent interception of authorization_code in PKCE flow>',
code_challenge_method:
'<transformation method applied on code_verifier to generate code_challenge>',
scope:
'<can contain space separated values such as openid or even encoded tenant/product>',
nonce:
'<string value used to associate a client session with an ID Token in openid flow, and to mitigate replay attacks>',
idp_hint:
'<this will contain the clientID of the SSO connection that the user selects in the case of multiple ones configured for a tenant/product>',
prompt: '<pass "login" to force authentication at the SAML IdP>',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"redirect_url": "https://mocksaml.com/api/saml/sso?RelayState=boxyhq_jackson_...&SAMLRequest=nVbZkqs4En33V1T4...",
"authorize_form": ""
}
```
</TabItem>
</Tabs>
### Handle IdP Response
The response is sent back to your app after authentication at IdP. After the handling of this response, the profile of the authenticated user is extracted and stored against a short-lived code that is then sent back to the app. To handle the response use the appropriate method as detailed below:
#### SAML Response
Handle the response from the SAML Identity Provider. After successful authentication, IdP sends back (via browser POST) the `SAMLResponse` and `RelayState` to the Assertion Consumer Service (ACS) URL (`samlPath`) of the app. You'll use the `samlResponse` method within your ACS endpoint. This will parse and validate the SAML Response after which the user profile is extracted.
<Tabs>
<TabItem value="01" label="Request" default>
```js
await oauth.samlResponse({
SAMLResponse: '<SAML Response from the SAML IdP>',
RelayState: '<Relaystate from the original SAML request to the IdP>',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"redirect_url": "https://your-app.com/sso/callback?code=5db7257fde94e062f6243572e31818d6e64c3097&state=c38ee339-6b82-43d3-838f-4036820acce9"
}
```
</TabItem>
</Tabs>
#### OIDC Response
Handle the response from the OIDC Identity Provider. After successful authentication, IdP sends back (via browser redirect) the `code` and `state` to the redirect URL (`oidcPath`) that handles the OIDC response. You'll use the `oidcAuthzResponse` method within your `oidcPath` handler. This will exchange the `code` for tokenSet (id_token and access_token) from the OIDC Provider. The "userinfo" endpoint of the OIDC Provider also gets invoked. Both the `id_token` claims and `userinfo` response are used to form the user profile.
<Tabs>
<TabItem value="01" label="Request" default>
```js
await oauth.oidcAuthzResponse({
code: '<code received from OIDC IdP after authentication>',
state: '<state from the original OIDC request to the IdP>',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"redirect_url": "https://your-app.com/sso/callback?code=5db7257fde94e062f6243572e31818d6e64c3097&state=c38ee339-6b82-43d3-838f-4036820acce9"
}
```
</TabItem>
</Tabs>
### Request Access Token
Requests an `access_token` by passing the authorization `code` from the previous step along with other authentication details.
<Tabs>
<TabItem value="01" label="Request" default>
```js
const tenant = 'boxyhq';
const product = 'your-app';
await oauth.token({
code: '<Authorization code received from Jackson at redirect_url after login at IdP>',
redirect_uri:
'<redirect_uri used in original authorization request to Jackson>',
client_id: `tenant=${tenant}&product=${product}`,
client_secret: 'dummy',
grant_type: 'authorization_code',
});
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"access_token": "6b81f03b60c34e46e740d96c7e6242923736a2d1",
"token_type": "bearer",
"expires_in": 300
}
```
</TabItem>
</Tabs>
### Fetch User Profile
Once the `access_token` has been fetched, you can use it to retrieve the user profile from the Identity Provider.
<Tabs>
<TabItem value="01" label="Request" default>
```js
const accessToken = '<Access token from code exchange step above>';
await oauth.userInfo(accessToken);
```
</TabItem>
<TabItem value="02" label="Response">
```json
{
"raw": {
"id": "1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9",
"email": "samuel@example.com",
"firstName": "Samuel",
"lastName": "Jackson",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "samuel@example.com"
},
"id": "1dda9fb491dc01bd24d2423ba2f22ae561f56ddf2376b29a11c80281d21201f9",
"email": "samuel@example.com",
"firstName": "Samuel",
"lastName": "Jackson",
"requested": {
"client_id": "f7c909a5c72a5535847acf32558b2429a5172dd6",
"state": "c38ee339-6b82-43d3-838f-4036820acce9",
"redirect_uri": "https://your-app.com/sso/callback",
"tenant": "boxyhq",
"product": "your-app",
"scope": []
}
}
```
</TabItem>
</Tabs>

View File

@ -1,50 +0,0 @@
# Pre-loaded SSO Connections
#### SAML
If PRE_LOADED_CONNECTION is set then it should point to a directory with the following structure (example below):-
```bash
boxyhq.js
boxyhq.xml
anothertenant.js
anothertenant.xml
```
The JS file has the following structure:-
```javascript
module.exports = {
defaultRedirectUrl: 'http://localhost:3366/login/saml',
redirectUrl: '["http://localhost:3366/*"]',
tenant: 'boxyhq.com',
product: 'demo',
name: 'testConnection',
description: 'Just a test connection',
};
```
The XML file (which should have the same name as the .js file) is the raw XML metadata file you receive from your Identity Provider. Please ensure it is saved in the `utf-8` encoding.
The config and XML above correspond to the [Add connection API - SAML tab](../sso-flow/index.md#21-add-connection).
#### OIDC
For a connection backed by OpenID IdP create the \*.js file at PRE_LOADED_CONNECTION as shown below:-
See [Add connection API - OIDC tab](../sso-flow/index.md#21-add-connection)
```javascript
module.exports = {
defaultRedirectUrl: 'http://localhost:3366/sso/oauth/oidc',
redirectUrl: '["http://localhost:3366"]',
tenant: 'oidc.example.com',
product: 'crm',
name: 'OIDC connection for oidc.example.com',
description: 'OIDC connection for oidc.example.com',
oidcDiscoveryUrl:
'https://accounts.google.com/.well-known/openid-configuration',
oidcClientId: '<ClientId from the OpenID IdP>',
oidcClientSecret: '<ClientSecret from the OpenID IdP>',
};
```

View File

@ -1,144 +0,0 @@
# Service
## Health Check
The service offers a readiness and health check endpoint that can be configured in orchestration tools like Docker Compose and Kubernetes.
The `/api/health` GET endpoint returns a 200 when the service ready and healthy or a 5xx (typically 503) error if unhealthy. The response contains the current version of Jackson. For example: `{"version":"1.0.0"}`.
## With Docker
The docker container can be found at [boxyhq/jackson](https://hub.docker.com/r/boxyhq/jackson/tags). It is preferable to use a specific version instead of the `latest` tag.
Replace the values for `DB_URL`, `JACKSON_API_KEYS`, `NEXTAUTH_SECRET` and `NEXTAUTH_ADMIN_CREDENTIALS` with your own values before running docker run command.
```bash
docker run \
-p 5225:5225 \
-e DB_ENGINE="sql" \
-e DB_TYPE="postgres" \
-e DB_URL="postgres://postgres:postgres@postgres:5432/postgres" \
-e JACKSON_API_KEYS="secret" \
-e NEXTAUTH_URL="http://localhost:5225" \
-e EXTERNAL_URL="http://localhost:5225" \
-e NEXTAUTH_SECRET="super-secret" \
-e NEXTAUTH_ADMIN_CREDENTIALS="admin@company.com:secretpassword" \
-d boxyhq/jackson
```
OR
```bash
docker run \
-p 5225:5225 \
-e DB_ENGINE="mongo" \
-e DB_URL="mongodb://localhost:27017/jackson" \
-e JACKSON_API_KEYS="secret" \
-e NEXTAUTH_URL="http://localhost:5225" \
-e EXTERNAL_URL="http://localhost:5225" \
-e NEXTAUTH_SECRET="super-secret" \
-e NEXTAUTH_ADMIN_CREDENTIALS="admin@company.com:secretpassword" \
-d boxyhq/jackson
```
See the complete list of [Environment Variables](./env-variables.md)
Kubernetes and docker-compose deployment files will be coming soon.
## Without Docker
Please follow the below instructions.
### Clone the repository
You can clone the source from the [Jackson GitHub repo](https://github.com/boxyhq/jackson/tree/release)
```bash
git clone https://github.com/boxyhq/jackson
```
```bash
cd jackson
```
### Install dependencies
```bash
npm install
```
### Add environment variables
```bash
cp .env.example .env
```
Update `.env` with your values. See the complete list of [Environment Variables](./env-variables.md)
### Build and run
```bash
npm run build
```
```bash
npm run start
```
## Test the service is running
Open a browser and visit [http://localhost:5225](http://localhost:5225).
If you see a page asking you to sign in, congrats 🎉 you are seeing the [Admin Portal](../../admin-portal/overview).
## Database
Jackson currently supports the following databases.
- Postgres
- MySQL
- Microsoft SQL Server
- MariaDB
- MongoDB
- Redis
- [PlanetScale](https://planetscale.com/) (MySQL compatible)
- [Neon](https://neon.tech) (Serverless Postgres)
- Amazon DynamoDB
### PlanetScale
To connect PlanetScale database with Jackson, follow the below steps:
1. Create a new database on PlanetScale
2. Get your database [connection URL from the PlanetScale](https://planetscale.com/docs/tutorials/deploy-to-netlify#get-your-connection-string-from-planetscale)
3. Set the following environment variables
- `DB_ENGINE=planetscale`
- `DB_TYPE=mysql`
- `DB_SSL=true`
- `DATABASE_URL=<PlanetScale connection URL>`
4. Run the database migration to create the tables required by SAML Jackson
```bash
cd npm && PLANETSCALE_URL=<PlanetScale connection URL> npm run db:migration:run:planetscale
```
Make sure you have `?ssl={"rejectUnauthorized":true}` at the end of the PlanetScale connection URL.
Now you are ready to start the service.
## SAML Tracer
Each error event in the SAML request/ response phase is captured to aid in troubleshooting the SAML setup. The record or trace contains context related to the flow, like tenant, product, etc. The Admin Portal will have a tab under Enterprise SSO -> SAML Tracer showing a paginated list of traces over time. Developers can inspect a trace and will be able to ascertain the real reason for the failure.
## Deployment Guides (Coming soon)
- Heroku
- DigitalOcean
- Vercel
- Docker
- Kubernetes
- AWS
- GCP
- Azure

View File

@ -1,117 +0,0 @@
---
title: Enterprise SSO Webhook Events
sidebar_label: Events
---
# Webhook Events
SAML Jackson uses webhooks to notify your application any time changes are made to the connections. We'll notify you of the following 4 events for each connection.
## Events
<details>
<summary>
sso.created - New connection has been created.
</summary>
<p>
```json
{
"event": "sso.created",
"tenant": "boxyhq",
"product": "demo",
"data": {
"name": "SSO Connection",
"description": "SSO Connection for BoxyHQ",
"clientID": "326991705d478f0178fc2b49e35cd166dc771061",
"clientSecret": "15b2db91b2ba4c848b68148f108035e7138d69104d99de89",
"provider": "saml.example.com",
"friendlyProviderName": null
}
}
```
</p>
</details>
<details>
<summary>
sso.deactivated - A connection has been deactivated.
</summary>
<p>
```json
{
"event": "sso.deactivated",
"tenant": "boxyhq",
"product": "demo",
"data": {
"name": "SSO Connection",
"description": "SSO Connection for BoxyHQ",
"clientID": "326991705d478f0178fc2b49e35cd166dc771061",
"clientSecret": "15b2db91b2ba4c848b68148f108035e7138d69104d99de89",
"provider": "saml.example.com",
"friendlyProviderName": null
}
}
```
</p>
</details>
<details>
<summary>
sso.activated - A connection has been activated.
</summary>
<p>
```json
{
"event": "sso.activated",
"tenant": "boxyhq",
"product": "demo",
"data": {
"name": "SSO Connection",
"description": "SSO Connection for BoxyHQ",
"clientID": "326991705d478f0178fc2b49e35cd166dc771061",
"clientSecret": "15b2db91b2ba4c848b68148f108035e7138d69104d99de89",
"provider": "saml.example.com",
"friendlyProviderName": null
}
}
```
</p>
</details>
<details>
<summary>
sso.deleted - A connection has been deleted.
</summary>
<p>
```json
{
"event": "sso.deleted",
"tenant": "boxyhq",
"product": "demo",
"data": {
"name": "SSO Connection",
"description": "SSO Connection for BoxyHQ",
"clientID": "326991705d478f0178fc2b49e35cd166dc771061",
"clientSecret": "15b2db91b2ba4c848b68148f108035e7138d69104d99de89",
"provider": "saml.example.com",
"friendlyProviderName": null
}
}
```
</p>
</details>
## Configure Webhook
To configure the webhook, you have to set the following environment variables.
- `WEBHOOK_URL` - The URL to which the webhook events will be sent.
- `WEBHOOK_SECRET` - The secret key used to sign the webhook events.

View File

@ -1,27 +0,0 @@
---
title: Examples & Resources (Enterprise SSO)
sidebar_label: Examples & Resources
description: Examples & Resources for our Enterprise SSO product
---
# Examples & Resources (Enterprise SSO)
## Examples
- [Jackson with Next.js and NextAuth.js](https://github.com/boxyhq/jackson-examples/tree/main/apps/next-auth)
- [Jackson with Remix and remix-auth](https://github.com/boxyhq/jackson-remix-auth)
- [Jackson with React and client-side OAuth](https://github.com/boxyhq/jackson-examples/tree/main/apps/react)
- [Jackson with Express.js](https://github.com/boxyhq/jackson-examples/tree/main/apps/express)
- [Jackson with Supertokens and Express.js](https://github.com/boxyhq/jackson-supertokens-express)
- [Jackson with Express.js and Auth0](https://github.com/boxyhq/express-jackson-auth0-demo)
## Resources
- [Mock SAML hosted service](https://mocksaml.com)
- [Mock SAML](https://github.com/boxyhq/mock-saml)
- [NextAuth.js Provider](https://next-auth.js.org/providers/boxyhq-saml)
- [Remix Auth Strategy](https://github.com/boxyhq/remix-auth-saml)
## Third-party examples
- [Jackson with Next.js and Supertokens](https://github.com/nadilas/jackson-next-supertokens)

View File

@ -1,57 +0,0 @@
# Local Development
This guide will help you to setup and run SAML Jackson in development mode.
## Clone the repo
```bash
git clone https://github.com/boxyhq/jackson.git
cd jackson
```
## Install dependencies
Run the following command to install the Node dependencies.
```bash
npm install
```
## Setup environment variables
```bash
cp .env.example .env
```
Please refer to [environment variables](./deploy/env-variables.md) to read on setting environment variables.
## Setup the database
Run the following command to create database instances for the local development. Make sure you have Docker installed on your machine.
```bash
npm run dev-dbs
```
## Start the development server
Start the development server by running the following command.
```bash
npm run dev
```
## Testing Jackson in your local environment
The Jackson service can be accessed locally using the following URL
```bash
http://localhost:5225
```
You can visit the following URL to see if the Jackson was started successfully!
```bash
http://localhost:5225/api/hello
```

View File

@ -1,16 +0,0 @@
# Observability
Jackson provides first-class observability on the back of OpenTelemetry. Currently we support the following metrics. Traces and logs are coming soon.
Please check the [Environment Variables](./deploy/env-variables.md#opentelemetry-configuration) to configure to enable this feature.
## Metrics
| Name | Description | Type |
| --------------------------- | ---------------------------------------- | ----- |
| `jackson.connection.create` | Number of SSO Connection create requests | Count |
| `jackson.connection.get` | Number of SSO Connection get requests | Count |
| `jackson.connection.delete` | Number of SSO Connection delete requests | Count |
| `jackson.oauth.authorize` | Number of oauth authorize requests | Count |
| `jackson.oauth.token` | Number of oauth token requests | Count |
| `jackson.oauth.userinfo` | Number of oauth user info requests | Count |

View File

@ -1,48 +0,0 @@
---
title: Enterprise SSO Docs
---
# Enterprise SSO
Jackson is our Single Sign-On (SSO) service for SAML/OIDC Identity Providers [SSO in a box from BoxyHQ].
Jackson implements SSO as an OAuth 2.0 flow, abstracting away all the complexities of the underlying SAML/OIDC protocol. Check out our [GitHub repo](https://github.com/boxyhq/jackson).
## Architecture
![img alt](/img/enterprise-sso-arch.png)
We have developed Jackson from scratch adopting a modular architecture as shown below. The business logic is separated into controllers which helps us in incremental adoption of features.
![img alt](/img/jackson-architecture.png)
## Key Features
### Own your own data
- An open-source solution that allows you to keep control of your data
- Supports Bring Your Own Database (BYOD) and can be used with any database
- Built-in support for MySQL, MariaDB, Postgres, MongoDB, Redis, PlanetScale
- Works great with databases from popular hosting providers
### Flexible and easy to use
- Designed to work with OAuth 2.0 / OpenID Connect 1.0 flow
- Integrate with your existing OAuth 2.0 / OpenID Connect 1.0 library
### Support
Reach out to the maintainer at one of the following places:
- [GitHub Discussions](https://github.com/boxyhq/jackson/discussions)
- [GitHub Issues](https://github.com/boxyhq/jackson/issues)
- The email which is located [in GitHub profile](https://github.com/deepakprabhakara)
### Community
- [Discord](https://discord.gg/uyb7pYt4Pa)
- [Twitter](https://twitter.com/boxyhq)
### License
[Apache 2.0 License](https://github.com/boxyhq/jackson/blob/main/LICENSE)

View File

@ -1,25 +0,0 @@
---
title: SAML Federation
sidebar_label: SAML Federation
---
# SAML Federation
SAML Federation is an enterprise feature and you need to have an enterprise license to use this feature.
This feature allows you to federate multiple Identity Providers (IdPs) without needing any additional plugins or code changes. Extremely useful in cases where the SAML support is restricted to a single provider and you need to support multiple IdPs. Contact us to find out more.
## SAML Federation Flow
Here is how the SAML Federation flow works if you are using Jackson as a SAML IdP and want to federate with another identity provider (IdP) (Eg: Okta):
- The user accesses the Service Provider's (SP) login page
- The user clicks on the "Login with SAML" button
- The SP sends SAML Request to Jackson's SSO endpoint
- Jackson displays the list of IdP available for the user to choose from (if there is more than one IdP) based on the requested tenant and product combination
- Jackson redirects the user to the chosen IdP for authentication
- After successful authentication, IdP sends (POST) SAML Response to Jackson's ACS endpoint
- Jackson process SAML Response from the IdP and create a new SAML Response to send (POST) back to the SP's ACS endpoint
- SP process SAML Response from Jackson and create a new session for the user (Depending on the SP's implementation)
Visit [Create SAML Federation App](/docs/admin-portal/enterprise-sso#saml-federation) to learn how to create and configure a SAML Federation App.

View File

@ -1,25 +0,0 @@
# Software Bill Of Materials (SBOM) Reports
[SBOM](https://en.wikipedia.org/wiki/Software_bill_of_materials) is a list of components in a piece of software. It is like a list of ingredients of a product and is quickly becoming a standard for software supply chain risk management. The ecosystem is growing with tools that help you verify, scan and monitor all your dependencies.
## Report Standards
SBOM reports primarily use [SPDX](https://en.wikipedia.org/wiki/Software_Package_Data_Exchange) & [CycloneDX](https://cyclonedx.org/) standards.
## Reports
**Note:** This is supported for all versions >=0.3.8
You can find the SBOM reports as artifacts in our container registry at the locations below. They are updated every time there is change in the codebase and tagged by the exact version we release.
| Location | Files | Context |
| ----------------------------------------------- | ----------------------------- | ------------------------------------- |
| `ghcr.io/boxyhq/jackson/sbom:service-<version>` | `sbom.spdx`, `sbom.cyclonedx` | SAML Jackson service |
| `ghcr.io/boxyhq/jackson/sbom:npm-<version>` | `sbom.spdx`, `sbom.cyclonedx` | NPM package |
| `ghcr.io/boxyhq/jackson/sbom:docker-<version>` | `sbom.spdx`, `sbom.cyclonedx` | Docker Image for SAML Jackson service |
You can use [oras](https://oras.land/docs/category/cli) (or a similar OCI artifacts tool) to retrieve these files.
```bash
oras pull ghcr.io/boxyhq/jackson/sbom:service-<version>
```

View File

@ -1,17 +0,0 @@
# Security
In general most OAuth 2.0 security guidelines apply to Jackson as well but there are a few minor differences.
## Tenancy
OAuth 2.0 is typically a single instance and all users can login using the same instance. However SAML is based on an specific instance that your customers have to configure with their Identity Provider. This means that access to the SAML instance is limited to only those that have been provisioned for it, adding another layer of security to the login flow.
## Client Secret
The Config API returns a `client_id` and `client_secret` that you can save for each customer and use when initiating the OAuth 2.0 flow. However for convenience we also let you use a `tenant` and `product` instead since this doesn't require you to store any additional data. When using this we recommend you use the [CLIENT_SECRET_VERIFIER](./deploy/env-variables.md#client_secret_verifier) configuration and not use the default `dummy` value. The `client_secret` cannot really be misused because as you will see in the next section the tokens are short lived but it is a good idea to set the `client_secret` to something that is really a secret.
For client-side logins we highly recommend you use the PKCE flow which is supported by Jackson. This ensures a secure login without revealing the `client_secret` on the client-side.
## Tokens
The tokens generated by Jackson are short lived (default is 5 minutes) and hence there is no risk of it being misused even if the `client_secret` is known. Your SAML provider ensures that there can be no unauthorized.

View File

@ -1,29 +0,0 @@
---
title: Example flow
sidebar_label: Example flow
---
## Scenario
Let's say you have a customer `acme.com` who is using two of your SaaS offerings. For now let's call them:
- `CRM (Customer Relationship Management)` - Should integrate with the customer (of acme.com) facing SAML Identity Provider (Azure AD)
- `HRM (Human Resource Management)` - Should integrate with the Google workspace account of `acme.com` employees.
Let's see how SSO works in this case.
## Configure the SSO Connection
First as the application developer, you'll need to [add](./index.md#21-add-connection) the SSO connections for CRM and HRM. This will be saved (marked as SAML Metadata and OIDC Metadata in the below diagram) within Jackson and later used to orchestrate the IdP login.
## Login flow
Jackson uses the Authorization Code flow as outlined by the numbered steps below.
1. The Client (Browser app) initiates the login by redirecting to Jackson [`authorize`](./index.md#31-authorize) endpoint. Jackson will parse the tenant/product in the request and use it to redirect the user to the configured IdP.
2. Step 2 varies based on the Identity Provider type. For SAML IdP, Jackson would construct the SAML request, sign it and send it to IdP. The IdP validates the request and redirects the user to the login screen. For OIDC IdP, Jackson constructs an OpenID Connect request and redirects the user to the OIDC Provider authorization endpoint.
3. Once the user is logged in successfully, the IdP redirects back to Jackson. For SAML, the response contains the user profile. In the case of OIDC, the response contains the authorization code that is used by Jackson to obtain token and userprofile from the OIDC IdP. Jackson generates a short lived code and stores the user profile against it.
4. The authorization code generated in the previous step is sent to the client app.
5. The client [`exchanges`](./index.md#32-code-exchange) the code for token and uses it to query the [`userInfo`](./index.md#33-profile-request) endpoint of Jackson to get the complete user profile.
![img alt](/img/sso-flow.png)

View File

@ -1,333 +0,0 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Single Sign-On (SSO)
Jackson takes a multi-tenanted approach to implementing SSO, abstracting away all the complexities of the underlying SAML/OIDC protocol. What this means is you can enable SSO for all (your) customers across products from a single instance of jackson, and works with both SAML and OIDC Identity Provider(IdP)s.
**Note:** All the APIs below support both `application/x-www-form-urlencoded` and `application/json` content types. Examples below use `application/x-www-form-urlencoded`.
**Note:** OAuth 2.0 protocol uses underscore casing for the parameters, we use camel casing for all our APIs. For example it's `client_id` in the OAuth 2.0 flow and `clientID` in our APIs.
## 1. Setting up SSO Provider
Please follow the instructions [here](../sso-providers) to guide your customers in setting up SAML/OIDC correctly for your product(s). You should create a copy of the doc and modify it with your custom settings, we have used the values that work for our demo apps.
## 2. SSO Connection API
You will need to provide a place in the UI for your customers (The account settings page is usually a good place for this) to configure this and then call the APIs below.
### 2.1 Add connection
<Tabs>
<TabItem value="saml" label="SAML" default>
Once your customer has set up the SAML app on their Identity Provider, the Identity Provider will generate an IdP or SP metadata file. Some Identity Providers only generate an IdP metadata file but it usually works for the SP login flow as well. It is an XML file that contains various attributes Jackson needs to validate incoming SAML login requests. This step is the equivalent of setting an OAuth 2.0 app and generating a client ID and client secret that will be used in the login flow.
The following API call sets up the connection in Jackson:
```bash
curl --location --request POST 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'encodedRawMetadata=Base64(<IdP/SP metadata XML>)' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/saml' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=boxyhq.com' \
--data-urlencode 'product=demo' \
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo SAML connection'
```
- `metadataUrl`: URL containing the SAML metadata contents. Either this or `encodedRawMetadata` needs to be specified
- `encodedRawMetadata`: Base64 encoding of the XML metadata your customer gets from their Identity Provider. Either this or `metadataUrl` needs to be specified
- `defaultRedirectUrl`: The redirect URL to use in the IdP login flow. Jackson will call this URL after completing an IdP login flow
- `redirectUrl`: Allowed redirect URL. Repeat this field multiple times to allow multiple redirect URLs. Jackson will disallow any redirects not on this list (or not the default URL above).
- `tenant`: Jackson supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id. **Should not contain the : character since we use it as a delimiter internally**
- `product`: Jackson support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using. **Should not contain the : character since we use it as a delimiter internally**
- `name`: A friendly name to identify the SAML connection
- `description`: A short description with some information of the connection
The response returns a JSON with `clientID` and `clientSecret` that can be stored against your tenant and product for a more secure OAuth 2.0 flow. If you do not want to store the `clientID` and `clientSecret` you can alternatively use `client_id=tenant=<tenantID>&product=<productID>` and use `dummy` (or the value you set for the [secret verifier](../deploy/env-variables.md#client_secret_verifier) env) as the value for `client_secret` when setting up the OAuth 2.0 flow. Additionally a `idpMetadata.provider` attribute is also returned which indicates the domain of your Identity Provider.
</TabItem>
<TabItem value="oidc" label="OIDC">
Once your customer has set up the [OIDC app](../sso-providers/generic-oidc.md) on their Identity Provider, the Identity Provider will generate a clientId and clientSecret.
The following API call sets up the connection in Jackson:
```bash
curl --location --request POST 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/oidc' \
--data-urlencode 'oidcDiscoveryUrl=<well-known url of OIDC Provider>' \
--data-urlencode 'oidcClientId=<clientId of IdP Registered App>' \
--data-urlencode 'oidcClientSecret=<clientSecret of IdP Registered App>' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=boxyhq.com' \
--data-urlencode 'product=demo' \
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo OIDC connection'
```
- `oidcDiscoveryUrl`: OpenID Providers supporting discovery make the metadata available at the endpoint obtained by concatenating issuer and `/.well-known/openid-configuration`
- `oidcClientId`: The client identifier issued to the client during the IdP registration process.
- `oidcClientSecret`: The client secret issued to the client during the IdP registration process.
- `defaultRedirectUrl`: The redirect URL to use in the IdP login flow. Jackson will call this URL after completing an IdP login flow
- `redirectUrl`: Allowed redirect URL. Repeat this field multiple times to allow multiple redirect URLs. Jackson will disallow any redirects not on this list (or not the default URL above).
- `tenant`: Jackson supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id. **Should not contain the : character since we use it as a delimiter internally**
- `product`: Jackson support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using. **Should not contain the : character since we use it as a delimiter internally**
- `name`: A friendly name to identify the OIDC connection
- `description`: A short description with some information of the connection
The response returns a JSON with `clientID` and `clientSecret` that can be stored against your tenant and product for a more secure OAuth 2.0 flow. If you do not want to store the `clientID` and `clientSecret` you can alternatively use `client_id=tenant=<tenantID>&product=<productID>` and use `dummy` (or the value you set for the [secret verifier](../deploy/env-variables.md#client_secret_verifier) env) as the value for `client_secret` when setting up the OAuth 2.0 flow. Additionally a `idpMetadata.provider` attribute is also returned which indicates the domain of your Identity Provider.
</TabItem>
</Tabs>
### 2.2 Get connections
This endpoint can be used to retrieve SAML/OIDC connections configured for a tenant/product. This can be used to check and display the details to your customers. You can use either `clientID` or `tenant` and `product` combination.
<Tabs>
<TabItem value="saml" label="SAML" default>
```bash
curl -G --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'tenant=boxyhq.com' \
--data-urlencode 'product=demo'
```
```bash
curl -G --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>'
```
The response returns a JSON with `idpMetadata.provider`indicating the domain of your Identity Provider. If an empty JSON payload is returned then we do not have any connection stored for the attributes you requested.
</TabItem>
<TabItem value="oidc" label="OIDC">
```bash
curl -G --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'tenant=boxyhq.com' \
--data-urlencode 'product=demo'
```
```bash
curl -G --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>'
```
The response returns a JSON with `oidcProvider.provider` indicating the domain of your Identity Provider. If an empty JSON payload is returned then we do not have any connection stored for the attributes you requested.
</TabItem>
</Tabs>
### 2.3 Update connection
This endpoint can be used to update an existing SSO Connection.
<Tabs>
<TabItem value="saml" label="SAML" default>
```bash
curl --location --request PATCH 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>' \ /* Required */
--data-urlencode 'clientSecret=<Client Secret>' \ /* Required */
--data-urlencode 'encodedRawMetadata=Base64(<IdP/SP metadata XML>)' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/saml' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=boxyhq.com' \ /* Required */
--data-urlencode 'product=demo' \ /* Required */
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo SAML connection'
```
</TabItem>
<TabItem value="oidc" label="OIDC" default>
```bash
curl --location --request PATCH 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>' \ /* Required */
--data-urlencode 'clientSecret=<Client Secret>' \ /* Required */
--data-urlencode 'oidcDiscoveryUrl=<well-known url of OIDC Provider>' \
--data-urlencode 'oidcClientId=<clientId of IdP Registered App>' \
--data-urlencode 'oidcClientSecret=<clientSecret of IdP Registered App>' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/oidc' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=boxyhq.com' \ /* Required */
--data-urlencode 'product=demo' \ /* Required */
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo OIDC connection'
```
</TabItem>
</Tabs>
### 2.4 Delete connections
This endpoint can be used to delete existing connections either by tenant/product or clientID.
```bash
curl -X "DELETE" --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--url-query 'tenant=boxyhq.com' \
--url-query 'product=demo'
```
```bash
curl -X "DELETE" --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Jackson API Key>' \
--url-query 'clientID=<Client ID>'
--url-query 'clientSecret=<Client Secret>'
```
## 3. OAuth 2.0 Flow
:::info
#### OpenID Connect flow
Jackson also supports the [OIDC flow](https://openid.net/specs/openid-connect-core-1_0.html). By including `openid` in the `scope` param, an additional `id_token` is returned from the token endpoint which contains the user claims: `id, email, firstName, and lastName`. To enable the flow on Jackson, be sure to configure the keys and algorithm in [OpenID configuration](../deploy/env-variables.md#openid-configuration). If the authentication request contained `nonce` then it is passed unmodified to the ID Token, which the client can use to validate and mitigate replay attacks.
:::
Jackson has been designed to abstract the underlying SAML/OIDC login flow as a pure OAuth 2.0 flow. This means it's compatible with any standard OAuth 2.0 library out there, both client-side and server-side. It is important to remember that SSO Connection is configured per customer unlike OAuth 2.0 where you can have a single OAuth app supporting logins for all customers.
Jackson also supports the PKCE authorization flow (<https://oauth.net/2/pkce/>), so you can protect your SPAs.
If for any reason you need to implement the flow on your own, the steps are outlined below:
### 3.1 Authorize
The OAuth flow begins with redirecting your user to the `authorize` URL:
```bash
https://localhost:5225/api/oauth/authorize
?response_type=code&provider=saml
&client_id=<clientID or tenant and product query params as described in the SSO connection API section above>
&redirect_uri=<redirect URL>
&state=<randomly generated state id>
```
- `response_type`: `code` is the only supported type for now but maybe extended in the future
- `client_id`: Use the client_id returned by the SSO connection API or use `tenant=<tenantID>&product=<productID>` to use the tenant and product IDs instead. **Note:** Please don't forget to URL encode the query parameters including `client_id`.
- `tenant`: Optionally you can provide use `dummy` as the value for `client_id` and specify the `tenant` and `product` custom attributes (if your OAuth 2.0 library allows it).
- `product`: Should be specified if specifying `tenant` above
- `idp_hint`: Can be used to select the Identity Provider if multiple connections match for the same `tenant/product`. Should point to the absolute "clientID" of the SSO Connection in Jackson.
- `redirect_uri`: This is where the user will be taken back once the authorization flow is complete
- `state`: Use a randomly generated string as the state, this will be echoed back as a query parameter when taking the user back to the `redirect_uri` above. You should validate the state to prevent XSRF attacks.
- `nonce` (for OIDC flow): String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values.
- `forceAuthn` (for SAML SSO Connections): If passed in with the value `true`, the outgoing SAML request to IdP will have the param `ForceAuthn` set as true forcing the user to re-authenticate even if they have an active session.
- `login_hint` (Relevant for OIDC IdPs like Google): If passed in, the parameter will be forwarded in the OIDC IdP authorize request. The IdP can use this value (normally an account identifier such as an email address) as a hint to skip the account selection page.
**NOTE**: You can also pass the encoded tenant/product in either `scope` or `access_type` or `resource` (Set `client_id` as `dummy`). This will come in handy for some setups where the client_id can't be set dynamically.
The user will be taken to the IdP based on the configured SAML/OIDC metadata.
In case of any errors, we return the `error`, `error_description` and `state` (from original request) (see [Error Response](https://www.oauth.com/oauth2-servers/authorization/the-authorization-response/)) back to the `redirect_uri` (`redirect_uri` is validated against the saml connection to prevent open redirects).
### 3.2 Code Exchange
Once the user logs in successfully at the IdP, IdP sends back the SAML/OIDC response to Jackson. For SAML, the response contains the user profile. In the case of OIDC, the response contains the authorization code that is used by Jackson to obtain token and userprofile from the OIDC IdP. Jackson generates a short lived `code` and stores the user profile against it. After successful authorization, the user is redirected back to the `redirect_uri`. The query parameters will include the `code` and `state` parameters. You should validate that the state matches the one you sent in the `authorize` request.
The code can then be exchanged for a token by making the following request:
```bash
curl --request POST \
--url 'http://localhost:5225/api/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'grant_type=authorization_code' \
--data 'client_id=<clientID or tenant and product query params as described in the SAML connection API section above>' \
--data 'client_secret=<clientSecret or any arbitrary value if using the tenant and product in the clientID>' \
--data 'redirect_uri=<redirect URL>' \
--data 'code=<code from the query parameter above>'
```
- `grant_type`: `authorization_code` is the only supported flow, for now. We might extend this in the future
- `client_id`: Use the client_id returned by the SSO connection API or use `tenant=<tenantID>&product=<productID>` to use the tenant and product IDs instead. **Note:** Please don't forget to URL encode the query parameters including `client_id`.
- `client_secret`: Use the client_secret returned by the SAML connection API or any arbitrary value if using the tenant and product in the clientID
- `redirect_uri`: This is where the user will be taken back once the authorization flow is complete. Use the same redirect_uri as the previous request
If everything goes well you should receive a JSON response that includes the access token. This token is needed for the next step where we fetch the user profile.
```json
{
"access_token": <access token>,
"token_type": "bearer",
"expires_in": 300
}
```
### 3.3 Profile Request
The short-lived access token can now be used to request the user's profile. You'll need to make the following request:
```bash
curl --request GET \
--url 'https://localhost:5225/api/oauth/userinfo' \
--header 'authorization: Bearer <access token>'
```
If everything goes well you should receive a JSON response with the user's profile:
```json
{
"id": <id from the Identity Provider>,
"email": "sjackson@coolstartup.com",
"firstName": "SAML",
"lastName": "Jackson"
"raw": {
...
},
"requested": {
...
}
}
```
- `id`: The id of the user as provided by the Identity Provider. (SAML SLO request requires you to pass `id` as `nameId`. Save `id` if you have a plan to implement SLO in the future.)
- `email`: The email address of the user as provided by the Identity Provider
- `firstName`: The first name of the user as provided by the Identity Provider
- `lastName`: The last name of the user as provided by the Identity Provider
- `raw`: This contains all claims attributes returned by the SAML provider
- `requested`: This contains the `tenant`, `product`, `client_id` and `state` from the authorize request. It can be used to reconcile context on the client side if needed
## 4. SAML SLO
SLO is a SAML flow that allows an end-user to logout of a single session and be automatically logged out of all linked sessions created during the SSO process.
The SLO flow begins with redirecting your user to the `/api/logout` endpoint.
```bash
https://localhost:5225/api/logout
?nameId=google-auth0-f92cc1834efc0f73e9c09
&tenant=boxyhq.com
&product=demo
&redirectUrl=http://www.example.com/logout
```
- `nameId`: Identifies the subject of a SAML assertion (Typically the user who is authenticated)
- `tenant`: The tentant
- `product`: The product
- `redirectUrl`: Post logout redirect URL
IdP will send a response (as a POST operation) to a specific URL (Single Logout URL) for the logout request. You need to register this URL on the IdP `/api/logout/callback` to handle the response.
Jackson will redirect users to `redirectUrl` after the successful logout.
:::info
You should save the `id` returned by the `userinfo` for an user so that you can use the `id` as `nameId` with SLO request.
:::

View File

@ -1,54 +0,0 @@
---
title: Set up your own custom SAML application for Auth0 SAML
sidebar_label: Auth0 SAML
---
# Auth0 SAML SSO
In this section, we will show you how to set up your own custom SAML application for Auth0 SAML.
## Create Application
From your Auth0 dashboard, click **Applications** from the left navigation menu.
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
![img alt](/img/sso-providers/auth0/1.png)
If you haven't created a SAML application, click the **Create Application** button to create a new application.
Give your application a **Name** and click **Create**.
![img alt](/img/sso-providers/auth0/5.png)
## Configure Application
Click the tab **Addons** and enable **SAML2 WEB APP** addon.
![img alt](/img/sso-providers/auth0/2.png)
Enter your **Application Callback URL** on the next screen and click **Enable**.
Replace the values with the ones you have received from SAML Jackson.
![img alt](/img/sso-providers/auth0/3.png)
Click the tab **Usage** and download the **Identity Provider Metadata**.
![img alt](/img/sso-providers/auth0/4.png)
## Attribute Mapping
No additional attribute mapping is required for Auth0 SAML to work with SAML Jackson.
## Next steps
You've successfully configured your custom SAML application for Auth0 SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [Auth0 Doc](https://auth0.com/docs)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,80 +0,0 @@
---
title: Set up your own custom SAML application for Azure AD SAML
sidebar_label: Azure AD SAML
---
# Azure AD SAML SSO
In this section, we will show you how to set up your own custom SAML application for Azure AD SAML.
## Create Application
From your Azure Admin console, click **Enterprise applications** from the left navigation menu.
![img alt](/img/sso-providers/azure/1.png)
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
If you haven't created a SAML application, click **New application** from the top to create a new application.
![img alt](/img/sso-providers/azure/2.png)
From the next screen, click **Create your own application**. Give your application a **Name** and click **Create**.
![img alt](/img/sso-providers/azure/3.png)
## Configure Application
Select **Single Sign On** from the **Manage** section of your app and then **SAML**.
![img alt](/img/sso-providers/azure/4.png)
Click **Edit** on the **Basic SAML Configuration** section.
![img alt](/img/sso-providers/azure/5.png)
Enter the following values in the **Basic SAML Configuration** section on the next screen:
- **Identifier (Entity ID)**
- **Reply URL (Assertion Consumer Service URL)**
Replace the values with the ones you have received from SAML Jackson.
Click **Save** to save your changes.
![img alt](/img/sso-providers/azure/6.png)
## Attribute Mapping
Click **Edit** on the **Attributes & Claims** section.
![img alt](/img/sso-providers/azure/7.png)
You have to configure the following attributes under the **Attributes & Claims** section:
| Name | Value |
| -------------------------------------------------------------------- | ---------------------- |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` | user.mail |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname` | user.givenname |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name` | user.userprincipalname |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` | user.surname |
See the screenshot below.
![img alt](/img/sso-providers/azure/8.png)
Go to the section **SAML Signing Certificate** section and download the **Federation Metadata XML**.
![img alt](/img/sso-providers/azure/9.png)
## Next steps
You've successfully configured your custom SAML application for Azure AD SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [Azure Admin Console](https://portal.azure.com/)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,16 +0,0 @@
---
title: Set up app in your OpenID Connect Identity Provider
sidebar_label: OpenID Connect Provider
---
# OIDC Provider setup
To allow apps or clients to login using an OIDC Identity Provider, we must register an application with the IdP. The process might slightly vary from one IdP to another (refer your IdP documentation), but there are a few things in common.
- **Callback URL**: This will be the URL where Jackson receives the OIDC Authorization response. Make sure to set the full HTTPS URL obtained by concatenating Jackson endpoint with [oidcPath](../deploy/env-variables.md#oidc_path) env. The default value set for `oidcPath` in Jackson service is `/api/oauth/oidc`.
- **Client/Application ID**: The OIDC Identity Provider normally will generate a unique identifier for the registered App. Make a note of this to be used later when creating the SSO connection with Jackson.
- **Client Secret**: Along with the Client ID, the IdP also generates a client secret which is used to authenticate the client while issuing tokens. Make a note of this to be used later when creating the SSO connection with Jackson.
:::info
Since Jackson acts as a proxy between the app and the OIDC Identity Provider, here the application/client is Jackson.
:::

View File

@ -1,39 +0,0 @@
---
title: Set up your own custom SAML application for a Generic IdP
sidebar_label: Generic SAML 2.0 Provider
---
# Generic SAML
This guide explains the settings youd need to use to configure SAML with your Identity Provider. Once this is set up you should get an XML metadata file that should then be configured using our [API (or calling the API controller connection method if using our NPM)](../sso-flow/index.md#21-add-connection).
> Please do not add a trailing slash at the end of the URLs.
Create them exactly as shown below:
- Assertion consumer service URL / Single Sign-On URL / Destination URL: `http://localhost:5225/api/oauth/saml`
- Entity ID / Identifier / Audience URI / Audience Restriction: `https://saml.boxyhq.com`
- Response: `Signed`
- Assertion Signature: `Signed`
- Signature Algorithm: `RSA-SHA256`
- Assertion Encryption: `Unencrypted`
:::info
The deployed Jackson service has a Service Provider (SP) endpoint that exposes the above metadata and the same can be accessed at `<jackson_endpoint>/.well-known/saml-configuration`.
:::
## SAML profile/claims/attributes mapping
As outlined in the guide above we try and support 4 attributes in the SAML claims - `id`, `email`, `firstName`, `lastName`. This is how the common SAML attributes map over for most providers, but some providers have custom mappings. Please refer to the documentation on Identity Provider to understand the exact mapping.
| SAML Attribute | Jackson mapping |
| ---------------------------------------------------------------------- | --------------- |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier` | id |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress` | email |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname` | firstName |
| `http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname` | lastName |

View File

@ -1,73 +0,0 @@
---
title: Set up your own custom SAML application for Google SAML
sidebar_label: Google SAML
---
# Google SAML SSO
In this section, we will show you how to set up your own custom SAML application for Google SAML.
## Create Application
From your Google Admin console, click **Apps** from the sidebar then click **Web and mobile apps** from the list.
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
If you haven't created a SAML application, click **Add custom SAML app** from the menu.
![img alt](/img/sso-providers/google/1.png)
Give your application an **App name** and click **Continue**.
![img alt](/img/sso-providers/google/2.png)
## Configure Application
From the next screen, click **DOWNLOAD METADATA** to download the metadata XML file, then click **Continue**.
![img alt](/img/sso-providers/google/3.png)
Enter the following values in the **Service provider details** section:
- **ACS URL**
- **Entity ID**
Replace the values with the ones you have received from SAML Jackson and click **Continue** to save the configuration.
![img alt](/img/sso-providers/google/4.png)
## Attribute Mapping
Under the **Attributes** section, you have to configure the following attributes:
| App attributes | Google directory attributes |
| -------------- | --------------------------- |
| email | Primary email |
| firstName | First name |
| lastName | Last name |
See the screenshot below.
After you have configured the attributes, click **Finish** to save the configuration.
![img alt](/img/sso-providers/google/5.png)
From the next screen, click **User access** to configure the application to allow users to log in.
![img alt](/img/sso-providers/google/6.png)
Check the **ON for everyone** checkbox and click **Save**.
![img alt](/img/sso-providers/google/7.png)
## Next steps
You've successfully configured your custom SAML application for Google SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [Google Admin Console](https://admin.google.com/)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,20 +0,0 @@
---
title: SAML SSO Providers
sidebar_label: SSO Providers
---
# SAML SSO Providers
SAML Jackson supports the following SSO providers:
- [Generic SAML 2.0 Provider](./generic-saml.md)
- [Azure](./azure.md)
- [Microsoft AD FS](./microsoft-adfs.md)
- [Okta](./okta.md)
- [Auth0](./auth0.md)
- [Google](./google.md)
- [OneLogin](./onelogin.md)
- [PingOne](./pingone.md)
- [JumpCloud](./jumpcloud.md)
- [Rippling](./rippling.md)
- [OpenID Connect Provider](./generic-oidc.md)

View File

@ -1,68 +0,0 @@
---
title: Set up your own custom SAML application for JumpCloud SAML
sidebar_label: JumpCloud SAML
---
# JumpCloud SAML SSO
In this section, we will show you how to set up your own custom SAML application for JumpCloud SAML.
## Create Application
From your JumpCloud Admin console, click **SSO** from the left navigation menu.
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
If you haven't created a SAML application, click plus icon and then **Custom SAML App** to create a new application
![img alt](/img/sso-providers/jumpcloud/1.png)
Give your application a **Display Label**.
![img alt](/img/sso-providers/jumpcloud/2.png)
## Configure Application
Next click on the **SSO** tab and enter the following values:
- **IdP Entity ID**
- **SP Entity ID**
- **ACS URL**
Replace the values with the ones you have received from SAML Jackson.
![img alt](/img/sso-providers/jumpcloud/3.png)
## Attribute Mapping
Under the **Attributes** section, you have to configure the following attributes:
See the screenshot below.
| Service Provider Attribute Name | JumpCloud Attribute Name |
| ------------------------------- | ------------------------ |
| email | email |
| firstName | firstname |
| lastName | lastname |
Make sure you have checked the **Declare Redirect Endpoint** checkbox.
Finally, click **Activate** to save the application configuration.
![img alt](/img/sso-providers/jumpcloud/4.png)
Now go back to the SAML app you just created, click the tab **SSO**, and click the button **Export Metadata** to download the metadata XML file.
![img alt](/img/sso-providers/jumpcloud/5.png)
## Next steps
You've successfully configured your custom SAML application for JumpCloud. At this stage, you can assign users to your application and start using it.
## Resources
- [JumpCloud](https://jumpcloud.com/) official website
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,51 +0,0 @@
---
title: Set up your own custom SAML application for Microsoft AD FS
sidebar_label: Microsoft AD FS
---
# Microsoft AD FS SAML SSO
In this section, we will show you how to set up your own custom SAML application for Microsoft AD FS.
In AD FS, a relying party (RP) trust needs to be set up. You can supply our SP metadata file, usually located at `https://<your-hosted-url>/.well-known/sp-metadata` and let AD FS automatically pick up the configuration.
If you are manually entering the details then you'll find the details you need in [this section](./generic-saml.md). The public certificate is needed for Signature verification and is usually located at `https://<your-hosted-url>/.well-known/saml.cer` for Signature verification.
You will also need to map some attributes of the claims so we can fetch the profile information for your user.
## Create a claims aware Relying Party Trust using federation metadata
1. In Server Manager, click Tools, and then select AD FS Management.
2. Under Actions, click Add Relying Party Trust.
![img alt](/img/sso-providers/adfs/addtrust1.png)
3. On the Welcome page, choose Claims aware and click Start.
![img alt](/img/sso-providers/adfs/addtrust2.png)
4. On the Select Data Source page, click Import data about the relying party published online or on a local network. In Federation metadata address (host name or URL), type the federation metadata URL or host name for the partner, and then click Next.
![img alt](/img/sso-providers/adfs/addtrust12.png)
5. On the Specify Display Name page type a name in Display name, under Notes type a description for this relying party trust, and then click Next.
6. On the Choose Issuance Authorization Rules page, select either Permit all users to access this relying party or Deny all users access to this relying party, and then click Next.
7. On the Ready to Add Trust page, review the settings, and then click Next to save your relying party trust information.
8. On the Finish page, click Close. This action automatically displays the Edit Claim Rules dialog box.
9. **Mapping attributes**:
On the Configure Claim Rule screen, enter a Claim Rule Name of your choice, select Active Directory as the Attribute Store, then add the following mapping:
- From the LDAP Attribute column, select `E-Mail-Addresses`. From the Outgoing Claim Type, type `E-Mail Address`.
- From the LDAP Attribute column, select `Given-Name`. From the Outgoing Claim Type, type `Given Name`.
- From the LDAP Attribute column, select `Surname`. From the Outgoing Claim Type, type `Surname`.
- From the LDAP Attribute column, select `User-Principal-Name`. From the Outgoing Claim Type, type `Name ID`.
10. **Transform Rule**: Create a transform rule mapping the incoming `Email-Address` to outgoing `NameID` (of type `Email`), ADFS by default sends `NameID` as `Unspecified` which results in an `InvalidNameIDPolicy` error if this step is missed.
![Transform rule](/img/sso-providers/adfs/nameid-email.png)
If you'd rather use Claim rule language then the following rule can be applied:
```sh
c:[Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"] => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType, Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/format"] = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");
```
11. Finally open Windows PowerShell as an administrator, then run the following command:
```sh
Set-ADFSRelyingPartyTrust -TargetName <display-name> -SamlResponseSignature "MessageAndAssertion"
```

View File

@ -1,76 +0,0 @@
---
title: Set up your own custom SAML application for Okta SAML
sidebar_label: Okta SAML
---
# Okta SAML SSO
In this section, we will show you how to set up your own custom SAML application for Okta SAML.
## Create Application
From your Okta account, click **Applications** from the left navigation menu.
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
If you haven't created a SAML application, click the **Create App Integration** button to create a new application.
![img alt](/img/sso-providers/okta/1.png)
Choose **SAML 2.0** from the next screen and click **Next**.
![img alt](/img/sso-providers/okta/2.png)
Give your application an **App Name** and click **Next**.
![img alt](/img/sso-providers/okta/3.png)
## Configure Application
Enter the following values in the **SAML Settings** section on the next screen:
- **Single sign on URL**
- **Audience URI (SP Entity ID)**
- Select **EmailAddress** from the **Name ID format** dropdown.
Replace the values with the ones you have received from SAML Jackson.
![img alt](/img/sso-providers/okta/4.png)
## Attribute Mapping
Under the **Attribute Statements** section, you have to configure the following attributes:
| Name | Value |
| --------- | -------------- |
| id | user.id |
| email | user.email |
| firstName | user.firstName |
| lastName | user.lastName |
See the screenshot below.
![img alt](/img/sso-providers/okta/5.png)
On the next screen select **I'm an Okta customer adding an internal app** and click **Finish**.
![img alt](/img/sso-providers/okta/6.png)
From your application, click **Sign On** tab and go to the section **SAML Signing Certificates**
Click the **Actions** dropdown for the correct certificate and click **View IdP metadata**. A separate window will open with the metadata XML file, you can copy it to your clipboard.
![img alt](/img/sso-providers/okta/7.png)
## Next steps
You've successfully configured your custom SAML application for Okta SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [Okta](https://www.okta.com/) official website
- Visit [Okta documentation](https://developer.okta.com/docs/concepts/saml/)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,91 +0,0 @@
---
title: Set up your own custom SAML application for OneLogin SAML
sidebar_label: OneLogin SAML
---
# OneLogin SAML SSO
In this section, we will show you how to set up your own custom SAML application for OneLogin SAML.
## Create Application
From your OneLogin account, click **Applications** from the top navigation menu.
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
If you haven't created a SAML application, click the **Add App** button to create a new application.
![img alt](/img/sso-providers/onelogin/1.png)
Search for **SAML Test Connector** in the **Find Applications** section. Select **SAML Custom Connector (Advanced)** from the search results.
![img alt](/img/sso-providers/onelogin/2.png)
Give your application a **Display Name** and click **Save**.
![img alt](/img/sso-providers/onelogin/3.png)
## Configure Application
From your application, click the **Configuration** tab on the left to configure the application.
You have to enter the following values in the **Application details** section:
- **Audience (Entity ID)**
- **ACS (Consumer) URL Validator**
- **ACS (Consumer) URL**
- Select the **Service Provider** from the **SAML initiator** dropdown.
Replace the values with the ones you have received from SAML Jackson.
Click **Save** to save the configuration.
![img alt](/img/sso-providers/onelogin/4.png)
![img alt](/img/sso-providers/onelogin/7.png)
Click the dropdown menu **More Actions** from the top right corner and click **SAML Metadata** to download the metadata XML file.
![img alt](/img/sso-providers/onelogin/5.png)
## Attribute Mapping
From your application, click the **Parameters** tab on the left.
You have to configure the following attributes:
| SAML Custom Connector Field | Value |
| --------------------------- | ---------- |
| id | UUID |
| email | Email |
| firstName | First Name |
| lastName | Last Name |
See the screenshot below.
![img alt](/img/sso-providers/onelogin/6.png)
See the below screenshot to see how to map the **id** attribute to **UUID**.
Enter **id** in the **Field name** input and check the **Include in SAML assertion** checkbox. Click **Save** to continue.
![img alt](/img/sso-providers/onelogin/8.png)
On the next screen, select **UUID** from the **Value** dropdown and click **Save**.
![img alt](/img/sso-providers/onelogin/9.png)
Do the same for the other attributes (email, firstName, lastName).
## Next steps
You've successfully configured your custom SAML application for OneLogin SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [OneLogin](https://www.onelogin.com/) official website
- Visit [OneLogin documentation](https://developers.onelogin.com/)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,71 +0,0 @@
---
title: Set up your own custom SAML application for PingOne SAML
sidebar_label: PingOne SAML
---
# PingOne SAML SSO
In this section, we will show you how to set up your own custom SAML application for PingOne SAML.
## Create Application
From your PingOne account, click **Connections** > **Applications** from left navigation menu.
If your application is already created, choose it from the list and move to the section [Configure Application](#configure-application)
If you haven't created a SAML application, click plus button to create a new application.
![img alt](/img/sso-providers/pingone/1.png)
Give your application a **Application Name**, choose **SAML Application** from the **Application Type** and click **Configure**.
## Configure Application
![img alt](/img/sso-providers/pingone/2.png)
From the next screen, you have to enter the following values in the **SAML Configuration** section:
- **ACS URLs**
- **Entity ID**
Replace the values with the ones you have received from SAML Jackson.
Click **Save** to save the configuration.
![img alt](/img/sso-providers/pingone/3.png)
Click the **Configuration** tab from the top and click **Download Metadata** to download the metadata XML file.
![img alt](/img/sso-providers/pingone/4.png)
## Attribute Mapping
Click the **Attribute Mappings** tab from the top and you have to configure the following attributes:
| SAML App | PingOne |
| --------- | ------------- |
| id | User ID |
| email | Email Address |
| firstName | Given Name |
| lastName | Family Name |
See the screenshot below.
![img alt](/img/sso-providers/pingone/5.png)
Make sure you have enabled your app so that it can be used by the users. You can do this by clicking the **Toggle** button next to your app.
![img alt](/img/sso-providers/pingone/6.png)
## Next steps
You've successfully configured your custom SAML application for PingOne SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [Ping Identity Website](https://www.pingidentity.com/en.html)
- [Ping Identity Documentation](https://docs.pingidentity.com/)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,58 +0,0 @@
---
title: Set up your own custom SAML application for Rippling SAML
sidebar_label: Rippling SAML
---
# Rippling SAML SSO
This section will show you how to set up your own custom SAML application for Rippling SAML.
## Create Application
You'll need to create a new **Custom App** from your Rippling account if the app is not already in the Rippling app directory.
Go to **IT Management** > **Custom App** from the left navigation menu.
![img alt](/img/sso-providers/rippling/1.png)
Click **Create New App** button to create a new application.
From the next screen, fill in the following fields:
- **App Name**
- **Select Categories**
- **Upload Logo**
- **What type of app would you like to create?** - Make sure you select **Single Sign-On (SAML)** from the list.
![img alt](/img/sso-providers/rippling/2.png)
## Configure Application
Copy the **Idp Metadata URL** or **Idp Metadata XML** from the next screen. You'll need this value to configure your SAML connection in SAML Jackson.
![img alt](/img/sso-providers/rippling/3.png)
You'll need to enter the **ACS URL** and **Entity ID**. You'll get these values from SAML Jackson.
![img alt](/img/sso-providers/rippling/4.png)
Make sure that **Service Provider Entity ID** matches the **SAML Audience (SP Entity ID)** value from SAML Jackson.
From the **Settings** tab of custom app you just created. Go to **Advanced SAML Settings** section and check the box for **Disable InResponseTo field in assertions for IdP initiated SSO**.
This is because Rippling sends dummy values for the **InResponseTo** field and SAML Jackson will try to validate the **InResponseTo** field if it is present.
![img alt](/img/sso-providers/rippling/5.png)
## Next steps
You've successfully configured your custom SAML application for Rippling SAML. At this stage, you can assign users to your application and start using it.
## Resources
- [Rippling](https://www.rippling.com/) official website
- Visit [Rippling documentation](https://developer.rippling.com/)
:::tip
Got a question? [Ask here](https://discord.gg/uyb7pYt4Pa)
:::

View File

@ -1,35 +0,0 @@
# Upgrade Guide
## Upgrading to v1.11.0
We have patched the SSO connection (`/api/v1/connections`) DELETE handler to accept payload (client/Secret or tenant/product/strategy) as part of query parameters. Earlier, the payload was expected to be part of the body which is non-standard and is no longer supported in Next.js.
## Upgrading to v1.9.7
We discovered and fixed a database connection leak introduced in v1.9.1, if you are using versions 1.9.1 to 1.9.6 then please upgrade to v1.9.7
## Upgrading to v1.8.0
1. We support bringing your own database (BYOD), this is a very tricky feature to support and we are still iterating on the schema which works as seamlessly as possible across the range of databases we support. Unfortunately, not everything goes smoothly here and we have encountered some length issues on newer versions of MySQL and MariaDB. The best way forward was to change the schema of the keys we use from length 1500 to 250 which is compatible with the newer versions. As a result, this will break your updates if you are using MySQL, MariaDB, or MS SQL Server. If you encounter this please reach out and we'll guide you through the update process. If you haven't gone into production yet then please update to v1.8.0 before you deploy it to production.
## Upgrading to v1.3.10
1. For users of our npm library, `directorySync` has been renamed to `directorySyncController`.
## Upgrading to v1.3.6
1. `samlSPConfig.get()` is now async since we introduced a global certificate instead of per tenant certificate to ease the SAML setup process.
## Upgrading to v1.3.0
1. Landed support for OpenID Identity Providers.
2. Landed new API (`/api/v1/connections`) to support setting up both SAML/OIDC SSO Connections.
**Note:** The previous API for SAML configuration `/api/v1/saml/config` has been deprecated, and would be completely removed in a future release.
3. Renamed env variable `PRE_LOADED_CONFIG` to [`PRE_LOADED_CONNECTION`](deploy/env-variables.md#pre_loaded_connection) for Jackson service. In the case of npm `preLoadedConfig` becomes`preLoadedConnection`.
4. Make sure to set the value for [`oidcPath`](deploy/env-variables.md#oidc_path) in case you are using the npm.
## Backups
Please remember to take backups before upgrading Jackson. We cannot stress how important this step is, although we take precautions to avoid bugs they sometimes do slip by us. Having backups will not only help you recover from these rare events but should be part of your disaster recovery process. If you need any help with this please do not hesitate to reach out to us.

View File

@ -1,64 +0,0 @@
# Automated Audit Events
When an end customer uses a Viewer or Enterprise token to view logs directly from the Retraced API, Retraced will record the read event in your audit log.
You can configure these events with the optional `view_log_action` parameter when you create a new Viewer or Enterprise token through the Publisher API. The default action is "audit.log.view". Viewer tokens also require an `actor_id` parameter at creation time, while Enterprise token audit events generate an `actor.id` from the token.
## Viewer Example
Suppose a viewer token was created with `group_id=example.com`, `actor_id=user@example.com` and `action=viwer.view_logs`. When the token is used, an event like this will be inserted into your audit log:
```json
{
"action": "viewer.view_logs",
"crud": "r",
"actor": {
"id": "user@example.com"
},
"group": {
"id": "example.com"
},
"description": "GET http://localhost:3000/auditlog/viewer/v1/graphql",
"source_ip": "1.1.0.180"
}
```
## Enterprise Example
An Enterprise token created with `group_id` "example.com" and no `view_log_action` would generate an event similar to this when used:
```json
{
"action": "audit.log.view",
"crud": "r",
"actor": {
"id": "enterprise:1234567"
},
"group": {
"id": "example.com"
},
"description": "GET http://localhost:3000/auditlog/enterprise/v1/graphql",
"source_ip": "1.1.0.180"
}
```
## Viewer Enterprise Token Self-Management
Another instance where Viewers can perform actions bypassing your API is when creating, retrieiving, updating, or deleting their own Enterprise tokens. Retraced will add these events to your audit log on your behalf. Note that Retraced does not insert audit events when Enterprise tokens are managed through the Publisher API, since you have the option of sending your own audit events for these actions.
An example of an event logged when a Viewer creates their own Enterpise token is:
```json
{
"action": "eitapi_token.create",
"crud": "c",
"actor": {
"id": "user@example.com"
},
"group": {
"id": "example.com"
},
"description": "POST http://localhost:3000/auditlog/viewer/v1/project/02211171900c4172b4a80d23855961c5/eitapi_token",
"source_ip": "1.1.0.180"
}
```

View File

@ -1,86 +0,0 @@
# Display Templates
Display templates is an important part of controlling how the events are rendered in the browser, exports or over any other stream.
A display template has the following components:
## Definitions
### Name
The name is internal only to the admin site. This is a place for you to record what the template is attempting to do.
### Rules
The rules field is a collection of rules that will be evaluated by the Retraced rules engine to determine if this template shoud be applied to the event. We'll cover that in detail shortly. But the idea is that you can have multiple rules, and the first one that matches will control how the event is rendered.
### Template
A handlebars-enabled, markdown rendered display template to use when the rules evaluate to true for a particular event. This ultimately is the text that you want to show for the matching events.
## Rules
Rules are processed against the event object. The best example is with actual data: you can click the Raw object in the admin site and see any actual event object. This is the exact context that is sent into the rule engine.
Rules are expressed as an array of comparators. When the _value_ of the _path_ matches the _comparator_, the rule evaluates to true and the template is applied. Retraced supports a large number of comparators, a [full list of comparators is available](/docs/retraced/advanced/template-comparators).
### Examples
This rule matches when the `action` is set to the string "document.edit":
```json
[
{
"comparator": "is",
"path": "action",
"value": "document.edit"
}
]
```
This rule matches when the `action` is set to the string "document.edit" AND the type of the document is set to "spreadsheet":
```json
[
{
"comparator": "is",
"path": "action",
"value": "document.edit"
},
{
"comparator": "is",
"path": "target.type",
"value": "spreadsheet"
}
]
```
## Templates
Templates are a handlebars string that will be used to display the event. The context of the handlebars engine is the event object, and the output is a markdown string.
### Examples
Partial Event:
```json
{
"action": "document.create",
"actor": {
"name": "Dr. Evil"
},
"target": {
"type": "spreadsheet",
"name": "Master Plan For World Domination.xlsx"
}
}
```
Template:
```
**{{ actor.name }}** created the document **{{ target.name }}**
```
Result:
**Dr. Evil** created the document **Master Plan For World Domination**

View File

@ -1,14 +0,0 @@
---
title: Retraced Advanced Concepts
sidebar_label: Overview
---
# Advanced Concepts
Once you've started sending events into Retraced, it's time to explore some of the advanced functionality.
- [Display templates](/docs/retraced/advanced/display-templates)
- [Template Comparators](/docs/retraced/advanced/template-comparators)
<!-- - [SSH Event Streaming](/docs/retraced/advanced/ssh-streaming) -->
- [Tracking Application Versions](/docs/retraced/advanced/tracking-application-versions)
- [Automated Audit Events](/docs/retraced/advanced/automated-audit-events)

View File

@ -1,31 +0,0 @@
# SSH Event Streaming
SSH Event Streaming allows Enterprise API users to stream events as they occur over ssh using an Enterprise API Token.
## Usage
To use the SSH event streaming feature, you'll need to start by getting an
[Enterprise API token](/docs/retraced/apis/enterprise-api#getting-an-enterprise-api-token).
To open a stream, connect to `tail.retraced.io` using your Enterprise API token as
the username:
```
ssh aeb1c315b9a8ed11a3f998d8e8ff@tail.retraced.io
```
Once the connection is open, CSV events will begin to stream through stdout,
and can be piped to a file or other event ingest system.
The same token can be used for multiple concurrent streaming sessions, all sessions
will receive every event that occurs while they are active.
## Parameters
The streaming APIs support a few parameters that can control the format of events.
The default output format is CSV, but JSON is also supported via the
`format` parameter
```sh
ssh aeb1c315b9a8ed11a3f998d8e8ff?format=json@tail.retraced.io
```

View File

@ -1,19 +0,0 @@
# Template Comparators
The following values are acceptable for "comparator" field in rules in the Retraced rules engine:
| Comparator | Desscription |
| --- | --- |
| `eq` | Matches when the `value` is equal to the event object data at `path`. This compares values only and doesn't compare types. |
| `is` | The same as `eq` but it also compares types of objects. |
| `neq` | Matches when the `value` is not equal to the event object data at `path`. This compares values only and doesn't compare types. This is the inverse of `eq`. |
| `not` | The same as `neq` but it also compares types of objects. This is the inverse of `is`. |
| `lt` | Matches when the `value` is less than the event object data at `path`. |
| `lte` | Matches when the `value` is less than or equal to the event object data at `path`. |
| `gt` | Matches when the `value` is greater than the event object data at `path`. |
| `gte` | Matches when the `value` is greater than or equal to the event object data at `path`. |
| `exists` | Matches when the `value` key exists and is not null on the event object data. |
| `nexists` | Matches when the `value` key does not exists or is null on the event object data. |
| `contains` | Matches when the event object data at `path` contains `value`. |
| `ncontains` | Matches when the event object data at `path` does not contain `value`. |
| `matches` | This rule is a raw regex rule. When the `value` is interpreted as a regular expression and applied to the event object data at `path`, returns the regex match value. |

View File

@ -1,89 +0,0 @@
# Tracking Event Publisher Versions
When sending events to Retraced, consumers of the [Publisher API](/docs/retraced/apis/publisher-api)
may send event metadata like the name and version of the vendor component that is
sending the events. A minimal event payload that includes this metadata might look like
```json
{
"action": "user.login",
"crud": "c",
"group": {
"id": "7890123",
"name": "some.customer"
},
"actor": {
"id": "123456",
"name": "user@example.com"
},
"component": "authentication-api",
"version": "ae242df"
}
```
Where `component` describes a single versioned piece of a architecture like `authentication-api`
or `spreadsheet-processor` and `version` is usually one of
- A git SHA of the component's source code as in `ae242df`
- A semantic version for the component as in `1.0.3`
- A build number of the component as in `129`
Sending this information to Retraced will allow Retraced to give better
guarantees about time windows during which an event **did not** occur.
## Example
To better understand how this works, consider the following stream of events,
in which the `password.change` action at 12:35 is the very first `password.change`
event seen in Retraced, because a recent new release of the vendor app is the first
to start tracking `password.change` events.
| action | received |
| ----------------- | ------------------- |
| `email.change` | 2017-01-01 11:14:00 |
| `user.login` | 2017-01-01 11:30:00 |
| `email.change` | 2017-01-01 12:01:00 |
| `user.login` | 2017-01-01 12:12:00 |
| `password.change` | 2017-01-01 12:35:00 |
| `user.login` | 2017-01-01 12:49:00 |
| `password.change` | 2017-01-01 12:52:00 |
Without any info about app versions, we can still say for certain that
- no `password.change` events occured between 12:35 and 12:52.
We cannot say anything about whether or not any `password.change` events
occurred before 12:35, because we have to assume that the vendor application
was not publishing these events until we see the first one at 12:35.
| action | received | component | version |
| ----------------- | ------------------- | -------------------- | --------- |
| `email.change` | 2017-01-01 11:14:00 | `authentication-api` | `aeb22f1` |
| `user.login` | 2017-01-01 11:30:00 | `authentication-api` | `aeb22f1` |
| `email.change` | 2017-01-01 12:01:00 | `authentication-api` | `fd02eed` |
| `user.login` | 2017-01-01 12:12:00 | `authentication-api` | `fd02eed` |
| `password.change` | 2017-01-01 12:35:00 | `authentication-api` | `fd02eed` |
| `user.login` | 2017-01-01 12:49:00 | `authentication-api` | `fd02eed` |
| `password.change` | 2017-01-01 12:52:00 | `authentication-api` | `493ef1d` |
Since we know the version of the component sending each event, we can know for sure
that the app version that sends `password.change` events was sending `email.change` events as
early as 12:01. In addition to what we knew before, that
- no `password.change` events occured between 12:35 and 12:52
we now can also guarantee that
- no `password.change` events occurred between 12:01 and 12:35.
Note: Being able to make these guarantees relies on an assumption that application
versions change at the same time, and that there are never multiple versions of
a single component running in parallel for significant periods of time. If
Publisher API consumers rely on canary deploys or staged rollouts over several days,
then component names will need to be rotated during the rollout.
## Using SDKs
If you are using one of the official [Retraced SDKs](/docs/retraced/sdks/available-sdks),
you can provide the `version` and `component` fields when the client is initialized,
and they will be sent for every event.

View File

@ -1,17 +0,0 @@
---
title: Admin API
sidebar_label: Admin API
description: Admin API
---
# Admin API
### [Swagger JSON](http://localhost:3000/auditlog/admin/v1/swagger.json) | [API Console](https://retraced.readme.io/v1.0/reference)
## Authentication
The Admin API expects a base64-encoded hmac-signed [JSON Web Token](https://tools.ietf.org/html/rfc7519) in an `Authorization` header:
```
Authorization: WU9VUl9TSUdORURfSldUX1RPS0VOX18K...
```

View File

@ -1,32 +0,0 @@
---
title: Enterprise API
sidebar_label: Enterprise API
description: Enterprise API
---
# Enterprise API
### [Swagger JSON](http://localhost:3000/auditlog/enterprise/v1/swagger.json) | [API Console](https://retraced.readme.io/v1.0/reference)
## Overview
The Enterprise API is the API that the end customer (the enterprise IT administrator) will consume to pull their organization events and ingest it into their own internal systems.
## Authentication
The Enterprise API endpoints expect the token to be provided in a header of the form
```
Authorization: token=YOUR_ENTERPRISE_TOKEN
```
## Getting an Enterprise API Token
There are currently two ways to manage Enterprise API tokens.
- Most often, end customers create and manage Enterprise IT tokens using the UI in the [Embedded Viewer](/docs/retraced/getting-started/embedded-viewer)
- There are also endpoints in the [Publisher API](/docs/retraced/apis/publisher-api) that
allow a vendor to create, edit, and delete Enterprise API tokens
Note that to allow end customers to manage Enterprise API tokens in the embedded viewer,
the `is_admin` query parameter must be set to `true` when [requesting a token to initialize the embedded viewer](https://retraced.readme.io/reference#publisherv1projectprojectidviewertoken)

View File

@ -1,803 +0,0 @@
# GraphQL Endpoint
The recommended way to search events using an API is to POST your query and variables to the appropriate Retraced GraphQL endpoint.
| API | Endpoint |
| ---------- | ----------------------------------------------------------------------------------------------- |
| Publisher | http://localhost:3000/auditlog/publisher/v1/project/{projectId}/graphql |
| Admin | http://localhost:3000/auditlog/admin/v1/project/{projectId}/environment/{environmentId}/graphql |
| Enterprise | http://localhost:3000/auditlog/enterprise/v1/graphql |
| Viewer | http://localhost:3000/auditlog/viewer/v1/graphql |
## Search
The query root provides a search method. A fully-formed query for a subset of event fields would look like this:
```
{
search(query:"action:user.login location:Germany", last:50, before:"opaquecursor") {
totalCount
pageInfo {
hasNextPage
}
edges {
cursor
node {
action
actor {
name
}
created
country
}
}
}
}
```
### Variables
Use `query`, `last`, and `before` variables to enable reuse of your query templates. If you define a parameterized query like this...
```
const searchQuery = `query Search($query: String!, $last: Int, $before: String) {
search(query:"action:user.login location:Germany", last:50, before:"opaquecursor") {
totalCount
pageInfo {
hasNextPage
}
edges {
cursor
node {
action
actor {
name
}
created
country
}
}
}
}`;
```
... then you can execute searches like this:
```
const vars = {
query: "action:user.login location:German",
last: 50,
before: "opaquecursor",
};
const res = fetch("http://localhost:3000/auditlog/publisher/v1/project/3hf140713bn302/graphql", {
method: "POST",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"Authorization": "Token token=2ba3059ad7f14071b9befb2a7a2e195e",
},
body: JSON.stringify({
query: searchQuery,
variables: vars,
}),
});
```
# Schema Types
<details>
<summary><strong>Table of Contents</strong></summary>
- [GraphQL Endpoint](#graphql-endpoint)
- [Search](#search)
- [Variables](#variables)
- [Schema Types](#schema-types)
- [Query](#query)
- [Objects](#objects)
- [Action](#action)
- [Actor](#actor)
- [Display](#display)
- [Event](#event)
- [EventEdge](#eventedge)
- [EventsConnection](#eventsconnection)
- [Field](#field)
- [Group](#group)
- [PageInfo](#pageinfo)
- [Target](#target)
- [Enums](#enums)
- [CRUD](#crud)
- [Scalars](#scalars)
- [Boolean](#boolean)
- [ID](#id)
- [Int](#int)
- [String](#string)
- [Interfaces](#interfaces)
</details>
## Query
The root query object of the Retraced GraphQL interface.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>search</strong></td>
<td valign="top"><a href="#eventsconnection">EventsConnection</a></td>
<td>
Run an advanced search for events.
</td>
</tr>
<tr>
<td colspan="2" align="right" valign="top">query</td>
<td valign="top"><a href="#string">String</a></td>
<td>
The <a href="/docs/retraced/getting-started/searching-for-events/#structured-advanced-search">structured search operators</a> used to filter events.
</td>
</tr>
<tr>
<td colspan="2" align="right" valign="top">first</td>
<td valign="top"><a href="#int">Int</a></td>
<td>
The limit of events to return, sorted from oldest to newest. It can optionally be used with the <code>after</code> argument.
</td>
</tr>
<tr>
<td colspan="2" align="right" valign="top">after</td>
<td valign="top"><a href="#string">String</a></td>
<td>
A cursor returned from a previous query.
</td>
</tr>
<tr>
<td colspan="2" align="right" valign="top">last</td>
<td valign="top"><a href="#int">Int</a></td>
<td>
The limit of events to return, sorted from newest to oldest. It can optionally be used with the <code>before</code> argument.
</td>
</tr>
<tr>
<td colspan="2" align="right" valign="top">before</td>
<td valign="top"><a href="#string">String</a></td>
<td>
A cursor returned from a previous query.
</td>
</tr>
</tbody>
</table>
## Objects
### Action
An action.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>action</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The action field of an event such as "user.login".
</td>
</tr>
</tbody>
</table>
### Actor
The agent who performed an event.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>id</strong></td>
<td valign="top"><a href="#id">ID</a></td>
<td>
A unique id representing this actor.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>name</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The name of this actor.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>href</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The URL associated with this actor.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>fields</strong></td>
<td valign="top">[<a href="#field">Field</a>]</td>
<td>
The set of fields associated with this actor.
</td>
</tr>
</tbody>
</table>
### Display
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>markdown</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td></td>
</tr>
</tbody>
</table>
### Event
A single record in an audit log.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>id</strong></td>
<td valign="top"><a href="#id">ID</a></td>
<td>
A unique id representing this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>action</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The type of action that was taken to generate this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>description</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The description of the event that was taken.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>group</strong></td>
<td valign="top"><a href="#group">Group</a></td>
<td>
The group associated with this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>actor</strong></td>
<td valign="top"><a href="#actor">Actor</a></td>
<td>
The actor associated with this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>target</strong></td>
<td valign="top"><a href="#target">Target</a></td>
<td>
The target associated with this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>crud</strong></td>
<td valign="top"><a href="#crud">CRUD</a></td>
<td>
The classification of this event as create, read, update, or delete.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>display</strong></td>
<td valign="top"><a href="#display">Display</a></td>
<td>
The display text for this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>received</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The time that the Retraced API received this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>created</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The time that this event was reported as performed.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>canonical_time</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The created time if specified; else the received time.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>is_failure</strong></td>
<td valign="top"><a href="#boolean">Boolean</a></td>
<td>
Set to true if the event represents a failed use of permissions.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>is_anonymous</strong></td>
<td valign="top"><a href="#boolean">Boolean</a></td>
<td>
Set to true if the user was not logged in when performing this action.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>source_ip</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The IP address of the actor when the action was performed.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>country</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The country that the actor was in when the action was performed.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>loc_subdiv1</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The large area of the country the actor was in when the action was performed (State).
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>loc_subdiv2</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The granular area of the country the actor was in when the action was performed (City).
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>component</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
An identifier for the vendor app component that sent the event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>version</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
An identifier for the version of the vendor app that sent the event, usually a git SHA
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>fields</strong></td>
<td valign="top">[<a href="#field">Field</a>]</td>
<td>
The set of fields associated with this event.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>raw</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The raw event sent to the Retraced API.
</td>
</tr>
</tbody>
</table>
### EventEdge
The event and cursor for a single result.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>node</strong></td>
<td valign="top"><a href="#event">Event</a></td>
<td>
The event object.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>cursor</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
An opaque cursor for paginating from this point in the search results. Use it as the <code>after</code> argument to paginate forward or the <code>before</code> argument to paginate backward.
</td>
</tr>
</tbody>
</table>
### EventsConnection
The results of a search query.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>edges</strong></td>
<td valign="top">[<a href="#eventedge">EventEdge</a>]</td>
<td>
The events and cursors matching the query.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>pageInfo</strong></td>
<td valign="top"><a href="#pageinfo">PageInfo</a></td>
<td>
Indications that more search results are available.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>totalCount</strong></td>
<td valign="top"><a href="#int">Int</a></td>
<td>
The total number of search results matched by the query.
</td>
</tr>
</tbody>
</table>
### Field
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>key</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The key for this field.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>value</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The value for this field.
</td>
</tr>
</tbody>
</table>
### Group
The group this event is associated with.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>id</strong></td>
<td valign="top"><a href="#id">ID</a></td>
<td>
A unique id representing this group.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>name</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The name of this group.
</td>
</tr>
</tbody>
</table>
### PageInfo
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>hasNextPage</strong></td>
<td valign="top"><a href="#boolean">Boolean</a></td>
<td>
When paging forward with <code>first</code>, indicates more results are available.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>hasPreviousPage</strong></td>
<td valign="top"><a href="#boolean">Boolean</a></td>
<td>
When paging backward with <code>last</code>, indicates more results are available.
</td>
</tr>
</tbody>
</table>
### Target
The object an event is performed on.
<table>
<thead>
<tr>
<th align="left">Field</th>
<th align="right">Argument</th>
<th align="left">Type</th>
<th align="left">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="2" valign="top"><strong>id</strong></td>
<td valign="top"><a href="#id">ID</a></td>
<td>
A unique id representing this target.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>name</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The name of this target.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>href</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The URL associated with this target.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>type</strong></td>
<td valign="top"><a href="#string">String</a></td>
<td>
The type of this target entity.
</td>
</tr>
<tr>
<td colspan="2" valign="top"><strong>fields</strong></td>
<td valign="top">[<a href="#field">Field</a>]</td>
<td>
The set of fields associated with this target.
</td>
</tr>
</tbody>
</table>
## Enums
### CRUD
Create | Read | Update | Delete
<table>
<thead>
<th align="left">Value</th>
<th align="left">Description</th>
</thead>
<tbody>
<tr>
<td valign="top"><strong>c</strong></td>
<td>
create
</td>
</tr>
<tr>
<td valign="top"><strong>r</strong></td>
<td>
read
</td>
</tr>
<tr>
<td valign="top"><strong>u</strong></td>
<td>
update
</td>
</tr>
<tr>
<td valign="top"><strong>d</strong></td>
<td>
delete
</td>
</tr>
</tbody>
</table>
## Scalars
### Boolean
The `Boolean` scalar type represents `true` or `false`.
### ID
The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.
### Int
The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
### String
The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.
## Interfaces

View File

@ -1,289 +0,0 @@
# API Documentation
Retraced API
## Version: 1.4.6
**License:** UNLICENSED
### /enterprise/v1/graphql
#### POST
##### Description:
Query events with [GraphQL](/docs/retraced/apis/admin-api)
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form Token token= ... | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 200 | OK |
null
### /enterprise/v1/search/active
#### POST
##### Description:
Initiate an active search. An active search will maintain
a persistent cursor that can be used at a later date to
retrieve additional events from the search.
Authenticate with an Enterprise API token.
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | header of the form token= ... | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 201 | Created |
null
### /enterprise/v1/search/saved
#### POST
##### Description:
Create a saved search.
Saved searches have an ID that can be used to initiate an active search.
Authenticate with an Enterprise API token.
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | header of the form token= ... | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 201 | Created |
null
### /publisher/v1/project/{projectId}/event
#### POST
##### Description:
Create an event. Returns the id of the created event, and
a cryptographic hash of the received event, as described [here](/docs/retraced/architecture/hashing-formula/).
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 201 | Created |
null
### /publisher/v1/project/{projectId}/event/bulk
#### POST
##### Description:
Create one or more events. Returns a list of the ids of the created event and
a cryptographic hash of each received events, as described [here](/docs/retraced/architecture/hashing-formula/).
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 201 | Created |
null
### /publisher/v1/project/{projectId}/viewertoken
#### GET
##### Description:
Create a token for use with the Retraced embedded viewer as described [here](/docs/retraced/getting-started/embedded-viewer/).
**Note**: At least one of `group_id` or `team_id` is required.
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
| actor_id | query | | Yes | string |
| group_id | query | The group identifier. Same as `team_id`. If both are passed, `group_id` will be used. | No | string |
| is_admin | query | Whether to display the Enterprise Settings and API Token Management. Set to `true` to show the settings. | No | string |
| target_id | query | If passed, only events relating to this target will be returned in a viewer that uses the token created | No | string |
| team_id | query | Same as `group_id`. If both are passed, `group_id` will be used. This field is deprecated. | No | string |
| view_log_action | query | The action that will be logged when the token is used | No | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 201 | Created |
null
### /publisher/v1/project/{projectId}/group/{groupId}/enterprisetoken
#### POST
##### Description:
Create a token for use with [Enterprise IT API](/docs/retraced/apis/enterprise-api/
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
| groupId | path | The group identifier. The generated token will be scoped to the specified group. | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 201 | Created |
null
#### GET
##### Description:
List all [Enterprise IT API](/docs/retraced/apis/enterprise-api/) tokens.
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
| groupId | path | The group identifier. | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 200 | OK |
null
### /publisher/v1/project/{projectId}/group/{groupId}/enterprisetoken/{tokenId}
#### GET
##### Description:
Retrieve an [Enterprise IT API](/docs/retraced/apis/enterprise-api/) token.
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | The project id. | Yes | string |
| groupId | path | The group identifier. | Yes | string |
| tokenId | path | The token id. | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 200 | OK |
null
#### PUT
##### Description:
Update an [Enterprise IT API](/docs/retraced/apis/enterprise-api/) token
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
| groupId | path | The group identifier. | Yes | string |
| tokenId | path | The token to update. | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 200 | OK |
null
#### DELETE
##### Description:
Delete an [Enterprise IT API](/docs/retraced/apis/enterprise-api/) token
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
| groupId | path | The group identifier. | Yes | string |
| tokenId | path | The token to delete. | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 204 | Deleted |
null
### /publisher/v1/project/{projectId}/graphql
#### POST
##### Description:
Query events with [GraphQL](/docs/retraced/apis/graphql/)
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| Authorization | header | auth header of the form Token token= ... | Yes | string |
| projectId | path | the project id | Yes | string |
##### Responses
| Code | Description |
| ---- | ----------- |
| 200 | OK |
null

View File

@ -1,19 +0,0 @@
# Retraced APIs Overview
Retraced provides several APIs:
## Publisher API
the [Publisher API](/docs/retraced/apis/publisher-api) is the primary API that an application vendor will use to send events into Retraced. This is the API that the [Retraced SDKs](/docs/retraced/sdks/available-sdks) consume. When getting started, this is the first place to start. Use the Publisher API to start sending events into Retraced.
## Enterprise API
The [Enterprise API](/docs/retraced/apis/enterprise-api) is the API that the end customer (the enterprise IT administrator) will consume to pull their organization events and ingest it into their own internal systems.
## Admin API
The [Admin API](/docs/retraced/apis/admin-api) is an optional API that can be used in place of the Retraced Admin site. The Retraced Admin site uses this API. It's useful to managing your account and API tokens and pulling reports.
## Swagger Documentation
### [Retraced API Console](https://retraced.readme.io) | [Publisher API Swagger JSON](http://localhost:3000/auditlog/publisher/v1/swagger.json) | [Enterprise API Swagger JSON](http://localhost:3000/auditlog/enterprise/v1/swagger.json) | [Admin API Swagger JSON](http://localhost:3000/auditlog/admin/v1/swagger.json)

View File

@ -1,65 +0,0 @@
---
title: Publisher API
sidebar_label: Publisher API
description: Publisher API
---
# Publisher API
### [Swagger JSON](http://localhost:3000/auditlog/publisher/v1/swagger.json) | [API Console](https://retraced.readme.io/v1.0/reference)
The Publisher API is the API that most applications will embed into a production system. This API contains the methods necessary to send new events into Retraced, create [viewer tokens](/docs/retraced/getting-started/embedded-viewer) and to programmatically search events when the embedded viewer is not being used.
When possible, it's recommended to use one of the supported [SDKs](/docs/retraced/sdks/available-sdks) as these provide an easier way to get started.
To consume the Publisher API directly, we publish a Swagger spec that is both [documented](https://retraced.readme.io/reference) and available in a [raw json object](http://localhost:3000/auditlog/publisher/v1/swagger.json).
The endpoints for reporting events are `/project/{project_id}/event` and `/project/{project_id}/event/bulk`. The bulk endpoint is for reporting multiple events in a single call. Clients using the bulk endpoint should expect longer response times when submitting large numbers of events.
## Body
We send an event json to `/project/{project_id}/event` API.
Following are the `mandatory` fields.
```json
{
"action": "action-name",
"crud": "c" | "r" | "u" | "d",
"actor": {
"id": "actor-id",
"name": "actor-name"
}
```
In case of `/project/{project_id}/event/bulk` API we will send an array of events like below,
```json
{
"events": [
{
"action": "action-name",
"crud": "c" | "r" | "u" | "d",
"actor": {
"id": "actor-id",
"name": "actor-name"
},
},
{
"action": "action-name",
"crud": "c" | "r" | "u" | "d",
"actor": {
"id": "actor-id",
"name": "actor-name"
}
}
]
}
```
## Authentication
The Publisher API endpoints expect the token to be provided in a header of the form
```
Authorization: token=YOUR_PUBLISHER_TOKEN
```

View File

@ -1,117 +0,0 @@
# Hashing Formula
When both the sender and the receiver of a message independently calculate a digest of the message, it's a proven way to ensure that both sides have the same content. But both sides needs to have a reference that describes how to calculate the digest. This document describes the specification that the Retraced API uses to calculate a message digest.
To calculate the digest, Retraced will build a colon (:) delimited string of all the fields, and then calculate a SHA256 digest. Empty or missing fields are not ignored, but are included in the digest as empty strings. Individual fields are percent-escaped before being added to the string.
The order of the fields is important, and is defined as:
1. `event_id`: The string ID that is returned from the Retraced API when calling create event.
1. `action`: The [action](/docs/retraced/how-to-audit-log/actions/) parameter provided when creating an event.
1. `target_id`: The ID of the [target](/docs/retraced/how-to-audit-log/targets/) parameter provided when creating an event. If no target was provided, this is an empty string.
1. `actor_id`: The ID of the [actor](/docs/retraced/how-to-audit-log/actors/) parameter provided when creating an event. If no actor was provided, this is an empty string.
1. `group_id`: The ID of the [group]/(/docs/retraced/architecture/groups/) parameter provided when creating an event. If no group was provided, this is an empty string.
1. `source_ip`: The IP address sent with the event. If no IP address was known, this is an empty string.
1. `is_failure`: An integer ("1" or "0") representation of the is_failure parameter provided when creating an event. This is required, and will default to "0".
1. `is_anonymous`: An integer ("1" or "0") representation of the is_anonymous parameter provided when creating an event. This is required, and will default to "0".
1. `fields`: A semicolon (`;`) separated list of the field=value parameters provided in the event. The fields are sorted alphabetically by the key name before encoding. A trailing `;` is included, if there are fields. If there are no fields, a single colon (`:`) should be appended in place of the fields list.
## Examples
### Simple Event
Given the following login audit event:
```json
{
"action": "user.login",
"group": {
"id": "group-id",
"name": "group-name"
},
"created": "2017-01-01T00:00:00.000000000Z",
"crud": "c",
"description": "User \"someone@someplace.com\" logged in",
"source_ip": "8.8.8.8",
"actor": {
"id": "actor-id",
"name": "actor-name",
"type": "user",
"url": "https://my.site.com/account/actor-id"
},
"is_failure": false,
"is_anonymous": false
}
```
A string is built with the fields, as described above:
```
event-id:user.login::actor-id:group-id:8.8.8.8:0:0:
```
Finally, a SHA256 digest of the above string returns:
```
1ee7c214a6bc2ab3e4f921b7c98a148357eebb56081fd68d88bd25acdec45332
```
### With Fields
Given the following audit event:
```json
{
"action": "document.share",
"group": {
"id": "group-id",
"name": "group-name"
},
"created": "2017-01-01T00:00:00.000000000Z",
"crud": "u",
"target": {
"id": "target-id",
"name": "document-name",
"type": "document",
"url": ""
},
"description": "Shared document with \"another@user.com\"",
"source_ip": "8.8.8.8",
"actor": {
"id": "actor-id",
"name": "a@user.com",
"type": "user",
"url": "https://my.site.com/account/actor-id"
},
"fields": {
"resulting_permission": "view,edit",
"permission_granted": "view"
},
"is_failure": false,
"is_anonymous": false
}
```
A string is built with the fields, as described above:
```
event-id:document.share:target-id:actor-id:group-id:8.8.8.8:0:0:permission_granted=view;resulting_permission=view,edit;
```
Finally, a SHA256 digest of the above string returns:
```
e3412f11c1ed3b592d5333441880373ede3b774bc62914ed9317d3affaec9048
```
### Escaping Hash Parameters
Any values used for hashing should have the following replacements applied:
1. `%` -- any percent symbols (`%`) should be converted to `%25`
1. `:` -- any colons (`:`) should be converted to `%3A`
Further, any values in the `fields` section should also have the following escapes applied in a second pass:
1. `=` -- any equals signs (`=`) should be converted to `%3D`
1. `;` -- any semicolons (`;`) should be converted to `%3B`

View File

@ -1,15 +0,0 @@
# Immutability Guarantee
When you send audit events into Retraced, we offer functionality that guarantees the data you sent is the data that was received. We use the same functionality to allow you to, at any time, cryptographically verify that the events have not changed since they were written and no events have been removed.
## Digest of Events
When an event is received by the Retraced API, the methods that receives the event will always synchronously compute a digest hash of the data received, using our publicly documented [hashing formula](/docs/retraced/architecture/hashing-formula). The computed digest is returned, along with the rest of the standard response. It's up to the sender to independently calculate the digest of the event and compare it to the response from the Retraced API. If these digests do not match, the event was not properly decoded or received by the Retraced API.
When using any of the [official Retraced SDKs](/docs/retraced/sdks/available-sdks), this computation and comparison happens automatically. All of our SDKs are open source, and this can be independently verified by examining the relevant source code of the SDK.
## Future Verification of Immutability
When validating immutability for audit events, it's important to both verify that the events have not changed, and to verify that no events were added or deleted. Retraced provides functionality for both of these verifications.
Audited events are not always displayed with every field originally sent. Also, it's possible for an [actor or item to be renamed](/docs/retraced/getting-started/renaming-properties) at some point in the future. Retraced will always store the original event received, and it's possible to retrieve that source. In fact, this source is used to dynamically calculate value to show when displaying an event in the browser or other source.

View File

@ -1,16 +0,0 @@
---
title: Retraced Architecture
sidebar_label: Overview
---
# Overview
Retraced is more than a traditional database to store and retrieve objects. The "Architecture" documentation provides an overview of some of the features that Retraced provides to provide immutability and verifiability of your audit log data.
![Audit logs Architecture](/img/audit-logs/audit-logs-architecture.png)
## Cryptographically Guarantee Immutability
Retraced implements industry standard and provable digest algorithms to ensure the data you send into an audit log is the data that was received. The same algorithms can be used in the future to verify that none of the data has changed since it was written. This works automatically when using our [SDKs](/docs/retraced/sdks/available-sdks), and can be implemented manually if you use the API directly.
Details of how we guarantee immutability are discussed in detail on the [immutability guarantee](/docs/retraced/architecture/immutability-guarantee) page.

View File

@ -1,21 +0,0 @@
# Container Signing and Verification for Retraced
Retraced container images are signed and can be verified using [cosign](https://github.com/sigstore/cosign).
## Fetching our public key
You can use [oras](https://oras.land/docs/category/cli) (or a similar OCI artifacts tool) to fetch our public key or download it from our website [here](https://boxyhq.com/.well-known/cosign.pub).
```bash
oras pull ghcr.io/boxyhq/cosign.pub:latest
```
## Container verification
**Note:** This is supported for all versions >=1.5.0
Our container images are hosted on [Docker Hub](https://hub.docker.com/r/retracedhq/retraced/tags). You can verify it by using the following command.
```bash
cosign verify --key cosign.pub retracedhq/retraced:<version>
```

View File

@ -1,163 +0,0 @@
# Using The Enterprise API
The Retraced Enterprise API enables users to consume audit log data programmatically and integrate it with an external monitoring or security system.
## Creating and Managing Enterprise Tokens
Enterprise Tokens can be created and managed via the [Embedded Viewer](/docs/retraced/exposing-retraced-data/viewer/)
**Note**: If you're a vendor integrating Retraced as your audit log, you can also manage and distribute Enterprise Tokens using the [Publisher API](/docs/retraced/apis/publisher-api/).
## Graphql
The quickest way to start getting events is using the GraphQL API. Below is an example request:
```sh
curl -sSL 'http://localhost:3000/auditlog/enterprise/v1/graphql' \
-H 'Authorization: token=<YOUR_ENTERPRISE_TOKEN>' \
-H 'Content-Type: application/json' \
--data-binary '{
"variables": {
"before": "",
"last": 3,
"query": "action:document.edit received:2017-11-01,2017-12-01"
},
"query": "query Search($query: String!, $last: Int, $before: String) { search(query: $query, last: $last, before: $before) { totalCount pageInfo { hasPreviousPage } edges { cursor node { id action crud created actor { name }}}}}"
}'
```
There are five things to pay attention to here:
- We send our Enterpise API Token in a header of the form `Authorization: token=...`
- `variables.last` is the number of events we're requesting, in this case we only want the last 3 events
- `variables.query` is a free-text or structured search query, as you'd use in [The Embedded Viewer](/docs/retraced/exposing-retraced-data/viewer/#search).
- `variables.before` allows us to specify a cursor for paging through events. Since we just want the most recent events, we'll leave this blank for now.
- In the `query` field, we describe the structure and parameters of the GraphQL query.
The response will look something like
```json
{
"data": {
"search": {
"edges": [
{
"cursor": "MTUxMDg3MjgwNzAxMyxmMzc4MDNkZDdlOTY0NmUzYTRkZjQyZjdiNGUzOWRjMQ==",
"node": {
"action": "license.update",
"actor": {
"name": "customertowne+xyz@mycompany.com"
},
"created": "2017-11-16T22:53:27Z",
"crud": "u",
"id": "f37803dd7e9646e3a4df42f7b4e39dc1"
}
},
{
"cursor": "MTUxMDg3Mjc5ODUyNiwyZWFiYzA2NDI5NTc0YWEzOWNmNmI4MWYxNTQ1NzFlMQ==",
"node": {
"action": "license.update",
"actor": {
"name": "jane.smith@company.com"
},
"created": "2017-11-16T22:53:18Z",
"crud": "u",
"id": "2eabc06429574aa39cf6b81f154571e1"
}
},
{
"cursor": "MTUxMDg2Nzc3MzMxNiw5Y2M2NTM3ZGRjZTk0ZGEyODI0NTA4ZTc4M2EzOGRjNQ==",
"node": {
"action": "application.branding.update",
"actor": {
"name": "john.doe@company.com"
},
"created": "2017-11-16T21:29:33Z",
"crud": "u",
"id": "9cc6537ddce94da2824508e783a38dc5"
}
}
],
"pageInfo": {
"hasPreviousPage": true
},
"totalCount": 2411
}
}
}
```
The query itself is in the `query` field of the json body:
```
query Search($query: String!, $last: Int, $before: String) { search(query: $query, last: $last, before: $before) { totalCount pageInfo { hasPreviousPage } edges { cursor node { id action crud created actor { name }}}}}
```
The same query is expanded below for readability. In general use, the first few lines won't change for every request, the interesting part is under `node`, where you're able to select which fields you'd like to receive.
```
query Search($query: String!, $last: Int, $before: String) {
search(query: $query, last: $last, before: $before) {
totalCount
pageInfo {
hasPreviousPage
}
edges {
cursor
node {
id
action
crud
created
actor {
name
}
}
}
}
}
```
This example only requests a few event fields: `id`, `action`, `crud`, `created`, and `actor.name`, but there are many other fields available, as described in the [Event Schema](/docs/retraced/apis/graphql/#event).
The GraphQL APIs for consuming events are specified fully in [GraphQL API Guide](/docs/retraced/apis/graphql/). There are example queries and usage in the [Go SDK](https://github.com/retracedhq/retraced-go/blob/master/graphql.go#L216) and the [Javascript SDK](https://github.com/retracedhq/retraced-js/blob/master/src/graphql.ts#L334)
<!-- ## SSH Event Stream
You can also use your Enterprise API Token to stream events over SSH in real time. You can use your token as the username, and ssh `tail.retraced.io`:
```sh
$ ssh <YOUR_ENTERPRISE_TOKEN>@tail.retraced.io
PTY allocation request failed on channel 0
584fad6b2a204326857c9eef7704d31f,,1510939272892,POST /viewer/v1/graphql,35.186.223.140,audit.log.view,r,"{""action"":""audit.log.view"",""crud"":""r"",""actor"":{""id"":""27c92eb3f5ce849b9866edd12f8fdef8""},""group"":{""id"":""1ff0ab86bcb8f9fcd67936db08b80600""},""description"":""POST /viewer/v1/graphql"",""source_ip"":""35.186.223.140""}",1ff0ab86bcb8f9fcd67936db08b80600,51e79795f89b4454a883a3a49d03d6ea,7a691d01114a494ba9d77eb302edce6a,BoxyHQ QA,16132,1494456302651,1510939272911,27c92eb3f5ce849b9866edd12f8fdef8,dexter+qa@boxyhq.com,51e79795f89b4454a883a3a49d03d6ea,7a691d01114a494ba9d77eb302edce6a,,1498682746392,1498682746393,1510939272927,,,,,,,,,
20e3371bb3ab4b7c8e0dfdda4b86de11,,1510939274311,POST /viewer/v1/graphql,35.186.223.140,audit.log.view,r,"{""action"":""audit.log.view"",""crud"":""r"",""actor"":{""id"":""27c92eb3f5ce849b9866edd12f8fdef8""},""group"":{""id"":""1ff0ab86bcb8f9fcd67936db08b80600""},""description"":""POST /viewer/v1/graphql"",""source_ip"":""35.186.223.140""}",1ff0ab86bcb8f9fcd67936db08b80600,51e79795f89b4454a883a3a49d03d6ea,7a691d01114a494ba9d77eb302edce6a,BoxyHQ QA,16133,1494456302651,1510939274324,27c92eb3f5ce849b9866edd12f8fdef8,dexter+qa@boxyhq.com,51e79795f89b4454a883a3a49d03d6ea,7a691d01114a494ba9d77eb302edce6a,,1498682746392,1498682746393,1510939274334,,,,,,,,,
```
The default format is csv, but JSON is also available, by appending `?format=json` to the token:
```sh
$ ssh f66bfe98f22648ae94b08c6c38e9ba7f?format=json@tail.retraced.io
PTY allocation request failed on channel 0
{"action":"audit.log.view","actor":{"created":1498682746392,"environment_id":"7a691d01114a494ba9d77eb302edce6a","first_active":1498682746393,"id":"27c92eb3f5ce849b9866edd12f8fdef8","last_active":1510939425326,"name":"dexter+qa@boxyhq.com","project_id":"51e79795f89b4454a883a3a49d03d6ea"},"crud":"r","description":"POST /viewer/v1/graphql","group":{"created_at":1494456302651,"environment_id":"7a691d01114a494ba9d77eb302edce6a","event_count":"16134","id":"1ff0ab86bcb8f9fcd67936db08b80600","last_active":1510939425315,"name":"BoxyHQ QA","project_id":"51e79795f89b4454a883a3a49d03d6ea"},"id":"8d14443a55dc4b7d87939917019a520d","raw":"{\"action\":\"audit.log.view\",\"crud\":\"r\",\"actor\":{\"id\":\"27c92eb3f5ce849b9866edd12f8fdef8\"},\"group\":{\"id\":\"1ff0ab86bcb8f9fcd67936db08b80600\"},\"description\":\"POST /viewer/v1/graphql\",\"source_ip\":\"35.186.223.140\"}","received":1510939425299,"source_ip":"35.186.223.140","target":{}}
```
Events will continue to appear as long as the ssh session is open. These events can now be piped to a file, or to any other program to ingest them into your monitoring or security systems.
**Note**: SSH Streaming may not be available in all Retraced environments.
For more information, check out [SSH Streaming](/docs/retraced/advanced/ssh-streaming/). -->
## Saved Searches
The Enterprise API includes several endpoints for saving a search and maintaining a persistent cursor across search queries.
The general workflow is:
- Create a "Saved Search" with desired query parameters
- Create an "Active Search" from the saved search's ID
- Use the "Pump Active Search" endpoint whenever you want to get more events from your search.
- Pump active search will always return only the events that occurred since the last time it was queried, so it can be called as often as every few seconds, or as infrequently as every few months
**Note**: Saved Search functionality may not be available in all Retraced environments.
The endpoints for managing Saved Searches are described in the [Enterprise API Guide](/docs/retraced/apis/enterprise-api/). There's also an [OpenAPI/Swagger specification](http://localhost:3000/auditlog/enterprise/v1/swagger.json) and [interactive API console](https://retraced.readme.io/reference#searchactive).

Some files were not shown because too many files have changed in this diff Show More