diff --git a/pr-preview/pr-921/404.html b/pr-preview/pr-921/404.html new file mode 100644 index 000000000..8852ef1c0 --- /dev/null +++ b/pr-preview/pr-921/404.html @@ -0,0 +1,23 @@ + + + + + +Page Not Found | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

404: Page Not Found

If you navigated here from a broken link on the OpenFGA website, please open an issue on GitHub.

Otherwise, try navigating to the home page, and then find or search for the content you need from there.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/api/index.html b/pr-preview/pr-921/api/index.html new file mode 100644 index 000000000..d7857b59c --- /dev/null +++ b/pr-preview/pr-921/api/index.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/api/service.html b/pr-preview/pr-921/api/service.html new file mode 100644 index 000000000..6c95b4975 --- /dev/null +++ b/pr-preview/pr-921/api/service.html @@ -0,0 +1,23 @@ + + + + + +Open FGA API Explorer | OpenFGA + + + + + + + + + + + + + + +
Skip to main content
Loading...
+ + \ No newline at end of file diff --git a/pr-preview/pr-921/api/service.html.html b/pr-preview/pr-921/api/service.html.html new file mode 100644 index 000000000..d7857b59c --- /dev/null +++ b/pr-preview/pr-921/api/service.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/css/styles.91f1981e.css b/pr-preview/pr-921/assets/css/styles.91f1981e.css new file mode 100644 index 000000000..19fe3371c --- /dev/null +++ b/pr-preview/pr-921/assets/css/styles.91f1981e.css @@ -0,0 +1 @@ +.col,.container{padding:0 var(--ifm-spacing-horizontal);width:100%}.markdown>h2,.markdown>h3,.markdown>h4,.markdown>h5,.markdown>h6{margin-bottom:calc(var(--ifm-heading-vertical-rhythm-bottom)*var(--ifm-leading))}body,ol ol,ol ul,ul ol,ul ul{margin:0}pre,table{overflow:auto}blockquote,pre{margin:0 0 var(--ifm-spacing-vertical)}.breadcrumbs__link,.button{transition-timing-function:var(--ifm-transition-timing-default)}.button,code{vertical-align:middle}.button--outline.button--active,.button--outline:active,.button--outline:hover,:root{--ifm-button-color:var(--ifm-font-color-base-inverse)}.menu__link:hover,a{transition:color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.navbar--dark,:root{--ifm-navbar-link-hover-color:var(--ifm-color-primary)}.menu,.navbar-sidebar{overflow-x:hidden}:root,html[data-theme=dark]{--ifm-color-emphasis-500:var(--ifm-color-gray-500)}.menu__list-item-collapsible a,.theme-doc-markdown h1{font-family:var(--ofga-font-highlight)}.toggleButton_gllP,html{-webkit-tap-highlight-color:transparent}*,.loadingRing_RJI3 div,.swagger-ui .border-box,.swagger-ui a,.swagger-ui article,.swagger-ui body,.swagger-ui code,.swagger-ui dd,.swagger-ui div,.swagger-ui dl,.swagger-ui dt,.swagger-ui fieldset,.swagger-ui footer,.swagger-ui form,.swagger-ui h1,.swagger-ui h2,.swagger-ui h3,.swagger-ui h4,.swagger-ui h5,.swagger-ui h6,.swagger-ui header,.swagger-ui html,.swagger-ui input[type=email],.swagger-ui input[type=number],.swagger-ui input[type=password],.swagger-ui input[type=tel],.swagger-ui input[type=text],.swagger-ui input[type=url],.swagger-ui legend,.swagger-ui li,.swagger-ui main,.swagger-ui ol,.swagger-ui p,.swagger-ui pre,.swagger-ui section,.swagger-ui table,.swagger-ui td,.swagger-ui textarea,.swagger-ui th,.swagger-ui tr,.swagger-ui ul{box-sizing:border-box}.swagger-ui html,html{-webkit-text-size-adjust:100%}.swagger-ui .v-base,.swagger-ui progress{vertical-align:initial}.authorListItem_n3yI,.swagger-ui .list{list-style-type:none}.markdown li,body{word-wrap:break-word}.swagger-ui .authorization__btn svg,.swagger-ui .model-box-control svg,.swagger-ui .models-control svg,.swagger-ui .opblock-summary-control svg,a.buttonLink_MrmQ svg>*,a.buttonLink_MrmQ:hover svg>*{fill:var(--ofga-neutral-light)}.swagger-ui .collapse,.swagger-ui table,table{border-collapse:collapse}:root{--ifm-color-scheme:light;--ifm-dark-value:10%;--ifm-darker-value:15%;--ifm-darkest-value:30%;--ifm-light-value:15%;--ifm-lighter-value:30%;--ifm-lightest-value:50%;--ifm-contrast-background-value:90%;--ifm-contrast-foreground-value:70%;--ifm-contrast-background-dark-value:70%;--ifm-contrast-foreground-dark-value:90%;--ifm-color-primary:#3578e5;--ifm-color-secondary:#ebedf0;--ifm-color-success:#00a400;--ifm-color-info:#54c7ec;--ifm-color-warning:#ffba00;--ifm-color-danger:#fa383e;--ifm-color-primary-dark:#306cce;--ifm-color-primary-darker:#2d66c3;--ifm-color-primary-darkest:#2554a0;--ifm-color-primary-light:#538ce9;--ifm-color-primary-lighter:#72a1ed;--ifm-color-primary-lightest:#9abcf2;--ifm-color-primary-contrast-background:#ebf2fc;--ifm-color-primary-contrast-foreground:#102445;--ifm-color-secondary-dark:#d4d5d8;--ifm-color-secondary-darker:#c8c9cc;--ifm-color-secondary-darkest:#a4a6a8;--ifm-color-secondary-light:#eef0f2;--ifm-color-secondary-lighter:#f1f2f5;--ifm-color-secondary-lightest:#f5f6f8;--ifm-color-secondary-contrast-background:#fdfdfe;--ifm-color-secondary-contrast-foreground:#474748;--ifm-color-success-dark:#009400;--ifm-color-success-darker:#008b00;--ifm-color-success-darkest:#007300;--ifm-color-success-light:#26b226;--ifm-color-success-lighter:#4dbf4d;--ifm-color-success-lightest:#80d280;--ifm-color-success-contrast-background:#e6f6e6;--ifm-color-success-contrast-foreground:#003100;--ifm-color-info-dark:#4cb3d4;--ifm-color-info-darker:#47a9c9;--ifm-color-info-darkest:#3b8ba5;--ifm-color-info-light:#6ecfef;--ifm-color-info-lighter:#87d8f2;--ifm-color-info-lightest:#aae3f6;--ifm-color-info-contrast-background:#eef9fd;--ifm-color-info-contrast-foreground:#193c47;--ifm-color-warning-dark:#e6a700;--ifm-color-warning-darker:#d99e00;--ifm-color-warning-darkest:#b38200;--ifm-color-warning-light:#ffc426;--ifm-color-warning-lighter:#ffcf4d;--ifm-color-warning-lightest:#ffdd80;--ifm-color-warning-contrast-background:#fff8e6;--ifm-color-warning-contrast-foreground:#4d3800;--ifm-color-danger-dark:#e13238;--ifm-color-danger-darker:#d53035;--ifm-color-danger-darkest:#af272b;--ifm-color-danger-light:#fb565b;--ifm-color-danger-lighter:#fb7478;--ifm-color-danger-lightest:#fd9c9f;--ifm-color-danger-contrast-background:#ffebec;--ifm-color-danger-contrast-foreground:#4b1113;--ifm-color-white:#fff;--ifm-color-black:#000;--ifm-color-gray-0:var(--ifm-color-white);--ifm-color-gray-100:#f5f6f7;--ifm-color-gray-200:#ebedf0;--ifm-color-gray-300:#dadde1;--ifm-color-gray-400:#ccd0d5;--ifm-color-gray-500:#bec3c9;--ifm-color-gray-600:#8d949e;--ifm-color-gray-700:#606770;--ifm-color-gray-800:#444950;--ifm-color-gray-900:#1c1e21;--ifm-color-gray-1000:var(--ifm-color-black);--ifm-color-emphasis-0:var(--ifm-color-gray-0);--ifm-color-emphasis-100:var(--ifm-color-gray-100);--ifm-color-emphasis-200:var(--ifm-color-gray-200);--ifm-color-emphasis-300:var(--ifm-color-gray-300);--ifm-color-emphasis-400:var(--ifm-color-gray-400);--ifm-color-emphasis-600:var(--ifm-color-gray-600);--ifm-color-emphasis-700:var(--ifm-color-gray-700);--ifm-color-emphasis-800:var(--ifm-color-gray-800);--ifm-color-emphasis-900:var(--ifm-color-gray-900);--ifm-color-emphasis-1000:var(--ifm-color-gray-1000);--ifm-color-content:var(--ifm-color-emphasis-900);--ifm-color-content-inverse:var(--ifm-color-emphasis-0);--ifm-color-content-secondary:#525860;--ifm-background-color:#0000;--ifm-background-surface-color:var(--ifm-color-content-inverse);--ifm-global-border-width:1px;--ifm-global-radius:0.4rem;--ifm-hover-overlay:#0000000d;--ifm-font-color-base:var(--ifm-color-content);--ifm-font-color-base-inverse:var(--ifm-color-content-inverse);--ifm-font-color-secondary:var(--ifm-color-content-secondary);--ifm-font-family-base:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--ifm-font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--ifm-font-size-base:100%;--ifm-font-weight-light:300;--ifm-font-weight-normal:400;--ifm-font-weight-semibold:500;--ifm-font-weight-bold:700;--ifm-font-weight-base:var(--ifm-font-weight-normal);--ifm-line-height-base:1.65;--ifm-global-spacing:1rem;--ifm-spacing-vertical:var(--ifm-global-spacing);--ifm-spacing-horizontal:var(--ifm-global-spacing);--ifm-transition-fast:200ms;--ifm-transition-slow:400ms;--ifm-transition-timing-default:cubic-bezier(0.08,0.52,0.52,1);--ifm-global-shadow-lw:0 1px 2px 0 #0000001a;--ifm-global-shadow-md:0 5px 40px #0003;--ifm-global-shadow-tl:0 12px 28px 0 #0003,0 2px 4px 0 #0000001a;--ifm-z-index-dropdown:100;--ifm-z-index-fixed:200;--ifm-z-index-overlay:400;--ifm-container-width:1140px;--ifm-container-width-xl:1320px;--ifm-code-background:#f6f7f8;--ifm-code-border-radius:var(--ifm-global-radius);--ifm-code-font-size:90%;--ifm-code-padding-horizontal:0.1rem;--ifm-code-padding-vertical:0.1rem;--ifm-pre-background:var(--ifm-code-background);--ifm-pre-border-radius:var(--ifm-code-border-radius);--ifm-pre-color:inherit;--ifm-pre-line-height:1.45;--ifm-pre-padding:1rem;--ifm-heading-color:inherit;--ifm-heading-margin-top:0;--ifm-heading-margin-bottom:var(--ifm-spacing-vertical);--ifm-heading-font-family:var(--ifm-font-family-base);--ifm-heading-font-weight:var(--ifm-font-weight-bold);--ifm-heading-line-height:1.25;--ifm-h1-font-size:2rem;--ifm-h2-font-size:1.5rem;--ifm-h3-font-size:1.25rem;--ifm-h4-font-size:1rem;--ifm-h5-font-size:0.875rem;--ifm-h6-font-size:0.85rem;--ifm-image-alignment-padding:1.25rem;--ifm-leading-desktop:1.25;--ifm-leading:calc(var(--ifm-leading-desktop)*1rem);--ifm-list-left-padding:2rem;--ifm-list-margin:1rem;--ifm-list-item-margin:0.25rem;--ifm-list-paragraph-margin:1rem;--ifm-table-cell-padding:0.75rem;--ifm-table-background:#0000;--ifm-table-stripe-background:#00000008;--ifm-table-border-width:1px;--ifm-table-border-color:var(--ifm-color-emphasis-300);--ifm-table-head-background:inherit;--ifm-table-head-color:inherit;--ifm-table-head-font-weight:var(--ifm-font-weight-bold);--ifm-table-cell-color:inherit;--ifm-link-color:var(--ifm-color-primary);--ifm-link-decoration:none;--ifm-link-hover-color:var(--ifm-link-color);--ifm-link-hover-decoration:underline;--ifm-paragraph-margin-bottom:var(--ifm-leading);--ifm-blockquote-font-size:var(--ifm-font-size-base);--ifm-blockquote-border-left-width:2px;--ifm-blockquote-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-blockquote-padding-vertical:0;--ifm-blockquote-shadow:none;--ifm-blockquote-color:var(--ifm-color-emphasis-800);--ifm-blockquote-border-color:var(--ifm-color-emphasis-300);--ifm-hr-background-color:var(--ifm-color-emphasis-500);--ifm-hr-height:1px;--ifm-hr-margin-vertical:1.5rem;--ifm-scrollbar-size:7px;--ifm-scrollbar-track-background-color:#f1f1f1;--ifm-scrollbar-thumb-background-color:silver;--ifm-scrollbar-thumb-hover-background-color:#a7a7a7;--ifm-alert-background-color:inherit;--ifm-alert-border-color:inherit;--ifm-alert-border-radius:var(--ifm-global-radius);--ifm-alert-border-width:0px;--ifm-alert-border-left-width:5px;--ifm-alert-color:var(--ifm-font-color-base);--ifm-alert-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-alert-padding-vertical:var(--ifm-spacing-vertical);--ifm-alert-shadow:var(--ifm-global-shadow-lw);--ifm-avatar-intro-margin:1rem;--ifm-avatar-intro-alignment:inherit;--ifm-avatar-photo-size:3rem;--ifm-badge-background-color:inherit;--ifm-badge-border-color:inherit;--ifm-badge-border-radius:var(--ifm-global-radius);--ifm-badge-border-width:var(--ifm-global-border-width);--ifm-badge-color:var(--ifm-color-white);--ifm-badge-padding-horizontal:calc(var(--ifm-spacing-horizontal)*0.5);--ifm-badge-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-breadcrumb-border-radius:1.5rem;--ifm-breadcrumb-spacing:0.5rem;--ifm-breadcrumb-color-active:var(--ifm-color-primary);--ifm-breadcrumb-item-background-active:var(--ifm-hover-overlay);--ifm-breadcrumb-padding-horizontal:0.8rem;--ifm-breadcrumb-padding-vertical:0.4rem;--ifm-breadcrumb-size-multiplier:1;--ifm-breadcrumb-separator:url('data:image/svg+xml;utf8,');--ifm-breadcrumb-separator-filter:none;--ifm-breadcrumb-separator-size:0.5rem;--ifm-breadcrumb-separator-size-multiplier:1.25;--ifm-button-background-color:inherit;--ifm-button-border-color:var(--ifm-button-background-color);--ifm-button-border-width:var(--ifm-global-border-width);--ifm-button-font-weight:var(--ifm-font-weight-bold);--ifm-button-padding-horizontal:1.5rem;--ifm-button-padding-vertical:0.375rem;--ifm-button-size-multiplier:1;--ifm-button-transition-duration:var(--ifm-transition-fast);--ifm-button-border-radius:calc(var(--ifm-global-radius)*var(--ifm-button-size-multiplier));--ifm-button-group-spacing:2px;--ifm-card-background-color:var(--ifm-background-surface-color);--ifm-card-border-radius:calc(var(--ifm-global-radius)*2);--ifm-card-horizontal-spacing:var(--ifm-global-spacing);--ifm-card-vertical-spacing:var(--ifm-global-spacing);--ifm-toc-border-color:var(--ifm-color-emphasis-300);--ifm-toc-link-color:var(--ifm-color-content-secondary);--ifm-toc-padding-vertical:0.5rem;--ifm-toc-padding-horizontal:0.5rem;--ifm-dropdown-background-color:var(--ifm-background-surface-color);--ifm-dropdown-font-weight:var(--ifm-font-weight-semibold);--ifm-dropdown-link-color:var(--ifm-font-color-base);--ifm-dropdown-hover-background-color:var(--ifm-hover-overlay);--ifm-footer-background-color:var(--ifm-color-emphasis-100);--ifm-footer-color:inherit;--ifm-footer-link-color:var(--ifm-color-emphasis-700);--ifm-footer-link-hover-color:var(--ifm-color-primary);--ifm-footer-link-horizontal-spacing:0.5rem;--ifm-footer-padding-horizontal:calc(var(--ifm-spacing-horizontal)*2);--ifm-footer-padding-vertical:calc(var(--ifm-spacing-vertical)*2);--ifm-footer-title-color:inherit;--ifm-footer-logo-max-width:min(30rem,90vw);--ifm-hero-background-color:var(--ifm-background-surface-color);--ifm-hero-text-color:var(--ifm-color-emphasis-800);--ifm-menu-color:var(--ifm-color-emphasis-700);--ifm-menu-color-active:var(--ifm-color-primary);--ifm-menu-color-background-active:var(--ifm-hover-overlay);--ifm-menu-color-background-hover:var(--ifm-hover-overlay);--ifm-menu-link-padding-horizontal:0.75rem;--ifm-menu-link-padding-vertical:0.375rem;--ifm-menu-link-sublist-icon:url('data:image/svg+xml;utf8,');--ifm-menu-link-sublist-icon-filter:none;--ifm-navbar-background-color:var(--ifm-background-surface-color);--ifm-navbar-height:3.75rem;--ifm-navbar-item-padding-horizontal:0.75rem;--ifm-navbar-item-padding-vertical:0.25rem;--ifm-navbar-link-color:var(--ifm-font-color-base);--ifm-navbar-link-active-color:var(--ifm-link-color);--ifm-navbar-padding-horizontal:var(--ifm-spacing-horizontal);--ifm-navbar-padding-vertical:calc(var(--ifm-spacing-vertical)*0.5);--ifm-navbar-shadow:var(--ifm-global-shadow-lw);--ifm-navbar-search-input-background-color:var(--ifm-color-emphasis-200);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-800);--ifm-navbar-search-input-placeholder-color:var(--ifm-color-emphasis-500);--ifm-navbar-search-input-icon:url('data:image/svg+xml;utf8,');--ifm-navbar-sidebar-width:83vw;--ifm-pagination-border-radius:var(--ifm-global-radius);--ifm-pagination-color-active:var(--ifm-color-primary);--ifm-pagination-font-size:1rem;--ifm-pagination-item-active-background:var(--ifm-hover-overlay);--ifm-pagination-page-spacing:0.2em;--ifm-pagination-padding-horizontal:calc(var(--ifm-spacing-horizontal)*1);--ifm-pagination-padding-vertical:calc(var(--ifm-spacing-vertical)*0.25);--ifm-pagination-nav-border-radius:var(--ifm-global-radius);--ifm-pagination-nav-color-hover:var(--ifm-color-primary);--ifm-pills-color-active:var(--ifm-color-primary);--ifm-pills-color-background-active:var(--ifm-hover-overlay);--ifm-pills-spacing:0.125rem;--ifm-tabs-color:var(--ifm-font-color-secondary);--ifm-tabs-color-active:var(--ifm-color-primary);--ifm-tabs-color-active-border:var(--ifm-tabs-color-active);--ifm-tabs-padding-horizontal:1rem;--ifm-tabs-padding-vertical:1rem;--docusaurus-progress-bar-color:var(--ifm-color-primary);--ofga-green-neon:#79ed83;--ofga-green-light:#d3ffd7;--ofga-green-dark:#558f69;--ofga-cyan-neon-light:#cdfcfe;--ofga-cyan-neon:#20f1f5;--ofga-cyan-neon-dark:#2f7f82;--ofga-neutral-black:#131519;--ofga-neutral-darkest:#272b33;--ofga-neutral-darker:#3a3d44;--ofga-neutral-dark:#838892;--ofga-neutral-aluminium:#bdc4cf;--ofga-neutral-base:var(--ofga-neutral-aluminium);--ofga-neutral-light:#d3d8df;--ofga-neutral-lighter:#eaecee;--ofga-neutral-lightest:#f4f6f7;--ofga-neutral-white:#fff;--ofga-color-default:#fff;--ofga-color-comment:#737981;--ofga-color-keyword:#aaa;--ofga-color-module:#79ed83;--ofga-color-type:#79ed83;--ofga-color-relation:#20f1f5;--ofga-color-directly-assignable:#ceec93;--ofga-color-primary:var(--ofga-green-neon);--ofga-color-primary-dark:var(--ofga-green-dark);--ofga-color-primary-light:var(--ofga-green-light);--ofga-color-secondary:var(--ofga-cyan-neon);--ofga-color-secondary-light:var(--ofga-cyan-neon-light);--ofga-color-secondary-dark:var(--ofga-cyan-neon-dark);--ofga-color-foreground:var(--ofga-neutral-white);--ofga-color-background:var(--ofga-neutral-black);--ofga-font-base:"Inter",sans-serif,-apple-system,BlinkMacSystemFont,‘Segoe UI’,Roboto,Helvetica,Arial,sans-serif,‘Apple Color Emoji’,‘Segoe UI Emoji’,‘Segoe UI Symbol’;--ofga-font-highlight:"Space Grotesk",sans-serif;--true-black:#000;--true-white:#fff;--ifm-color-primary:#2e8555;--ifm-color-primary-dark:#29784c;--ifm-color-primary-darker:#277148;--ifm-color-primary-darkest:#205d3b;--ifm-color-primary-light:#33925d;--ifm-color-primary-lighter:#359962;--ifm-color-primary-lightest:#3cad6e;--ifm-code-font-size:95%;--docusaurus-highlighted-code-line-bg:#0000001a;--ifm-pre-padding:2rem;--ifm-navbar-height:6.5rem;--docusaurus-announcement-bar-height:auto;--docusaurus-collapse-button-bg:#0000;--docusaurus-collapse-button-bg-hover:#0000001a;--doc-sidebar-width:300px;--doc-sidebar-hidden-width:30px;--docusaurus-blog-social-icon-size:1rem;--ifm-color-primary-contrast-foreground:var(--ofga-neon-green);--docusaurus-tag-list-border:var(--ifm-color-emphasis-300)}.badge--danger,.badge--info,.badge--primary,.badge--secondary,.badge--success,.badge--warning{--ifm-badge-border-color:var(--ifm-badge-background-color)}.button--link,.button--outline{--ifm-button-background-color:#0000}html{background-color:var(--ifm-background-color);color:var(--ifm-font-color-base);color-scheme:var(--ifm-color-scheme);font:var(--ifm-font-size-base)/var(--ifm-line-height-base) var(--ifm-font-family-base);-webkit-font-smoothing:antialiased;text-rendering:optimizelegibility;text-size-adjust:100%}iframe{border:0;color-scheme:auto}.container{margin:0 auto;max-width:var(--ifm-container-width)}.container--fluid,.navbar__logo img{max-width:inherit}.row{display:flex;flex-wrap:wrap;margin:0 calc(var(--ifm-spacing-horizontal)*-1)}.margin-bottom--none,.margin-vert--none,.markdown>:last-child{margin-bottom:0!important}.margin-top--none,.margin-vert--none,.tabItem_LNqP{margin-top:0!important}.row--no-gutters,.swagger-ui .mh0{margin-left:0;margin-right:0}.margin-horiz--none,.margin-right--none{margin-right:0!important}.row--no-gutters>.col,.swagger-ui .ph0{padding-left:0;padding-right:0}.row--align-top,.swagger-ui .items-start{align-items:flex-start}.row--align-bottom,.swagger-ui .items-end{align-items:flex-end}.menuExternalLink_NmtK,.row--align-center,.swagger-ui .items-center{align-items:center}.row--align-stretch,.swagger-ui .items-stretch{align-items:stretch}.row--align-baseline,.swagger-ui .items-baseline{align-items:baseline}.col{--ifm-col-width:100%;flex:1 0;margin-left:0;max-width:var(--ifm-col-width)}.padding-bottom--none,.padding-vert--none{padding-bottom:0!important}.padding-top--none,.padding-vert--none{padding-top:0!important}.padding-horiz--none,.padding-left--none{padding-left:0!important}.padding-horiz--none,.padding-right--none{padding-right:0!important}.col[class*=col--]{flex:0 0 var(--ifm-col-width)}.col--1{--ifm-col-width:8.33333%}.col--offset-1{margin-left:8.33333%}.col--2{--ifm-col-width:16.66667%}.col--offset-2{margin-left:16.66667%}.col--3{--ifm-col-width:25%}.col--offset-3{margin-left:25%}.col--4{--ifm-col-width:33.33333%}.col--offset-4{margin-left:33.33333%}.col--5{--ifm-col-width:41.66667%}.col--offset-5{margin-left:41.66667%}.col--6{--ifm-col-width:50%}.col--offset-6{margin-left:50%}.col--7{--ifm-col-width:58.33333%}.col--offset-7{margin-left:58.33333%}.col--8{--ifm-col-width:66.66667%}.col--offset-8{margin-left:66.66667%}.col--9{--ifm-col-width:75%}.col--offset-9{margin-left:75%}.col--10{--ifm-col-width:83.33333%}.col--offset-10{margin-left:83.33333%}.col--11{--ifm-col-width:91.66667%}.col--offset-11{margin-left:91.66667%}.col--12{--ifm-col-width:100%}.col--offset-12{margin-left:100%}.margin-horiz--none,.margin-left--none{margin-left:0!important}.margin--none{margin:0!important}.margin-bottom--xs,.margin-vert--xs{margin-bottom:.25rem!important}.margin-top--xs,.margin-vert--xs{margin-top:.25rem!important}.margin-horiz--xs,.margin-left--xs{margin-left:.25rem!important}.margin-horiz--xs,.margin-right--xs{margin-right:.25rem!important}.margin--xs{margin:.25rem!important}.margin-bottom--sm,.margin-vert--sm{margin-bottom:.5rem!important}.margin-top--sm,.margin-vert--sm{margin-top:.5rem!important}.margin-horiz--sm,.margin-left--sm{margin-left:.5rem!important}.margin-horiz--sm,.margin-right--sm{margin-right:.5rem!important}.margin--sm{margin:.5rem!important}.margin-bottom--md,.margin-vert--md{margin-bottom:1rem!important}.margin-top--md,.margin-vert--md{margin-top:1rem!important}.margin-horiz--md,.margin-left--md{margin-left:1rem!important}.margin-horiz--md,.margin-right--md{margin-right:1rem!important}.margin--md{margin:1rem!important}.margin-bottom--lg,.margin-vert--lg{margin-bottom:2rem!important}.margin-top--lg,.margin-vert--lg{margin-top:2rem!important}.margin-horiz--lg,.margin-left--lg{margin-left:2rem!important}.margin-horiz--lg,.margin-right--lg{margin-right:2rem!important}.margin--lg{margin:2rem!important}.margin-bottom--xl,.margin-vert--xl{margin-bottom:5rem!important}.margin-top--xl,.margin-vert--xl{margin-top:5rem!important}.margin-horiz--xl,.margin-left--xl{margin-left:5rem!important}.margin-horiz--xl,.margin-right--xl{margin-right:5rem!important}.margin--xl{margin:5rem!important}.padding--none{padding:0!important}.padding-bottom--xs,.padding-vert--xs{padding-bottom:.25rem!important}.padding-top--xs,.padding-vert--xs{padding-top:.25rem!important}.padding-horiz--xs,.padding-left--xs{padding-left:.25rem!important}.padding-horiz--xs,.padding-right--xs{padding-right:.25rem!important}.padding--xs{padding:.25rem!important}.padding-bottom--sm,.padding-vert--sm{padding-bottom:.5rem!important}.padding-top--sm,.padding-vert--sm{padding-top:.5rem!important}.padding-horiz--sm,.padding-left--sm{padding-left:.5rem!important}.padding-horiz--sm,.padding-right--sm{padding-right:.5rem!important}.padding--sm{padding:.5rem!important}.padding-bottom--md,.padding-vert--md{padding-bottom:1rem!important}.padding-top--md,.padding-vert--md{padding-top:1rem!important}.padding-horiz--md,.padding-left--md{padding-left:1rem!important}.padding-horiz--md,.padding-right--md{padding-right:1rem!important}.padding--md{padding:1rem!important}.padding-bottom--lg,.padding-vert--lg{padding-bottom:2rem!important}.padding-top--lg,.padding-vert--lg{padding-top:2rem!important}.padding-horiz--lg,.padding-left--lg{padding-left:2rem!important}.padding-horiz--lg,.padding-right--lg{padding-right:2rem!important}.padding--lg{padding:2rem!important}.padding-bottom--xl,.padding-vert--xl{padding-bottom:5rem!important}.padding-top--xl,.padding-vert--xl{padding-top:5rem!important}.padding-horiz--xl,.padding-left--xl{padding-left:5rem!important}.padding-horiz--xl,.padding-right--xl{padding-right:5rem!important}.padding--xl{padding:5rem!important}code{background-color:var(--ifm-code-background);border:.1rem solid #0000001a;border-radius:var(--ifm-code-border-radius);font-family:var(--ifm-font-family-monospace);font-size:var(--ifm-code-font-size);padding:var(--ifm-code-padding-vertical) var(--ifm-code-padding-horizontal)}.swagger-ui .color-inherit,.swagger-ui .hover-inherit:focus,.swagger-ui .hover-inherit:hover,a code{color:inherit}pre{background-color:var(--ifm-pre-background);border-radius:var(--ifm-pre-border-radius);color:var(--ifm-pre-color);font:var(--ifm-code-font-size)/var(--ifm-pre-line-height) var(--ifm-font-family-monospace);padding:var(--ifm-pre-padding)}pre code{background-color:initial;border:none;font-size:100%;line-height:inherit;padding:0}kbd{background-color:var(--ifm-color-emphasis-0);border:1px solid var(--ifm-color-emphasis-400);border-radius:.2rem;box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-400);color:var(--ifm-color-emphasis-800);font:80% var(--ifm-font-family-monospace);padding:.15rem .3rem}h1,h2,h3,h4,h5,h6{color:var(--ifm-heading-color);font-family:var(--ifm-heading-font-family);font-weight:var(--ifm-heading-font-weight);line-height:var(--ifm-heading-line-height);margin:var(--ifm-heading-margin-top) 0 var(--ifm-heading-margin-bottom) 0}h1{font-size:var(--ifm-h1-font-size)}h2{font-size:var(--ifm-h2-font-size)}h3{font-size:var(--ifm-h3-font-size)}h4{font-size:var(--ifm-h4-font-size)}h5{font-size:var(--ifm-h5-font-size)}h6{font-size:var(--ifm-h6-font-size)}.swagger-ui .errors-wrapper .errors .message.thrown,.swagger-ui .mw-100,img{max-width:100%}img[align=right]{padding-left:var(--image-alignment-padding)}img[align=left]{padding-right:var(--image-alignment-padding)}.markdown{--ifm-h1-vertical-rhythm-top:3;--ifm-h2-vertical-rhythm-top:2;--ifm-h3-vertical-rhythm-top:1.5;--ifm-heading-vertical-rhythm-top:1.25;--ifm-h1-vertical-rhythm-bottom:1.25;--ifm-heading-vertical-rhythm-bottom:1}.markdown:after,.markdown:before{content:"";display:table}.markdown:after,.swagger-ui .cb,.swagger-ui .cf:after{clear:both}.markdown h1:first-child{--ifm-h1-font-size:3rem;margin-bottom:calc(var(--ifm-h1-vertical-rhythm-bottom)*var(--ifm-leading))}.markdown>h2{--ifm-h2-font-size:2rem;margin-top:calc(var(--ifm-h2-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h3{--ifm-h3-font-size:1.5rem;margin-top:calc(var(--ifm-h3-vertical-rhythm-top)*var(--ifm-leading))}.markdown>h4,.markdown>h5,.markdown>h6{margin-top:calc(var(--ifm-heading-vertical-rhythm-top)*var(--ifm-leading))}.markdown>p,.markdown>pre,.markdown>ul,.tabList__CuJ{margin-bottom:var(--ifm-leading)}.markdown li>p{margin-top:var(--ifm-list-paragraph-margin)}.markdown li+li{margin-top:var(--ifm-list-item-margin)}ol,ul{margin:0 0 var(--ifm-list-margin);padding-left:var(--ifm-list-left-padding)}ol ol,ul ol{list-style-type:lower-roman}ol ol ol,ol ul ol,ul ol ol,ul ul ol{list-style-type:lower-alpha}table{display:block;margin-bottom:var(--ifm-spacing-vertical)}table thead tr{border-bottom:2px solid var(--ifm-table-border-color)}table thead,table tr:nth-child(2n){background-color:var(--ifm-table-stripe-background)}table tr{background-color:var(--ifm-table-background);border-top:var(--ifm-table-border-width) solid var(--ifm-table-border-color)}table td,table th{border:var(--ifm-table-border-width) solid var(--ifm-table-border-color);padding:var(--ifm-table-cell-padding)}table th{background-color:var(--ifm-table-head-background);color:var(--ifm-table-head-color);font-weight:var(--ifm-table-head-font-weight)}table td{color:var(--ifm-table-cell-color)}strong{font-weight:var(--ifm-font-weight-bold)}a{color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}a:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.button:hover,.text--no-decoration,.text--no-decoration:hover,a:not([href]){-webkit-text-decoration:none;text-decoration:none}p{margin:0 0 var(--ifm-paragraph-margin-bottom)}blockquote{border-left:var(--ifm-blockquote-border-left-width) solid var(--ifm-blockquote-border-color);box-shadow:var(--ifm-blockquote-shadow);color:var(--ifm-blockquote-color);font-size:var(--ifm-blockquote-font-size);padding:var(--ifm-blockquote-padding-vertical) var(--ifm-blockquote-padding-horizontal)}blockquote>:first-child{margin-top:0}blockquote>:last-child{margin-bottom:0}hr{background-color:var(--ifm-hr-background-color);border:0;height:var(--ifm-hr-height);margin:var(--ifm-hr-margin-vertical) 0}.shadow--lw{box-shadow:var(--ifm-global-shadow-lw)!important}.shadow--md{box-shadow:var(--ifm-global-shadow-md)!important}.shadow--tl{box-shadow:var(--ifm-global-shadow-tl)!important}.text--primary,.wordWrapButtonEnabled_EoeP .wordWrapButtonIcon_Bwma{color:var(--ifm-color-primary)}.text--secondary{color:var(--ifm-color-secondary)}.text--success{color:var(--ifm-color-success)}.text--info{color:var(--ifm-color-info)}.text--warning{color:var(--ifm-color-warning)}.text--danger{color:var(--ifm-color-danger)}.swagger-ui .tc,.text--center{text-align:center}.swagger-ui .tl,.text--left{text-align:left}.swagger-ui .tj,.text--justify{text-align:justify}.swagger-ui .tr,.text--right{text-align:right}.swagger-ui .ttc,.text--capitalize{text-transform:capitalize}.swagger-ui .ttl,.text--lowercase{text-transform:lowercase}.alert__heading,.swagger-ui .ttu,.text--uppercase{text-transform:uppercase}.text--light{font-weight:var(--ifm-font-weight-light)}.text--normal{font-weight:var(--ifm-font-weight-normal)}.text--semibold{font-weight:var(--ifm-font-weight-semibold)}.text--bold{font-weight:var(--ifm-font-weight-bold)}.swagger-ui .i,.swagger-ui dfn,.text--italic{font-style:italic}.swagger-ui .truncate,.text--truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.swagger-ui .responses-inner .curl,.swagger-ui .ws-normal,.swagger-ui legend{white-space:normal}.text--break{word-wrap:break-word!important;word-break:break-word!important}.clean-btn{background:none;border:none;color:inherit;cursor:pointer;font-family:inherit;padding:0}.alert,.alert .close{color:var(--ifm-alert-foreground-color)}.clean-list,.documentation-card-box-links-none_sQ2X li,.documentation-card-box-links-none_sQ2X ul{list-style:none;padding-left:0}.alert--primary{--ifm-alert-background-color:var(--ifm-color-primary-contrast-background);--ifm-alert-background-color-highlight:#3578e526;--ifm-alert-foreground-color:var(--ifm-color-primary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-primary-dark)}.alert--secondary{--ifm-alert-background-color:var(--ifm-color-secondary-contrast-background);--ifm-alert-background-color-highlight:#ebedf026;--ifm-alert-foreground-color:var(--ifm-color-secondary-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-secondary-dark)}.alert--success{--ifm-alert-background-color:var(--ifm-color-success-contrast-background);--ifm-alert-background-color-highlight:#00a40026;--ifm-alert-foreground-color:var(--ifm-color-success-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-success-dark)}.alert--info{--ifm-alert-background-color:var(--ifm-color-info-contrast-background);--ifm-alert-background-color-highlight:#54c7ec26;--ifm-alert-foreground-color:var(--ifm-color-info-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-info-dark)}.alert--warning{--ifm-alert-background-color:var(--ifm-color-warning-contrast-background);--ifm-alert-background-color-highlight:#ffba0026;--ifm-alert-foreground-color:var(--ifm-color-warning-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-warning-dark)}.alert--danger{--ifm-alert-background-color:var(--ifm-color-danger-contrast-background);--ifm-alert-background-color-highlight:#fa383e26;--ifm-alert-foreground-color:var(--ifm-color-danger-contrast-foreground);--ifm-alert-border-color:var(--ifm-color-danger-dark)}.alert{--ifm-code-background:var(--ifm-alert-background-color-highlight);--ifm-link-color:var(--ifm-alert-foreground-color);--ifm-link-hover-color:var(--ifm-alert-foreground-color);--ifm-link-decoration:underline;--ifm-tabs-color:var(--ifm-alert-foreground-color);--ifm-tabs-color-active:var(--ifm-alert-foreground-color);--ifm-tabs-color-active-border:var(--ifm-alert-border-color);background-color:var(--ifm-alert-background-color);border:var(--ifm-alert-border-width) solid var(--ifm-alert-border-color);border-left-width:var(--ifm-alert-border-left-width);border-radius:var(--ifm-alert-border-radius);box-shadow:var(--ifm-alert-shadow);padding:var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal)}.alert__heading{align-items:center;display:flex;font:700 var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);margin-bottom:.5rem}.alert__icon{display:inline-flex;margin-right:.4em}.alert__icon svg{fill:var(--ifm-alert-foreground-color);stroke:var(--ifm-alert-foreground-color);stroke-width:0}.alert .close{margin:calc(var(--ifm-alert-padding-vertical)*-1) calc(var(--ifm-alert-padding-horizontal)*-1) 0 0;opacity:.75}.alert .close:focus,.alert .close:hover{opacity:1}.alert a{text-decoration-color:var(--ifm-alert-border-color)}.alert a:hover{text-decoration-thickness:2px}.avatar{column-gap:var(--ifm-avatar-intro-margin);display:flex}.avatar__photo{border-radius:50%;display:block;height:var(--ifm-avatar-photo-size);overflow:hidden;width:var(--ifm-avatar-photo-size)}.avatar__photo--sm{--ifm-avatar-photo-size:2rem}.avatar__photo--lg{--ifm-avatar-photo-size:4rem}.avatar__photo--xl{--ifm-avatar-photo-size:6rem}.avatar__intro{display:flex;flex:1 1;flex-direction:column;justify-content:center;text-align:var(--ifm-avatar-intro-alignment)}.badge,.breadcrumbs__item,.breadcrumbs__link,.button,.dropdown>.navbar__link:after,.searchBarContainer_NW3z.searchIndexLoading_EJ1f .searchBarLoadingRing_YnHq,.swagger-ui .dib,.swagger-ui audio,.swagger-ui canvas,.swagger-ui video{display:inline-block}.avatar__name{font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base)}.avatar__subtitle{margin-top:.25rem}.avatar--vertical{--ifm-avatar-intro-alignment:center;--ifm-avatar-intro-margin:0.5rem;align-items:center;flex-direction:column}.badge{background-color:var(--ifm-badge-background-color);border:var(--ifm-badge-border-width) solid var(--ifm-badge-border-color);border-radius:var(--ifm-badge-border-radius);color:var(--ifm-badge-color);font-size:75%;font-weight:var(--ifm-font-weight-bold);line-height:1;padding:var(--ifm-badge-padding-vertical) var(--ifm-badge-padding-horizontal)}.badge--primary{--ifm-badge-background-color:var(--ifm-color-primary)}.badge--secondary{--ifm-badge-background-color:var(--ifm-color-secondary);color:var(--ifm-color-black)}.breadcrumbs__link,.button.button--secondary.button--outline:not(.button--active):not(:hover){color:var(--ifm-font-color-base)}.badge--success{--ifm-badge-background-color:var(--ifm-color-success)}.badge--info{--ifm-badge-background-color:var(--ifm-color-info)}.badge--warning{--ifm-badge-background-color:var(--ifm-color-warning)}.badge--danger{--ifm-badge-background-color:var(--ifm-color-danger)}.breadcrumbs{margin-bottom:0;padding-left:0}.breadcrumbs__item:not(:last-child):after{background:var(--ifm-breadcrumb-separator) center;content:" ";display:inline-block;filter:var(--ifm-breadcrumb-separator-filter);height:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier));margin:0 var(--ifm-breadcrumb-spacing);opacity:.5;width:calc(var(--ifm-breadcrumb-separator-size)*var(--ifm-breadcrumb-size-multiplier)*var(--ifm-breadcrumb-separator-size-multiplier))}.breadcrumbs__item--active .breadcrumbs__link{background:var(--ifm-breadcrumb-item-background-active);color:var(--ifm-breadcrumb-color-active)}.breadcrumbs__link{border-radius:var(--ifm-breadcrumb-border-radius);font-size:calc(1rem*var(--ifm-breadcrumb-size-multiplier));padding:calc(var(--ifm-breadcrumb-padding-vertical)*var(--ifm-breadcrumb-size-multiplier)) calc(var(--ifm-breadcrumb-padding-horizontal)*var(--ifm-breadcrumb-size-multiplier));transition-duration:var(--ifm-transition-fast);transition-property:background,color}.breadcrumbs__link:any-link:hover,.breadcrumbs__link:link:hover,.breadcrumbs__link:visited:hover,area[href].breadcrumbs__link:hover{background:var(--ifm-breadcrumb-item-background-active);-webkit-text-decoration:none;text-decoration:none}.breadcrumbs--sm{--ifm-breadcrumb-size-multiplier:0.8}.breadcrumbs--lg{--ifm-breadcrumb-size-multiplier:1.2}.button{background-color:var(--ifm-button-background-color);border:var(--ifm-button-border-width) solid var(--ifm-button-border-color);border-radius:var(--ifm-button-border-radius);cursor:pointer;font-size:calc(.875rem*var(--ifm-button-size-multiplier));font-weight:var(--ifm-button-font-weight);line-height:1.5;padding:calc(var(--ifm-button-padding-vertical)*var(--ifm-button-size-multiplier)) calc(var(--ifm-button-padding-horizontal)*var(--ifm-button-size-multiplier));text-align:center;transition-duration:var(--ifm-button-transition-duration);transition-property:color,background,border-color;-webkit-user-select:none;user-select:none;white-space:nowrap}.button,.button:hover{color:var(--ifm-button-color)}.button--outline{--ifm-button-color:var(--ifm-button-border-color)}.button--outline:hover{--ifm-button-background-color:var(--ifm-button-border-color)}.button--link{--ifm-button-border-color:#0000;color:var(--ifm-link-color);text-decoration:var(--ifm-link-decoration)}.button--link.button--active,.button--link:active,.button--link:hover{color:var(--ifm-link-hover-color);text-decoration:var(--ifm-link-hover-decoration)}.dropdown__link--active,.dropdown__link:hover,.menu__link:hover,.navbar__brand:hover,.navbar__link--active,.navbar__link:hover,.pagination-nav__link:hover,.pagination__link:hover,.sidebarItemLink_mo7H:hover,.swagger-ui .link,.swagger-ui .no-underline{-webkit-text-decoration:none;text-decoration:none}.button.disabled,.button:disabled,.button[disabled]{opacity:.65;pointer-events:none}.button--sm{--ifm-button-size-multiplier:0.8}.button--lg{--ifm-button-size-multiplier:1.35}.button--block{display:block;width:100%}.button.button--secondary{color:var(--ifm-color-gray-900)}:where(.button--primary){--ifm-button-background-color:var(--ifm-color-primary);--ifm-button-border-color:var(--ifm-color-primary)}:where(.button--primary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-primary-dark);--ifm-button-border-color:var(--ifm-color-primary-dark)}.button--primary.button--active,.button--primary:active{--ifm-button-background-color:var(--ifm-color-primary-darker);--ifm-button-border-color:var(--ifm-color-primary-darker)}:where(.button--secondary){--ifm-button-background-color:var(--ifm-color-secondary);--ifm-button-border-color:var(--ifm-color-secondary)}:where(.button--secondary):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-secondary-dark);--ifm-button-border-color:var(--ifm-color-secondary-dark)}.button--secondary.button--active,.button--secondary:active{--ifm-button-background-color:var(--ifm-color-secondary-darker);--ifm-button-border-color:var(--ifm-color-secondary-darker)}:where(.button--success){--ifm-button-background-color:var(--ifm-color-success);--ifm-button-border-color:var(--ifm-color-success)}:where(.button--success):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-success-dark);--ifm-button-border-color:var(--ifm-color-success-dark)}.button--success.button--active,.button--success:active{--ifm-button-background-color:var(--ifm-color-success-darker);--ifm-button-border-color:var(--ifm-color-success-darker)}:where(.button--info){--ifm-button-background-color:var(--ifm-color-info);--ifm-button-border-color:var(--ifm-color-info)}:where(.button--info):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-info-dark);--ifm-button-border-color:var(--ifm-color-info-dark)}.button--info.button--active,.button--info:active{--ifm-button-background-color:var(--ifm-color-info-darker);--ifm-button-border-color:var(--ifm-color-info-darker)}:where(.button--warning){--ifm-button-background-color:var(--ifm-color-warning);--ifm-button-border-color:var(--ifm-color-warning)}:where(.button--warning):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-warning-dark);--ifm-button-border-color:var(--ifm-color-warning-dark)}.button--warning.button--active,.button--warning:active{--ifm-button-background-color:var(--ifm-color-warning-darker);--ifm-button-border-color:var(--ifm-color-warning-darker)}:where(.button--danger){--ifm-button-background-color:var(--ifm-color-danger);--ifm-button-border-color:var(--ifm-color-danger)}:where(.button--danger):not(.button--outline):hover{--ifm-button-background-color:var(--ifm-color-danger-dark);--ifm-button-border-color:var(--ifm-color-danger-dark)}.button--danger.button--active,.button--danger:active{--ifm-button-background-color:var(--ifm-color-danger-darker);--ifm-button-border-color:var(--ifm-color-danger-darker)}.button-group{display:inline-flex;gap:var(--ifm-button-group-spacing)}.button-group>.button:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.button-group>.button:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.button-group--block{display:flex;justify-content:stretch}.button-group--block>.button,.swagger-ui .flex-grow-1{flex-grow:1}.card{background-color:var(--ifm-card-background-color);border-radius:var(--ifm-card-border-radius);box-shadow:var(--ifm-global-shadow-lw);display:flex;flex-direction:column;overflow:hidden}.card--full-height,.swagger-ui .h-100,.table-of-contents,.theme-doc-toc-desktop,body,html{height:100%}.card__image{padding-top:var(--ifm-card-vertical-spacing)}.card__image:first-child,.swagger-ui .pt0{padding-top:0}.card__body,.card__footer,.card__header{padding:var(--ifm-card-vertical-spacing) var(--ifm-card-horizontal-spacing)}.card__body:not(:last-child),.card__footer:not(:last-child),.card__header:not(:last-child),.swagger-ui .pb0{padding-bottom:0}.card__body>:last-child,.card__footer>:last-child,.card__header>:last-child{margin-bottom:0}.card__footer{margin-top:auto}.table-of-contents{margin-bottom:0;padding:var(--ifm-toc-padding-vertical) 0}.table-of-contents,.table-of-contents ul{list-style:none;padding-left:var(--ifm-toc-padding-horizontal)}.table-of-contents li{margin:var(--ifm-toc-padding-vertical) var(--ifm-toc-padding-horizontal)}.table-of-contents__left-border{border-left:1px solid var(--ifm-toc-border-color)}.table-of-contents__link{color:var(--ifm-toc-link-color);display:block}.table-of-contents__link--active,.table-of-contents__link--active code,.table-of-contents__link:hover,.table-of-contents__link:hover code{color:var(--ifm-color-primary);-webkit-text-decoration:none;text-decoration:none}.close{color:var(--ifm-color-black);float:right;font-size:1.5rem;font-weight:var(--ifm-font-weight-bold);line-height:1;opacity:.5;padding:1rem;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.close:hover,.swagger-ui .o-70{opacity:.7}.close:focus,.swagger-ui .o-80,.theme-code-block-highlighted-line .codeLineNumber_Tfdd:before{opacity:.8}.dropdown{display:inline-flex;font-weight:var(--ifm-dropdown-font-weight);position:relative;vertical-align:top}.dropdown--hoverable:hover .dropdown__menu,.dropdown--show .dropdown__menu{opacity:1;pointer-events:all;transform:translateY(-1px);visibility:visible}.dropdown--right .dropdown__menu{left:inherit;right:0}.dropdown--nocaret .navbar__link:after{content:none!important}.dropdown__menu{background-color:var(--ifm-dropdown-background-color);border-radius:var(--ifm-global-radius);box-shadow:var(--ifm-global-shadow-md);left:0;list-style:none;max-height:80vh;min-width:10rem;opacity:0;overflow-y:auto;padding:.5rem;pointer-events:none;position:absolute;top:calc(100% - var(--ifm-navbar-item-padding-vertical) + .3rem);transform:translateY(-.625rem);transition-duration:var(--ifm-transition-fast);transition-property:opacity,transform,visibility;transition-timing-function:var(--ifm-transition-timing-default);visibility:hidden;z-index:var(--ifm-z-index-dropdown)}.menu__caret,.menu__link,.menu__list-item-collapsible{border-radius:.25rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.dropdown__link{border-radius:.25rem;color:var(--ifm-dropdown-link-color);display:block;font-size:.875rem;margin-top:.2rem;padding:.25rem .5rem;white-space:nowrap}.dropdown__link--active,.dropdown__link:hover{background-color:var(--ifm-dropdown-hover-background-color);color:var(--ifm-dropdown-link-color)}.dropdown__link--active,.dropdown__link--active:hover{--ifm-dropdown-link-color:var(--ifm-link-color)}.dropdown>.navbar__link:after{border-color:currentcolor #0000;border-style:solid;border-width:.4em .4em 0;content:"";margin-left:.3em;position:relative;top:2px;transform:translateY(-50%)}.footer{background-color:var(--ifm-footer-background-color);color:var(--ifm-footer-color);padding:var(--ifm-footer-padding-vertical) var(--ifm-footer-padding-horizontal)}.footer--dark{--ifm-footer-background-color:#303846;--ifm-footer-color:var(--ifm-footer-link-color);--ifm-footer-link-color:var(--ifm-color-secondary);--ifm-footer-title-color:var(--ifm-color-white)}.footer__link-item{color:var(--ifm-footer-link-color);line-height:2}.footer__link-item:hover{color:var(--ifm-footer-link-hover-color)}.footer__link-separator{margin:0 var(--ifm-footer-link-horizontal-spacing)}.footer__logo{margin-top:1rem;max-width:var(--ifm-footer-logo-max-width)}.container__no-padding,.grid_OmBo{max-width:var(--ifm-container-width)}.footer__title{color:var(--ifm-footer-title-color);font:700 var(--ifm-h4-font-size)/var(--ifm-heading-line-height) var(--ifm-font-family-base);margin-bottom:var(--ifm-heading-margin-bottom)}.menu,.navbar__link{font-weight:var(--ifm-font-weight-semibold)}.docItemContainer_Djhp article>:first-child,.docItemContainer_Djhp header+*,.footer__item,.swagger-ui .mt0{margin-top:0}.admonitionContent_BuS1>:last-child,.collapsibleContent_i85q p:last-child,.content_APwV p:last-child,.details_lb9f>summary>p:last-child,.footer__items,.searchResultItem_U687>h2,.swagger-ui .mb0,.tabItem_Ymn6>:last-child{margin-bottom:0}.codeBlockStandalone_MEMb,.swagger-ui .pa0,[type=checkbox]{padding:0}.hero{align-items:center;background-color:var(--ifm-hero-background-color);color:var(--ifm-hero-text-color);display:flex;padding:4rem 2rem}.hero--primary{--ifm-hero-background-color:var(--ifm-color-primary);--ifm-hero-text-color:var(--ifm-font-color-base-inverse)}.hero--dark{--ifm-hero-background-color:#303846;--ifm-hero-text-color:var(--ifm-color-white)}.hero__title,.swagger-ui .f1,.title_f1Hy{font-size:3rem}.hero__subtitle,.swagger-ui .f3{font-size:1.5rem}.menu__list{list-style:none;margin:0;padding-left:0}.menu__caret,.menu__link{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu__list .menu__list{flex:0 0 100%;margin-top:.25rem;padding-left:var(--ifm-menu-link-padding-horizontal)}.menu__list-item:not(:first-child),.swagger-ui .mt1{margin-top:.25rem}.menu__list-item--collapsed .menu__list{height:0;overflow:hidden}.menu__list-item-collapsible{display:flex;flex-wrap:wrap;position:relative}.menu__caret:hover,.menu__link:hover,.menu__list-item-collapsible--active,.menu__list-item-collapsible:hover{background:var(--ifm-menu-color-background-hover)}.menu__list-item-collapsible .menu__link--active,.menu__list-item-collapsible .menu__link:hover{background:none!important}.menu__caret,.menu__link{align-items:center;display:flex}.navbar-sidebar,.navbar-sidebar__backdrop{bottom:0;opacity:0;top:0;transition-duration:var(--ifm-transition-fast);transition-timing-function:ease-in-out}.menu__link{color:var(--ifm-menu-color);flex:1;line-height:1.25}.menu__link:hover{color:var(--ifm-menu-color)}.menu__caret:before,.menu__link--sublist-caret:after{transition:transform var(--ifm-transition-fast) linear;content:"";filter:var(--ifm-menu-link-sublist-icon-filter)}.menu__link--sublist-caret:after{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem;height:1.25rem;margin-left:auto;min-width:1.25rem;transform:rotate(180deg);width:1.25rem}.menu__link--active,.menu__link--active:hover{color:var(--ifm-menu-color-active)}.navbar__brand,.navbar__link{color:var(--ifm-navbar-link-color)}.menu__link--active:not(.menu__link--sublist){background-color:var(--ifm-menu-color-background-active)}.menu__caret:before{background:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem}.navbar--dark,html[data-theme=dark]{--ifm-menu-link-sublist-icon-filter:invert(100%) sepia(94%) saturate(17%) hue-rotate(223deg) brightness(104%) contrast(98%)}.navbar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-navbar-shadow);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar>.container,.navbar>.container-fluid,.swagger-ui .checkbox label,.swagger-ui .flex{display:flex}.navbar--fixed-top{position:sticky;top:0;z-index:var(--ifm-z-index-fixed)}#nprogress .bar,.navbar-sidebar,body:before{position:fixed;left:0}.navbar__inner{display:flex;flex-wrap:wrap;justify-content:space-between;width:100%}.navbar__brand{align-items:center;display:flex;min-width:0}.navbar__brand:hover{color:var(--ifm-navbar-link-hover-color)}.announcementBarContent_xLdY,.navbar__title{flex:1 1 auto}.navbar__toggle{display:none;margin-right:.5rem}.navbar__logo{flex:0 0 auto}.navbar__items{align-items:center;flex:1;min-width:0}.navbar__items--center{flex:0 0 auto}.documentation-banner_hL3X .documentation-banner-content_N4KI p,.markdown details p,.navbar__items--center .navbar__brand,.section_sUhq h3,.section_sUhq p,.swagger-ui .ma0,.swagger-ui body{margin:0}.navbar__items--center+.navbar__items--right{flex:1}.navbar__items--right{flex:0 0 auto;justify-content:flex-end}.navbar__items--right>:last-child,.swagger-ui .pr0{padding-right:0}.navbar__item{display:inline-block;padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}#nprogress,.navbar__item.dropdown .navbar__link:not([href]){pointer-events:none}.navbar__link--active,.navbar__link:hover{color:var(--ifm-navbar-link-hover-color)}.navbar--dark,.navbar--primary{--ifm-menu-color:var(--ifm-color-gray-300);--ifm-navbar-link-color:var(--ifm-color-gray-100);--ifm-navbar-search-input-background-color:#ffffff1a;--ifm-navbar-search-input-placeholder-color:#ffffff80;color:var(--ifm-color-white)}.navbar--dark{--ifm-navbar-background-color:#242526;--ifm-menu-color-background-active:#ffffff0d;--ifm-navbar-search-input-color:var(--ifm-color-white)}.navbar--primary{--ifm-navbar-background-color:var(--ifm-color-primary);--ifm-navbar-link-hover-color:var(--ifm-color-white);--ifm-menu-color-active:var(--ifm-color-white);--ifm-navbar-search-input-color:var(--ifm-color-emphasis-500)}.navbar__search-input{appearance:none;background:var(--ifm-navbar-search-input-background-color) var(--ifm-navbar-search-input-icon) no-repeat .75rem center/1rem 1rem;border:none;border-radius:2rem;color:var(--ifm-navbar-search-input-color);cursor:text;display:inline-block;font-size:1rem;height:2rem;padding:0 .5rem 0 2.25rem;width:12.5rem}.navbar__search-input::placeholder{color:var(--ifm-navbar-search-input-placeholder-color)}.navbar-sidebar{background-color:var(--ifm-navbar-background-color);box-shadow:var(--ifm-global-shadow-md);transform:translate3d(-100%,0,0);transition-property:opacity,visibility,transform;visibility:hidden;width:var(--ifm-navbar-sidebar-width)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar__items{transform:translateZ(0)}.navbar-sidebar--show .navbar-sidebar,.navbar-sidebar--show .navbar-sidebar__backdrop{opacity:1;visibility:visible}.navbar-sidebar__backdrop{background-color:#0009;left:0;position:fixed;right:0;transition-property:opacity,visibility;visibility:hidden}.navbar-sidebar__brand{align-items:center;box-shadow:var(--ifm-navbar-shadow);display:flex;flex:1;height:var(--ifm-navbar-height);padding:var(--ifm-navbar-padding-vertical) var(--ifm-navbar-padding-horizontal)}.navbar-sidebar__items{display:flex;height:calc(100% - var(--ifm-navbar-height));transition:transform var(--ifm-transition-fast) ease-in-out}.navbar-sidebar__items--show-secondary{transform:translate3d(calc((var(--ifm-navbar-sidebar-width))*-1),0,0)}.navbar-sidebar__item{flex-shrink:0;padding:.5rem;width:calc(var(--ifm-navbar-sidebar-width))}.navbar-sidebar__back{background:var(--ifm-menu-color-background-active);font-size:15px;font-weight:var(--ifm-button-font-weight);margin:0 0 .2rem -.5rem;padding:.6rem 1.5rem;position:relative;text-align:left;top:-.5rem;width:calc(100% + 1rem)}.navbar-sidebar__close{display:flex;margin-left:auto}.pagination{column-gap:var(--ifm-pagination-page-spacing);display:flex;font-size:var(--ifm-pagination-font-size);padding-left:0}.pagination--sm{--ifm-pagination-font-size:0.8rem;--ifm-pagination-padding-horizontal:0.8rem;--ifm-pagination-padding-vertical:0.2rem}.pagination--lg{--ifm-pagination-font-size:1.2rem;--ifm-pagination-padding-horizontal:1.2rem;--ifm-pagination-padding-vertical:0.3rem}.pagination__item,.swagger-ui .inline-flex{display:inline-flex}.pagination__item>span{padding:var(--ifm-pagination-padding-vertical)}.pagination__item--active .pagination__link{color:var(--ifm-pagination-color-active)}.pagination__item--active .pagination__link,.pagination__item:not(.pagination__item--active):hover .pagination__link{background:var(--ifm-pagination-item-active-background)}.pagination__item--disabled,.pagination__item[disabled]{opacity:.25;pointer-events:none}.pagination__link{border-radius:var(--ifm-pagination-border-radius);color:var(--ifm-font-color-base);display:inline-block;padding:var(--ifm-pagination-padding-vertical) var(--ifm-pagination-padding-horizontal);transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav{display:grid;grid-gap:var(--ifm-spacing-horizontal);gap:var(--ifm-spacing-horizontal);grid-template-columns:repeat(2,1fr)}.pagination-nav__link{border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-pagination-nav-border-radius);display:block;height:100%;line-height:var(--ifm-heading-line-height);padding:var(--ifm-global-spacing);transition:border-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pagination-nav__link:hover{border-color:var(--ifm-pagination-nav-color-hover)}.content_knG7 a,.hitFooter_E9YW a,.suggestion_fB_2.cursor_eG29 mark,.swagger-ui .underline,.swagger-ui .underline-hover:focus,.swagger-ui .underline-hover:hover{-webkit-text-decoration:underline;text-decoration:underline}.pagination-nav__link--next{grid-column:2/3;text-align:right}.pagination-nav__label{font-size:var(--ifm-h4-font-size);font-weight:var(--ifm-heading-font-weight);word-break:break-word}.pagination-nav__link--prev .pagination-nav__label:before{content:"« "}.pagination-nav__link--next .pagination-nav__label:after{content:" »"}.pagination-nav__sublabel{color:var(--ifm-color-content-secondary);font-size:var(--ifm-h5-font-size);font-weight:var(--ifm-font-weight-semibold);margin-bottom:.25rem}.pills__item,.tabs{font-weight:var(--ifm-font-weight-bold)}.pills{display:flex;gap:var(--ifm-pills-spacing);padding-left:0}.pills__item{border-radius:.5rem;cursor:pointer;display:inline-block;padding:.25rem 1rem;transition:background var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.pills__item--active{color:var(--ifm-pills-color-active)}.pills__item--active,.pills__item:not(.pills__item--active):hover{background:var(--ifm-pills-color-background-active)}.pills--block{justify-content:stretch}.pills--block .pills__item{flex-grow:1;text-align:center}.tabs{color:var(--ifm-tabs-color);display:flex;margin-bottom:0;overflow-x:auto;padding-left:0}.tabs__item{border-bottom:3px solid #0000;border-radius:var(--ifm-global-radius);cursor:pointer;display:inline-flex;padding:var(--ifm-tabs-padding-vertical) var(--ifm-tabs-padding-horizontal);transition:background-color var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.tabs__item--active{border-bottom-color:var(--ifm-tabs-color-active-border);border-bottom-left-radius:0;border-bottom-right-radius:0;color:var(--ifm-tabs-color-active)}.tabs__item:hover{background-color:var(--ifm-hover-overlay)}.tabs--block{justify-content:stretch}.tabs--block .tabs__item{flex-grow:1;justify-content:center}html[data-theme=dark]{--ifm-color-scheme:dark;--ifm-color-emphasis-0:var(--ifm-color-gray-1000);--ifm-color-emphasis-100:var(--ifm-color-gray-900);--ifm-color-emphasis-200:var(--ifm-color-gray-800);--ifm-color-emphasis-300:var(--ifm-color-gray-700);--ifm-color-emphasis-400:var(--ifm-color-gray-600);--ifm-color-emphasis-600:var(--ifm-color-gray-400);--ifm-color-emphasis-700:var(--ifm-color-gray-300);--ifm-color-emphasis-800:var(--ifm-color-gray-200);--ifm-color-emphasis-900:var(--ifm-color-gray-100);--ifm-color-emphasis-1000:var(--ifm-color-gray-0);--ifm-background-color:#1b1b1d;--ifm-background-surface-color:#242526;--ifm-hover-overlay:#ffffff0d;--ifm-color-content:#e3e3e3;--ifm-color-content-secondary:#fff;--ifm-breadcrumb-separator-filter:invert(64%) sepia(11%) saturate(0%) hue-rotate(149deg) brightness(99%) contrast(95%);--ifm-code-background:#ffffff1a;--ifm-scrollbar-track-background-color:#444;--ifm-scrollbar-thumb-background-color:#686868;--ifm-scrollbar-thumb-hover-background-color:#7a7a7a;--ifm-table-stripe-background:#ffffff12;--ifm-toc-border-color:var(--ifm-color-emphasis-200);--ifm-color-primary-contrast-background:#102445;--ifm-color-primary-contrast-foreground:#ebf2fc;--ifm-color-secondary-contrast-background:#474748;--ifm-color-secondary-contrast-foreground:#fdfdfe;--ifm-color-success-contrast-background:#003100;--ifm-color-success-contrast-foreground:#e6f6e6;--ifm-color-info-contrast-background:#193c47;--ifm-color-info-contrast-foreground:#eef9fd;--ifm-color-warning-contrast-background:#4d3800;--ifm-color-warning-contrast-foreground:#fff8e6;--ifm-color-danger-contrast-background:#4b1113;--ifm-color-danger-contrast-foreground:#ffebec;--ifm-background-color:#272b33;--ifm-navbar-background-color:var(--ifm-background-color);--ifm-footer-background-color:var(--ifm-background-color)}#nprogress .bar{background:var(--docusaurus-progress-bar-color);height:2px;top:0;width:100%;z-index:1031}#nprogress .peg{box-shadow:0 0 10px var(--docusaurus-progress-bar-color),0 0 5px var(--docusaurus-progress-bar-color);height:100%;opacity:1;position:absolute;right:0;transform:rotate(3deg) translateY(-4px);width:100px}html{font-family:var(--ofga-font-base);scroll-behavior:smooth}:target:before{content:"";display:block;height:3.75rem;margin:-3.75rem 0 0}body:before{background:linear-gradient(270deg,#d1f4fa,#79ed83 34.37%,#20f1f5 71.35%,#d1f4fa);content:"";height:2px;top:0;width:100vw;z-index:1000}a,a:visited,logo a:active{color:var(--ofga-green-neon);transition:.2s}.container__no-padding{margin:0 auto;width:100%}.navbar{border-bottom:1px solid var(--ofga-neutral-darker);display:flex;height:var(--ifm-navbar-height);justify-content:center}.navbar__brand,.swagger-ui .mr0{margin-right:0}.navbar__logo{height:2.6rem;margin-right:29px;overflow:hidden;transition:.3s ease-in-out;width:42px}.docs-api-page .navbar__logo,.docs-doc-page .navbar__logo,.navbar__logo[data-minimal=false]{width:174px}.navbar__logo img{height:auto;width:174px}.navbar__items{color:var(--ofga-neutral-white);display:flex;font-size:1rem}.documentation-card-box-link_yEiX:hover,.navbar__items a:hover{background-color:unset}.navbar__items--right{grid-gap:.5rem}.navbar__link,.navbar__link:active,.navbar__link:hover,.navbar__link:visited{color:var(--ofga-neutral-light);font-weight:600;transition:.2s}.navbar__link--active{color:var(--ofga-color-white);font-weight:600}.navbar__link:hover,.swagger-ui .o-60{opacity:.6}.navbar__link.header-social{border:1px solid var(--ofga-neutral-white);border-radius:6px;font-size:.75rem;padding:.25rem .5rem}.header-social,.hitTree_kk6K,.social-media-banner-item_bn21{align-items:center;display:flex}.header-social:before{content:"";height:1.125rem;margin-right:.5rem;width:1.125rem}.header-github-link:before,.social-media-banner-github_kjwB:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23fff' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E") no-repeat}.header-twitter-link:before,.social-media-banner-twitter_Se7d:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8l164.9-188.5L26.8 48h145.6l100.5 132.9zm-24.8 373.8h39.1L151.1 88h-42z' style='fill:%23fff'/%3E%3C/svg%3E") no-repeat}.header-slack-link:before,.social-media-banner-cncf-slack_h6wH:before{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 18 18'%3E%3Cpath fill='%23fff' d='M3.781 11.375c0 1.04-.85 1.89-1.89 1.89s-1.892-.85-1.892-1.89.85-1.891 1.891-1.891h1.891zM4.734 11.375c0-1.04.85-1.891 1.89-1.891 1.042 0 1.892.85 1.892 1.89v4.735c0 1.041-.85 1.891-1.891 1.891s-1.891-.85-1.891-1.89zM6.625 3.782c-1.04 0-1.891-.85-1.891-1.89S5.584 0 6.624 0c1.042 0 1.892.85 1.892 1.891v1.891zM6.625 4.735c1.04 0 1.89.85 1.89 1.89s-.85 1.892-1.89 1.892H1.89C.85 8.517 0 7.667 0 6.626s.85-1.891 1.89-1.891zM14.218 6.626c0-1.041.85-1.891 1.89-1.891 1.042 0 1.892.85 1.892 1.89s-.85 1.891-1.891 1.891h-1.891zM13.265 6.626c0 1.04-.85 1.89-1.89 1.89s-1.892-.85-1.892-1.89V1.89c0-1.04.85-1.89 1.891-1.89s1.891.85 1.891 1.89zM11.374 14.218c1.041 0 1.891.85 1.891 1.891S12.415 18 11.375 18s-1.892-.85-1.892-1.89v-1.892zM11.374 13.266c-1.04 0-1.89-.85-1.89-1.891s.85-1.891 1.89-1.891h4.735c1.04 0 1.89.85 1.89 1.89s-.85 1.892-1.89 1.892z'/%3E%3C/svg%3E") no-repeat}.navbar__search{display:flex;grid-gap:1rem}.navbar__search-input{border:1px solid var(--ofga-neutral-light)}.navbar__search-input:focus{border:1px solid var(--ofga-color-primary-dark);outline:2px solid var(--ofga-color-primary)}.navbar__search button{color:var(--ofga-neutral-darkest);cursor:pointer}.menu,.swagger-ui .f6{font-size:.875rem}.menu__list{display:flex;flex-direction:column}.menu__list:not(.theme-doc-sidebar-menu){border-left:1px solid var(--ofga-neutral-dark);margin-left:.7rem}.menu__link,.menu__link:visited:not(.menu__link--active){color:var(--ofga-neutral-base)}.menu__link--active:not(.menu__link--sublist){background-color:initial}a.menu__link--active,a.menu__link:active,a.menu__link:hover{color:var(--ofga-neutral-white)}.menu__caret{align-items:center;display:flex;justify-content:center;left:0;padding:0;position:absolute;top:0}.menu__caret:before,.menu__link--sublist:after{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSI4IiBmaWxsPSJub25lIj48cGF0aCBzdHJva2U9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIxLjUiIGQ9Im0xIDEgNiA2IDYtNiIvPjwvc3ZnPg==) 50% no-repeat;height:1.5rem;min-height:29.5px;min-width:1.5rem;transform:rotate(1turn);width:1.5rem}.menu__link--sublist:after{left:0;position:absolute;top:0}.menu__list-item-collapsible:before{background-position:50%;content:"";height:auto;transition:.3s ease-in-out;width:1.5rem}.menu__list-item--collapsed .menu__caret:before,.menu__list-item--collapsed .menu__link--sublist:after,.swagger-ui .rotate-270{transform:rotate(270deg)}.theme-doc-sidebar-container button{background-color:#32363d}.theme-doc-sidebar-container button:hover{background-color:#3d4148}.theme-doc-sidebar-item-category{margin-bottom:1rem;margin-right:.5rem}.table-of-contents{display:flex;flex-direction:column;font-size:.875rem}.documentation-card-box-links-bold__aiB a,.swagger-ui .fw5,a.table-of-contents__link{font-weight:500}.swagger-ui section h3,a.table-of-contents__link,a.table-of-contents__link:visited{color:var(--ofga-neutral-base)}.documentation-card-box-filled_F0BA .documentation-card-box-description_u7_j,a.table-of-contents__link.table-of-contents__link--active,a.table-of-contents__link:active,a.table-of-contents__link:hover{color:var(--ofga-neutral-white)}.breadcrumbs__link svg,.feature_kx3O a,.feature_kx3O a:active,.feature_kx3O a:hover,.feature_kx3O a:visited,.pagination-nav__label,.swagger-ui .prop-type,.theme-doc-footer a,.theme-doc-footer a:active,.theme-doc-footer a:visited,.theme-doc-markdown a,.theme-doc-markdown a:active,.theme-doc-markdown a:hover,.theme-doc-markdown a:visited{color:var(--ofga-green-neon)}.breadcrumbs__item--active .breadcrumbs__link{color:var(--ofga-green-neon);font-weight:500}.breadcrumbs__link:hover,.theme-doc-footer a:hover{color:var(--ofga-green-dark)}.footer{border-top:1px solid var(--ofga-neutral-darker);height:5.5rem}.footer .container{display:flex;flex-direction:row-reverse;justify-content:space-between;max-width:var(--ifm-container-width-xl)}.footer__links{align-items:center;display:flex;grid-gap:1.125rem;margin:0}.footer__links .header-social:before{height:1.5rem;position:absolute;width:1.5rem}.footer__links .header-social{color:#0000;height:1.5rem;overflow:hidden;width:1.5rem}#__docusaurus-base-url-issue-banner-container,.display-on-desktop,.docSidebarContainer_YfHR,.footer__link-separator,.heroPattern_dn9n,.hideAction_vcyE>svg,.hideOnMobile_oZZF,.navbarSearchContainer_Bca1:empty,.sidebarLogo_isFc,.social-media-banner_EIek,.swagger-ui .Resizer.vertical.disabled,.swagger-ui .checkbox input[type=checkbox],.swagger-ui .dn,.swagger-ui .hidden,.swagger-ui [hidden],.swagger-ui template,.themedComponent_mlkZ,[data-theme=dark] .lightToggleIcon_pyhR,[data-theme=light] .darkToggleIcon_wfgR,html[data-announcement-bar-initially-dismissed=true] .announcementBar_mb4j{display:none}.footer__copyright{align-items:center;color:var(--ofga-neutral-white);display:flex;font-size:.875rem}.pagination-nav__link:hover{background-color:unset;border-color:var(--ofga-green-neon)}.theme-doc-markdown{color:var(--ofga-color-lighter);font-size:1.125rem;font-weight:400}.theme-doc-markdown h1{font-size:3rem;font-weight:600;letter-spacing:1.1px;line-height:3.5rem}.feature_kx3O a:hover,.theme-doc-markdown a:hover,a.buttonLink_MrmQ:hover,pre,pre code{background-color:var(--ofga-neutral-black)}.section_heading{color:var(--ofga-neutral-dark);font-size:.875rem;font-weight:500;margin-bottom:1.5rem}.blue-highlight-text,.green-highlight-text,.yellow-highlight-text{border-radius:2.4px;font-family:Inter;font-size:12px;font-style:normal;font-weight:600;letter-spacing:.8px;line-height:18px;padding:1.2px 7.2px;text-transform:uppercase}.markdown>h1:first-child{margin:2rem 0 3rem}.markdown>h2,.markdown>h3{margin-top:5rem}.markdown ol li:not(:last-of-type),.swagger-ui .pb3{padding-bottom:1rem}.markdown pre{margin:2rem 0}.markdown details{border-radius:24px!important;margin-top:2rem;padding:0}.markdown details summary,.swagger-ui .pa4{padding:2rem}.markdown details summary~div>div{margin:unset;padding:0 2rem}.markdown details summary:before{left:auto;right:1rem;top:1rem;transform:rotate(90deg)}.markdown details[data-collapsed=false]>summary:before{transform:rotate(270deg)!important}.markdown details h3{font-size:1.25rem;letter-spacing:-.1px;line-height:1.625rem;margin:unset;padding:1.5rem 0 1rem}.swagger-ui .f5,pre{font-size:1rem}.language-dsl\.openfga .token.plain{color:var(--ofga-color-default)}.language-dsl\.openfga .token.comment{color:var(--ofga-color-comment)}.language-dsl\.openfga .token.condition-param-type,.language-dsl\.openfga .token.keyword{color:var(--ofga-color-keyword)!important}.language-dsl\.openfga .token.module{color:var(--ofga-color-module)}.language-dsl\.openfga .token.condition,.language-dsl\.openfga .token.type{color:var(--ofga-color-type)}.language-dsl\.openfga .token.condition-param,.language-dsl\.openfga .token.relation{color:var(--ofga-color-relation)}.language-dsl\.openfga .token.directly-assignable{color:var(--ofga-color-directly-assignable)}.language-json .token.string{color:var(--ofga-color-primary)!important}.language-json .token.punctuation{color:var(--ofga-color-secondary)!important}.blue-highlight-text{background:#ddebfd;color:#00407d}.green-highlight-text{background:#def7f1;color:#004e4e}.yellow-highlight-text{background:#fcf7e4;color:#522c09}.heading_OPPZ,.section_sUhq h3{font-family:var(--ofga-font-highlight)}[data-theme=dark]{--ifm-color-primary:#25c2a0;--ifm-color-primary-dark:#21af90;--ifm-color-primary-darker:#1fa588;--ifm-color-primary-darkest:#1a8870;--ifm-color-primary-light:#29d5b0;--ifm-color-primary-lighter:#32d8b4;--ifm-color-primary-lightest:#4fddbf;--docusaurus-highlighted-code-line-bg:#0000004d}.backToTopButton_sjWU{background-color:var(--ifm-color-emphasis-200);border-radius:50%;bottom:1.3rem;box-shadow:var(--ifm-global-shadow-lw);height:3rem;opacity:0;position:fixed;right:1.3rem;transform:scale(0);transition:all var(--ifm-transition-fast) var(--ifm-transition-timing-default);visibility:hidden;width:3rem;z-index:calc(var(--ifm-z-index-fixed) - 1)}.backToTopButton_sjWU:after{background-color:var(--ifm-color-emphasis-1000);content:" ";display:inline-block;height:100%;-webkit-mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;mask:var(--ifm-menu-link-sublist-icon) 50%/2rem 2rem no-repeat;width:100%}.backToTopButtonShow_xfvO{opacity:1;transform:scale(1);visibility:visible}.skipToContent_fXgn{background-color:var(--ifm-background-surface-color);color:var(--ifm-color-emphasis-900);left:100%;padding:calc(var(--ifm-global-spacing)/2) var(--ifm-global-spacing);position:fixed;top:1rem;z-index:calc(var(--ifm-z-index-fixed) + 1)}.skipToContent_fXgn:focus{box-shadow:var(--ifm-global-shadow-md);left:1rem}.closeButton_CVFx{line-height:0;padding:0}.content_knG7{font-size:85%;padding:5px 0;text-align:center}.content_knG7 a{color:inherit}.announcementBar_mb4j{align-items:center;background-color:var(--ifm-color-white);border-bottom:1px solid var(--ifm-color-emphasis-100);color:var(--ifm-color-black);display:flex;height:var(--docusaurus-announcement-bar-height)}.announcementBarPlaceholder_vyr4{flex:0 0 10px}.announcementBarClose_gvF7{align-self:stretch;flex:0 0 30px}.toggle_vylO{height:2rem;width:2rem}.toggleButton_gllP{align-items:center;border-radius:50%;display:flex;height:100%;justify-content:center;transition:background var(--ifm-transition-fast);width:100%}.toggleButton_gllP:hover{background:var(--ifm-color-emphasis-200)}.toggleButtonDisabled_aARS{cursor:not-allowed}.darkNavbarColorModeToggle_X3D1:hover{background:var(--ifm-color-gray-800)}[data-theme=dark] .themedComponent--dark_xIcU,[data-theme=light] .themedComponent--light_NVdE,html:not([data-theme]) .themedComponent--light_NVdE{display:initial}[data-theme=dark]:root{--docusaurus-collapse-button-bg:#ffffff0d;--docusaurus-collapse-button-bg-hover:#ffffff1a}.collapseSidebarButton_PEFL{display:none;margin:0}.iconExternalLink_nPIU{margin-left:.3rem}.docMainContainer_TBSr,.docRoot_UBD9{display:flex;width:100%}.docsWrapper_hBAB{display:flex;flex:1 0 auto}.dropdownNavbarItemMobile_S0Fm,.swagger-ui .pointer:hover,.swagger-ui button,.swagger-ui section.models .pointer{cursor:pointer}.iconLanguage_nlXk{margin-right:5px;vertical-align:text-bottom}.searchBar_RVTs .dropdownMenu_qbY6{background:var(--search-local-modal-background,#f5f6f7);border-radius:6px;box-shadow:var(--search-local-modal-shadow,inset 1px 1px 0 0 #ffffff80,0 3px 8px 0 #555a64);left:auto!important;margin-top:8px;padding:var(--search-local-spacing,12px);position:relative;right:0!important;width:var(--search-local-modal-width,560px)}html[data-theme=dark] .searchBar_RVTs .dropdownMenu_qbY6{background:var(--search-local-modal-background,var(--ifm-background-color));box-shadow:var(--search-local-modal-shadow,inset 1px 1px 0 0 #2c2e40,0 3px 8px 0 #000309)}.searchBar_RVTs .dropdownMenu_qbY6 .suggestion_fB_2{align-items:center;background:var(--search-local-hit-background,#fff);border-radius:4px;box-shadow:var(--search-local-hit-shadow,0 1px 3px 0 #d4d9e1);color:var(--search-local-hit-color,#444950);cursor:pointer;display:flex;flex-direction:row;height:var(--search-local-hit-height,56px);padding:0 var(--search-local-spacing,12px);width:100%}html[data-theme=dark] .dropdownMenu_qbY6 .suggestion_fB_2{background:var(--search-local-hit-background,var(--ifm-color-emphasis-100));box-shadow:var(--search-local-hit-shadow,none);color:var(--search-local-hit-color,var(--ifm-font-color-base))}.documentation-card-box-links_XUmL .documentation-card-box-link_yEiX:not(:last-child),.searchBar_RVTs .dropdownMenu_qbY6 .suggestion_fB_2:not(:last-child){margin-bottom:4px}.searchBar_RVTs .dropdownMenu_qbY6 .suggestion_fB_2.cursor_eG29{background-color:var(--search-local-highlight-color,var(--ifm-color-primary))}.hitFooter_E9YW a,.hitIcon_a7Zy,.hitPath_ieM4,.hitTree_kk6K,.noResultsIcon_EBY5{color:var(--search-local-muted-color,#969faf)}html[data-theme=dark] .hitIcon_a7Zy,html[data-theme=dark] .hitPath_ieM4,html[data-theme=dark] .hitTree_kk6K,html[data-theme=dark] .noResultsIcon_EBY5{color:var(--search-local-muted-color,var(--ifm-color-secondary-darkest))}.hitTree_kk6K>svg{height:var(--search-local-hit-height,56px);opacity:.5;width:24px}.hitIcon_a7Zy,.hitTree_kk6K>svg{stroke-width:var(--search-local-icon-stroke-width,1.4)}.hitAction_NqkB,.hitIcon_a7Zy{height:20px;width:20px}.hitWrapper_sAK8{display:flex;flex:1 1 auto;flex-direction:column;font-weight:500;justify-content:center;margin:0 8px;overflow-x:hidden;width:80%}.hitWrapper_sAK8 mark{background:none;color:var(--search-local-highlight-color,var(--ifm-color-primary))}.hitTitle_vyVt{font-size:.9em}.hitPath_ieM4{font-size:.75em}.hitPath_ieM4,.hitTitle_vyVt{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.noResults_l6Q3{align-items:center;display:flex;flex-direction:column;justify-content:center;padding:var(--search-local-spacing,12px) 0}.noResultsIcon_EBY5{margin-bottom:var(--search-local-spacing,12px)}.hitFooter_E9YW{font-size:.85em;margin-top:var(--search-local-spacing,12px);text-align:center}.buttonCTA_Tyld:hover,.button_S86e:hover,.links_JbSJ a,a.buttonLink_MrmQ,a.buttonLink_MrmQ:hover,a.social-media-banner-item_bn21{-webkit-text-decoration:none;text-decoration:none}.cursor_eG29 .hideAction_vcyE>svg,.swagger-ui .db,.swagger-ui .markdown pre>code,.swagger-ui .opblock-body pre.microlight .headerline,.swagger-ui .prop-enum,.swagger-ui .renderedMarkdown pre>code,.swagger-ui article,.swagger-ui aside,.swagger-ui details,.swagger-ui figcaption,.swagger-ui figure,.swagger-ui footer,.swagger-ui header,.swagger-ui main,.swagger-ui menu,.swagger-ui nav,.swagger-ui section,.tocCollapsibleContent_vkbj a{display:block}.suggestion_fB_2.cursor_eG29,.suggestion_fB_2.cursor_eG29 .hitIcon_a7Zy,.suggestion_fB_2.cursor_eG29 .hitPath_ieM4,.suggestion_fB_2.cursor_eG29 .hitTree_kk6K,.suggestion_fB_2.cursor_eG29 mark{color:var(--search-local-hit-active-color,var(--ifm-color-white))!important}.searchBarContainer_NW3z{margin-left:16px}.searchBarContainer_NW3z .searchBarLoadingRing_YnHq{display:none;left:10px;position:absolute;top:6px}.searchBarContainer_NW3z .searchClearButton_qk4g{background:none;border:none;line-height:1rem;padding:0;position:absolute;right:.8rem;top:50%;transform:translateY(-50%)}.navbar__search,.section_OFtz,.swagger-ui .curl-command,.swagger-ui .highlight-code,.swagger-ui .loading-container .loading,.swagger-ui .opblock .tab-header .tab-item.active h4 span,.swagger-ui .relative{position:relative}.searchIndexLoading_EJ1f .navbar__search-input{background-image:none}.searchHintContainer_Pkmr{align-items:center;display:flex;gap:4px;height:100%;justify-content:center;pointer-events:none;position:absolute;right:10px;top:0}.searchHint_iIMx{background-color:var(--ifm-navbar-search-input-background-color);border:1px solid var(--ifm-color-emphasis-500);box-shadow:inset 0 -1px 0 var(--ifm-color-emphasis-500);color:var(--ifm-navbar-search-input-placeholder-color)}html[dir=rtl] .searchHintContainer_Pkmr{left:10px;right:auto}html[dir=rtl] .searchBarContainer_NW3z .searchClearButton_qk4g{left:.8rem;right:auto}html[dir=rtl] .searchBarContainer_NW3z .searchBarLoadingRing_YnHq{left:auto;right:10px}html[dir=rtl] .navbar__search-input{padding:0 2.25em 0 .5em}.loadingRing_RJI3{display:inline-block;height:20px;opacity:var(--search-local-loading-icon-opacity,.5);position:relative;width:20px}.loadingRing_RJI3 div{animation:1.2s cubic-bezier(.5,0,.5,1) infinite a;border:2px solid var(--search-load-loading-icon-color,var(--ifm-navbar-search-input-color));border-color:var(--search-load-loading-icon-color,var(--ifm-navbar-search-input-color)) #0000 #0000 #0000;border-radius:50%;display:block;height:16px;margin:2px;position:absolute;width:16px}.loadingRing_RJI3 div:first-child{animation-delay:-.45s}.loadingRing_RJI3 div:nth-child(2){animation-delay:-.3s}.loadingRing_RJI3 div:nth-child(3){animation-delay:-.15s}@keyframes a{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.navbarHideable_m1mJ{transition:transform var(--ifm-transition-fast) ease}.navbarHidden_jGov{transform:translate3d(0,calc(-100% - 2px),0)}.errorBoundaryError_a6uf{color:red;white-space:pre-wrap}.errorBoundaryFallback_VBag{color:red;padding:.55rem}.footerLogoLink_BH7S{opacity:.5;transition:opacity var(--ifm-transition-fast) var(--ifm-transition-timing-default)}.footerLogoLink_BH7S:hover,.hash-link:focus,.swagger-ui .o-100,.swagger-ui .shadow-hover:focus:after,.swagger-ui .shadow-hover:hover:after,:hover>.hash-link{opacity:1}.swagger-ui .outline-0,body:not(.navigation-with-keyboard) :not(input):focus{outline:0}.anchorWithStickyNavbar_LWe7{scroll-margin-top:calc(var(--ifm-navbar-height) + .5rem)}.anchorWithHideOnScrollNavbar_WYt5{scroll-margin-top:.5rem}.hash-link{opacity:0;padding-left:.5rem;transition:opacity var(--ifm-transition-fast);-webkit-user-select:none;user-select:none}.hash-link:before{content:"#"}.mainWrapper_z2l0{display:flex;flex:1 0 auto;flex-direction:column}.docusaurus-mt-lg,.markdown>h2,.terminalContainer_peeJ{margin-top:3rem}#__docusaurus,.swagger-ui .min-h-100{min-height:100%}#__docusaurus,.centerColumn_BDle{display:flex;flex-direction:column}.centerColumn_BDle,.swagger-ui .justify-center{justify-content:center}.sidebar_re4s{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 2rem)}.sidebarItemTitle_pO2u{font-size:var(--ifm-h3-font-size);font-weight:var(--ifm-font-weight-bold)}.container_mt6G,.sidebarItemList_Yudw{font-size:.9rem}.sidebarItem__DBe{margin-top:.7rem}.sidebarItemLink_mo7H{color:var(--ifm-font-color-base);display:block}.sidebarItemLinkActive_I1ZP{color:var(--ifm-color-primary)!important}.yearGroupHeading_rMGB{margin-bottom:.4rem;margin-top:1.6rem}.yearGroupHeading_QT03{margin:1rem .75rem .5rem}.searchContextInput_mXoe,.searchQueryInput_CFBF{background:var(--ifm-background-color);border:var(--ifm-global-border-width) solid var(--ifm-color-content-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-font-color-base);font-size:var(--ifm-font-size-base);margin-bottom:1rem;padding:.5rem;width:100%}.searchResultItem_U687{border-bottom:1px solid #dfe3e8;padding:1rem 0}.searchResultItemPath_uIbk{color:var(--ifm-color-content-secondary);font-size:.8rem;margin:.5rem 0 0}.searchResultItemSummary_oZHr{font-style:italic;margin:.5rem 0 0}.container_Xn_q{display:flex;font-size:1.125rem;justify-content:space-between;padding:2rem}.heading_OPPZ{display:flex;flex-direction:column;font-size:6rem;font-weight:600;margin-bottom:2rem}.heading_OPPZ svg{width:20rem}.headingSubtitle_qc__{color:var(--ofga-neutral-white);font-size:1.625rem;line-height:1.16;padding-top:1.5rem}.button_S86e,.button_S86e:hover,.headingDescription_uSbN{color:var(--ofga-neutral-light)}.button_S86e,a.buttonLink_MrmQ{background-color:var(--ofga-neutral-darker);border-radius:12px;display:flex;padding:.5rem 1rem}.headingDescription_uSbN{font-weight:400;margin-bottom:3rem}.buttons_qNcx{align-items:stretch;display:flex;flex-direction:column;justify-content:flex-start;grid-gap:1.5rem}.button_S86e{align-items:center;grid-gap:.5rem}.button_S86e:hover{background-color:var(--ofga-neutral-black);transition:.2s}.buttonCTA_Tyld{background-color:var(--ofga-green-neon);color:var(--ofga-neutral-black);transition:.2s}.buttonCTA_Tyld:hover{color:var(--ofga-green-neon);transition:.2s}a.social-media-banner-item_bn21{color:var(--ofga-neutral-white)}.social-media-banner-item_bn21:before{content:"";display:block;height:2rem;margin-right:.5rem;width:2rem}a.buttonLink_MrmQ{align-items:center;grid-gap:.5rem;font-weight:500;justify-content:center}a.buttonLink_MrmQ,a.buttonLink_MrmQ:hover{color:var(--ofga-neutral-light)}.swagger-ui .errors-wrapper .errors .error-line,.swagger-ui .scopes h2 a,.swagger-ui abbr[title]{-webkit-text-decoration:underline;text-decoration:underline}a.buttonLink_MrmQ svg>*{transition:.2s}a.buttonLinkPrimary__51_{background-color:var(--ofga-green-neon);color:var(--ofga-neutral-black)}a.buttonLinkPrimary__51_ svg>*,a.buttonLinkSecondary_NNVa svg>*{fill:var(--ofga-neutral-black)}a.buttonLinkSecondary_NNVa{background-color:var(--ofga-neutral-base);color:var(--ofga-neutral-black)}.container_Q0_S[data-theme=dark],.container_Q0_S[data-theme=dark] .links_JbSJ a,.container_Q0_S[data-theme=dark] .updates_myNp>:first-child,a.buttonLinkOutlined_NgK9{color:var(--ofga-neutral-lighter)}a.buttonLinkOutlined_NgK9{border:1px solid var(--ofga-neutral-base)}.grid_OmBo{bottom:0;grid-template-columns:1fr 1fr;left:0;margin:0 auto;padding:0;position:absolute;right:0;top:0;z-index:-1;grid-gap:6.25rem;display:none}.grid_OmBo div{border-left:1px solid var(--ofga-neutral-darker);border-right:1px solid var(--ofga-neutral-darker)}.section_VjpN{background-color:var(--ofga-neutral-black);color:var(--ofga-neutral-base);padding:3rem 0 4rem}.container_Q0_S,.links_JbSJ a{color:var(--ofga-neutral-darkest)}.container_bmt1{display:flex;flex-direction:column;justify-content:space-between;padding:0 2rem}.content_APwV p,.swagger-ui .mb3{margin-bottom:1rem}.highlight_WKpk{font-size:1.75rem;font-weight:500;line-height:1.28}.terminalImg_qyMa{max-width:100%;width:100%}.terminal_qwvx svg{height:100%;object-fit:cover;width:100%}.section_VjpN a:hover{background-color:var(--true-black)}.dockerSnippet_ru9D{background-color:#000;flex-grow:1;font-size:.875rem;margin-bottom:0;padding:1rem}.copyQuickstart_nRnP{background:none;border:0;cursor:pointer;display:flex;height:2rem;padding:.25rem;transition:.2s ease-in-out .2s;width:2rem}.container_Q0_S[data-theme=dark],.icon_ip5S{background-color:var(--ofga-neutral-darker)}.copyCodeBlock__2Ng{align-items:center;display:flex;gap:1rem;margin-bottom:2rem}.copyQuickstart_nRnP svg{stroke:var(--ofga-green-neon);transition:.2s ease-in-out}.copyQuickstart_nRnP:hover svg{stroke:var(--ofga-neutral-white);transition:.2s ease-in-out}.copyQuickstart_nRnP[data-copied=true] svg,.copyQuickstart_nRnP[data-copied=true]:hover svg{stroke:#0000}.copyQuickstart_nRnP[data-copied=true],.swagger-ui .ml5{margin-left:4rem}.copyQuickstart_nRnP[data-copied=true]:after{color:var(--ofga-green-neon);content:"copied ✓";font-family:courier;font-size:1rem;line-height:1.875rem;margin-left:-7.5rem;text-align:right;width:7.5rem}.copyQuickstart_nRnP[data-copied=false]:hover{margin-left:4rem;transition:.2s ease-in-out}.copyQuickstart_nRnP[data-copied=false]:before{color:var(--ofga-neutral-white);content:"copy";font-family:courier;font-size:1rem;line-height:1.875rem;margin-left:-9rem;margin-right:1rem;opacity:0;text-align:right;transition:.2s ease-in-out;width:8rem}.swagger-ui .link,.swagger-ui .link:active,.swagger-ui .link:focus,.swagger-ui .link:hover,.swagger-ui .link:link,.swagger-ui .link:visited,.swagger-ui .nested-links a{transition:color .15s ease-in}.copyQuickstart_nRnP[data-copied=false]:hover:before{opacity:1;transition:.2s ease-in-out}.section_sUhq{padding:3rem 0}.section_sUhq h2,.swagger-ui .ml4{margin-left:2rem}.section_sUhq h3{font-size:2rem;font-weight:500;letter-spacing:-.2px;line-height:1.25}.grid_f5pM{display:grid;grid-template-columns:1fr;grid-gap:3rem}.icon_ip5S{align-items:center;border-radius:8px;display:flex;height:3rem;justify-content:center;width:3rem}.authorSocialIcon_XYv3,.authorSocialLink_owbf{width:var(--docusaurus-blog-social-icon-size)}.feature_kx3O{display:grid;grid-template-rows:auto auto 1fr;grid-gap:1.5rem;padding:0 2rem}.sectionContainer_yxUZ{padding-bottom:10rem}.container_Q0_S{background-color:var(--ofga-neutral-aluminium);border-radius:8px;display:grid;height:auto;overflow:hidden;padding:0 3rem}.container_Q0_S>div{align-items:stretch;display:grid;grid-template-rows:1fr}.mainArea_jMsm,.swagger-ui .pl3{padding-left:1rem}.mainArea_jMsm h2{font-size:1.75rem;font-weight:500;line-height:1.3;margin:3rem 4rem 3rem 0}.heading_PV1J{grid-row-end:3;grid-row-start:1}.links_JbSJ{display:grid;grid-row-end:8;grid-row-start:3;list-style:none;margin-bottom:2.5rem;padding-left:0}.links_JbSJ li{align-items:center;display:flex;grid-gap:.875rem;margin-bottom:1rem}.links_JbSJ li svg{height:24px;width:24px}.links_JbSJ a{font-weight:500;padding:2px 8px}.updates_myNp>*{align-items:center;border-top:1px solid var(--ofga-neutral-dark);display:flex;padding-left:3rem}.container_Q0_S[data-theme=dark] .updates_myNp>*{border-top:1px solid var(--ofga-neutral-black)}.container_Q0_S .updates_myNp>:first-child{border-top:none;color:var(--ofga-neutral-black);font-size:1.25rem;font-weight:500;grid-row-end:4;grid-row-start:1}.update_M3NR{display:flex;grid-gap:.75rem;font-weight:500}[data-theme=dark] .githubSvg_Uu4N,[data-theme=dark] .xSvg_y3PF{fill:var(--light)}[data-theme=light] .githubSvg_Uu4N,[data-theme=light] .xSvg_y3PF{fill:var(--dark)}.authorSocials_rSDt{align-items:center;display:flex;flex-wrap:wrap;overflow:hidden;line-clamp:1;-webkit-line-clamp:1;-webkit-box-orient:vertical}.authorSocialLink_owbf,.authorSocials_rSDt{height:var(--docusaurus-blog-social-icon-size);line-height:0}.authorSocialLink_owbf{margin-right:.4rem}.authorSocialIcon_XYv3{height:var(--docusaurus-blog-social-icon-size)}.authorImage_XqGP{--ifm-avatar-photo-size:3.6rem}.author-as-h1_n9oJ .authorImage_XqGP{--ifm-avatar-photo-size:7rem}.author-as-h2_gXvM .authorImage_XqGP{--ifm-avatar-photo-size:5.4rem}.authorDetails_lV9A{align-items:flex-start;display:flex;flex-direction:column;justify-content:space-around}.authorName_yefp{display:flex;flex-direction:row;font-size:1.1rem;line-height:1.1rem}.author-as-h1_n9oJ .authorName_yefp{display:inline;font-size:2.4rem;line-height:2.4rem}.author-as-h2_gXvM .authorName_yefp{display:inline;font-size:1.4rem;line-height:1.4rem}.authorTitle_nd0D{display:-webkit-box;font-size:.8rem;line-height:1rem;overflow:hidden;line-clamp:1;-webkit-line-clamp:1;-webkit-box-orient:vertical}.author-as-h1_n9oJ .authorTitle_nd0D{font-size:1.2rem;line-height:1.6rem}.author-as-h2_gXvM .authorTitle_nd0D{font-size:1rem;line-height:1.3rem}.authorBlogPostCount_iiJ5{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.8rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.authorListItem_n3yI{margin-bottom:2rem}.authorCol_Hf19{max-width:inherit!important}.imageOnlyAuthorRow_pa_O{display:flex;flex-flow:row wrap}.imageOnlyAuthorCol_G86a{margin-left:.3rem;margin-right:.3rem}.swagger-ui,.swagger-ui .info h1,.swagger-ui .info h2,.swagger-ui .info h3,.swagger-ui .info h4,.swagger-ui .info h5{color:var(--ifm-color-primary-contrast-foreground)}.swagger-ui,.swagger-ui .sans-serif,.swagger-ui h1,.swagger-ui h2,.swagger-ui h3,.swagger-ui h4,.swagger-ui h5,.swagger-ui h6{font-family:var(--ofga-font-base)}.swagger-ui html{-ms-text-size-adjust:100%;line-height:1.15}.swagger-ui h1{font-size:2em;margin:.67em 0}.swagger-ui figure{margin:1em 40px}.swagger-ui hr{box-sizing:initial;height:0;overflow:visible}.swagger-ui code,.swagger-ui kbd,.swagger-ui pre,.swagger-ui samp{font-family:monospace,monospace;font-size:1em}.swagger-ui a{-webkit-text-decoration-skip:objects;background-color:initial}.swagger-ui abbr[title]{border-bottom:none;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.swagger-ui b,.swagger-ui strong{font-weight:bolder}.swagger-ui mark{background-color:#ff0;color:#000}.swagger-ui small{font-size:80%}.swagger-ui sub,.swagger-ui sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}.swagger-ui sub{bottom:-.25em}.swagger-ui sup{top:-.5em}.swagger-ui audio:not([controls]){display:none;height:0}.swagger-ui img{border-style:none;max-width:100%}.swagger-ui .overflow-hidden,.swagger-ui svg:not(:root){overflow:hidden}.swagger-ui button,.swagger-ui input,.swagger-ui optgroup,.swagger-ui select,.swagger-ui textarea{color:var(--ifm-color-primary-contrast-foreground);font-family:var(--ofga-font-base);font-size:100%;line-height:1.15;margin:0}.swagger-ui .overflow-visible,.swagger-ui button,.swagger-ui input{overflow:visible}.admonitionHeading_Gvgb code,.swagger-ui .ttn,.swagger-ui button,.swagger-ui select{text-transform:none}.swagger-ui [type=reset],.swagger-ui [type=submit],.swagger-ui button,.swagger-ui html [type=button]{-webkit-appearance:button}.swagger-ui [type=button]::-moz-focus-inner,.swagger-ui [type=reset]::-moz-focus-inner,.swagger-ui [type=submit]::-moz-focus-inner,.swagger-ui button::-moz-focus-inner{border-style:none;padding:0}.swagger-ui [type=button]:-moz-focusring,.swagger-ui [type=reset]:-moz-focusring,.swagger-ui [type=submit]:-moz-focusring,.swagger-ui button:-moz-focusring{outline:ButtonText dotted 1px}.swagger-ui fieldset{padding:.35em .75em .625em}.swagger-ui [type=checkbox],.swagger-ui [type=radio],.swagger-ui legend{padding:0;box-sizing:border-box}.swagger-ui legend{color:inherit;display:table;max-width:100%}.swagger-ui progress{display:inline-block}.swagger-ui [type=number]::-webkit-inner-spin-button,.swagger-ui [type=number]::-webkit-outer-spin-button{height:auto}.swagger-ui [type=search]{-webkit-appearance:textfield;outline-offset:-2px}.swagger-ui [type=search]::-webkit-search-cancel-button,.swagger-ui [type=search]::-webkit-search-decoration{-webkit-appearance:none}.swagger-ui ::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.swagger-ui summary{display:list-item}.swagger-ui .debug *{outline:gold solid 1px}.swagger-ui .debug-white *{outline:#fff solid 1px}.swagger-ui .debug-black *{outline:#000 solid 1px}.swagger-ui .debug-grid{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) #0000}.swagger-ui .debug-grid-16{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODYyRjhERDU2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODYyRjhERDQ2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QTY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3QjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvCS01IAAABMSURBVHjaYmR4/5+BFPBfAMFm/MBgx8RAGWCn1AAmSg34Q6kBDKMGMDCwICeMIemF/5QawEipAWwUhwEjMDvbAWlWkvVBwu8vQIABAEwBCph8U6c0AAAAAElFTkSuQmCC) #0000}.swagger-ui .debug-grid-8-solid{background:url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAAAAD/4QMxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzExMSA3OS4xNTgzMjUsIDIwMTUvMDkvMTAtMDE6MTA6MjAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIxMjI0OTczNjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIxMjI0OTc0NjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjEyMjQ5NzE2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjEyMjQ5NzI2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAbGhopHSlBJiZBQi8vL0JHPz4+P0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHAR0pKTQmND8oKD9HPzU/R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0f/wAARCAAIAAgDASIAAhEBAxEB/8QAWQABAQAAAAAAAAAAAAAAAAAAAAYBAQEAAAAAAAAAAAAAAAAAAAIEEAEBAAMBAAAAAAAAAAAAAAABADECA0ERAAEDBQAAAAAAAAAAAAAAAAARITFBUWESIv/aAAwDAQACEQMRAD8AoOnTV1QTD7JJshP3vSM3P//Z) #fff}.swagger-ui .debug-grid-16-solid{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzY3MkJEN0U2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzY3MkJEN0Y2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3RDY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pve6J3kAAAAzSURBVHjaYvz//z8D0UDsMwMjSRoYP5Gq4SPNbRjVMEQ1fCRDg+in/6+J1AJUxsgAEGAA31BAJMS0GYEAAAAASUVORK5CYII=) #fff}.swagger-ui .bg-bottom,.swagger-ui .bg-center,.swagger-ui .bg-left,.swagger-ui .bg-right,.swagger-ui .bg-top{background-repeat:no-repeat}.swagger-ui .aspect-ratio{height:0;position:relative}.swagger-ui .aspect-ratio--16x9{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1{padding-bottom:100%}.swagger-ui .aspect-ratio--object{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%;z-index:100}.swagger-ui .cover{background-size:cover!important}.swagger-ui .contain{background-size:contain!important}.swagger-ui .bg-center{background-position:50%}.swagger-ui .bg-top{background-position:top}.swagger-ui .bg-right{background-position:100%}.swagger-ui .bg-bottom{background-position:bottom}.swagger-ui .bg-left{background-position:0}.swagger-ui .outline{outline:solid 1px}.swagger-ui .outline-transparent{outline:#0000 solid 1px}.swagger-ui .ba{border-style:solid;border-width:1px}.swagger-ui .bt{border-top-style:solid;border-top-width:1px}.swagger-ui .br{border-right-style:solid;border-right-width:1px}.swagger-ui .bb{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl{border-left-style:solid;border-left-width:1px}.swagger-ui .bn{border-style:none;border-width:0}.swagger-ui .b--black{border-color:#000}.swagger-ui .b--near-black{border-color:#111}.swagger-ui .b--dark-gray{border-color:#333}.swagger-ui .b--mid-gray{border-color:#555}.swagger-ui .b--gray{border-color:#777}.swagger-ui .b--silver{border-color:#999}.swagger-ui .b--light-silver{border-color:#aaa}.swagger-ui .b--moon-gray{border-color:#ccc}.swagger-ui .b--light-gray{border-color:#eee}.swagger-ui .b--near-white{border-color:#f4f4f4}.swagger-ui .b--white{border-color:#fff}.swagger-ui .b--white-90{border-color:#ffffffe6}.swagger-ui .b--white-80{border-color:#fffc}.swagger-ui .b--white-70{border-color:#ffffffb3}.swagger-ui .b--white-60{border-color:#fff9}.swagger-ui .b--white-50{border-color:#ffffff80}.swagger-ui .b--white-40{border-color:#fff6}.swagger-ui .b--white-30{border-color:#ffffff4d}.swagger-ui .b--white-20{border-color:#fff3}.swagger-ui .b--white-10{border-color:#ffffff1a}.swagger-ui .b--white-05{border-color:#ffffff0d}.swagger-ui .b--white-025{border-color:hsla(0,0%,100%,.025)}.swagger-ui .b--white-0125{border-color:hsla(0,0%,100%,.013)}.swagger-ui .b--black-90{border-color:#000000e6}.swagger-ui .b--black-80{border-color:#000c}.swagger-ui .b--black-70{border-color:#000000b3}.swagger-ui .b--black-60{border-color:#0009}.swagger-ui .b--black-50{border-color:#00000080}.swagger-ui .b--black-40{border-color:#0006}.swagger-ui .b--black-30{border-color:#0000004d}.swagger-ui .b--black-20{border-color:#0003}.swagger-ui .b--black-10{border-color:#0000001a}.swagger-ui .b--black-05{border-color:#0000000d}.swagger-ui .b--black-025{border-color:rgba(0,0,0,.025)}.swagger-ui .b--black-0125{border-color:rgba(0,0,0,.013)}.swagger-ui .b--dark-red{border-color:#e7040f}.swagger-ui .b--red{border-color:#ff4136}.swagger-ui .b--light-red{border-color:#ff725c}.swagger-ui .b--orange{border-color:#ff6300}.swagger-ui .b--gold{border-color:#ffb700}.swagger-ui .b--yellow{border-color:gold}.swagger-ui .b--light-yellow{border-color:#fbf1a9}.swagger-ui .b--purple{border-color:#5e2ca5}.swagger-ui .b--light-purple{border-color:#a463f2}.swagger-ui .b--dark-pink{border-color:#d5008f}.swagger-ui .b--hot-pink{border-color:#ff41b4}.swagger-ui .b--pink{border-color:#ff80cc}.swagger-ui .b--light-pink{border-color:#ffa3d7}.swagger-ui .b--dark-green{border-color:#137752}.swagger-ui .b--green{border-color:#19a974}.swagger-ui .b--light-green{border-color:#9eebcf}.swagger-ui .b--navy{border-color:#001b44}.swagger-ui .b--dark-blue{border-color:#00449e}.swagger-ui .b--blue{border-color:#357edd}.swagger-ui .b--light-blue{border-color:#96ccff}.swagger-ui .b--lightest-blue{border-color:#cdecff}.swagger-ui .b--washed-blue{border-color:#f6fffe}.swagger-ui .b--washed-green{border-color:#e8fdf5}.swagger-ui .b--washed-yellow{border-color:#fffceb}.swagger-ui .b--washed-red{border-color:#ffdfdf}.swagger-ui .b--transparent,.swagger-ui .opblock.opblock-post,.swagger-ui .opblock.opblock-post .opblock-summary,.swagger-ui .opblock.opblock-put,.swagger-ui .opblock.opblock-put .opblock-summary{border-color:#0000}.swagger-ui .b--inherit{border-color:inherit}.swagger-ui .br0{border-radius:0}.swagger-ui .br1{border-radius:.125rem}.swagger-ui .br2{border-radius:.25rem}.swagger-ui .br3{border-radius:.5rem}.swagger-ui .br4{border-radius:1rem}.swagger-ui .br-100{border-radius:100%}.swagger-ui .br-pill{border-radius:9999px}.codeBlockTitle_Ktv7+.codeBlockContent_biex .codeBlock_bY9V,.swagger-ui .br--bottom{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right{border-bottom-left-radius:0;border-top-left-radius:0}.swagger-ui .br--left{border-bottom-right-radius:0;border-top-right-radius:0}.swagger-ui .b--dotted{border-style:dotted}.swagger-ui .b--dashed{border-style:dashed}.swagger-ui .b--solid{border-style:solid}.swagger-ui .b--none{border-style:none}.swagger-ui .bw0{border-width:0}.swagger-ui .bw1{border-width:.125rem}.swagger-ui .bw2{border-width:.25rem}.swagger-ui .bw3{border-width:.5rem}.swagger-ui .bw4{border-width:1rem}.swagger-ui .bw5{border-width:2rem}.swagger-ui .bt-0{border-top-width:0}.swagger-ui .br-0{border-right-width:0}.swagger-ui .bb-0{border-bottom-width:0}.swagger-ui .bl-0{border-left-width:0}.swagger-ui .shadow-1{box-shadow:0 0 4px 2px #0003}.swagger-ui .shadow-2{box-shadow:0 0 8px 2px #0003}.swagger-ui .shadow-3{box-shadow:2px 2px 4px 2px #0003}.swagger-ui .shadow-4{box-shadow:2px 2px 8px 0 #0003}.swagger-ui .shadow-5{box-shadow:4px 4px 8px 0 #0003}.swagger-ui .pre{overflow-x:auto;overflow-y:hidden;overflow:scroll}.swagger-ui .top-0{top:0}.swagger-ui .right-0{right:0}.swagger-ui .bottom-0{bottom:0}.swagger-ui .left-0{left:0}.swagger-ui .top-1{top:1rem}.swagger-ui .right-1{right:1rem}.swagger-ui .bottom-1{bottom:1rem}.swagger-ui .left-1{left:1rem}.swagger-ui .top-2{top:2rem}.swagger-ui .right-2{right:2rem}.swagger-ui .bottom-2{bottom:2rem}.swagger-ui .left-2{left:2rem}.swagger-ui .top--1{top:-1rem}.swagger-ui .right--1{right:-1rem}.swagger-ui .bottom--1{bottom:-1rem}.swagger-ui .left--1{left:-1rem}.swagger-ui .top--2{top:-2rem}.swagger-ui .right--2{right:-2rem}.swagger-ui .bottom--2{bottom:-2rem}.swagger-ui .left--2{left:-2rem}.swagger-ui .absolute--fill{bottom:0;left:0;right:0;top:0}.swagger-ui .cf:after,.swagger-ui .cf:before{content:" ";display:table}.swagger-ui .cl{clear:left}.swagger-ui .cr{clear:right}.swagger-ui .cn{clear:none}.swagger-ui .flex-auto{flex:1 1 auto;min-height:0;min-width:0}.swagger-ui .flex-none{flex:none}.swagger-ui .flex-column{flex-direction:column}.swagger-ui .flex-row{flex-direction:row}.swagger-ui .flex-wrap{flex-wrap:wrap}.swagger-ui .flex-nowrap{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse{flex-direction:column-reverse}.swagger-ui .flex-row-reverse{flex-direction:row-reverse}.swagger-ui .self-start{align-self:flex-start}.swagger-ui .self-end{align-self:flex-end}.swagger-ui .self-center{align-self:center}.swagger-ui .self-baseline{align-self:baseline}.swagger-ui .self-stretch{align-self:stretch}.swagger-ui .justify-start{justify-content:flex-start}.swagger-ui .justify-end{justify-content:flex-end}.swagger-ui .justify-between{justify-content:space-between}.swagger-ui .justify-around{justify-content:space-around}.swagger-ui .content-start{align-content:flex-start}.swagger-ui .content-end{align-content:flex-end}.swagger-ui .content-center{align-content:center}.swagger-ui .content-between{align-content:space-between}.swagger-ui .content-around{align-content:space-around}.swagger-ui .content-stretch{align-content:stretch}.swagger-ui .order-0{order:0}.swagger-ui .order-1{order:1}.swagger-ui .order-2{order:2}.swagger-ui .order-3{order:3}.swagger-ui .order-4{order:4}.swagger-ui .order-5{order:5}.swagger-ui .order-6{order:6}.swagger-ui .order-7{order:7}.swagger-ui .order-8{order:8}.swagger-ui .order-last{order:99999}.swagger-ui .flex-grow-0{flex-grow:0}.swagger-ui .flex-shrink-0{flex-shrink:0}.swagger-ui .flex-shrink-1{flex-shrink:1}.swagger-ui .di,.swagger-ui a.nostyle,.tags_jXut{display:inline}.swagger-ui .dit{display:inline-table}.swagger-ui .dt{display:table}.swagger-ui .dtc{display:table-cell}.swagger-ui .dt-row{display:table-row}.swagger-ui .dt-row-group{display:table-row-group}.swagger-ui .dt-column{display:table-column}.swagger-ui .dt-column-group{display:table-column-group}.swagger-ui .dt--fixed{table-layout:fixed;width:100%}.swagger-ui .fl{float:left}.swagger-ui .float-right,.swagger-ui .fr{float:right}.swagger-ui .fn{float:none}.swagger-ui .serif{font-family:georgia,serif}.swagger-ui .system-serif{font-family:serif}.swagger-ui .code,.swagger-ui code{font-family:Consolas,monaco,monospace}.swagger-ui .courier{font-family:Courier Next,courier,monospace}.swagger-ui .fs-normal{font-style:normal}.swagger-ui .fw4,.swagger-ui .normal,.swagger-ui .opblock-link{font-weight:400}.swagger-ui .b,.swagger-ui .fw7,.swagger-ui .opblock-link.shown,.swagger-ui .tab li.active,.swagger-ui table.model tr.description td:first-child,.swagger-ui table.model tr.property-row.required td:first-child{font-weight:700}.swagger-ui .fw1{font-weight:100}.swagger-ui .fw2{font-weight:200}.swagger-ui .fw3{font-weight:300}.swagger-ui .brace-close,.swagger-ui .brace-open,.swagger-ui .fw6{font-weight:600}.swagger-ui .fw8{font-weight:800}.swagger-ui .fw9{font-weight:900}.swagger-ui .input-reset{-webkit-appearance:none;-moz-appearance:none}.swagger-ui .button-reset::-moz-focus-inner,.swagger-ui .input-reset::-moz-focus-inner{border:0;padding:0}.swagger-ui .h1{height:1rem}.swagger-ui .h2{height:2rem}.swagger-ui .h3{height:4rem}.swagger-ui .h4{height:8rem}.swagger-ui .h5{height:16rem}.swagger-ui .h-25{height:25%}.swagger-ui .h-50{height:50%}.swagger-ui .h-75{height:75%}.swagger-ui .vh-25{height:25vh}.swagger-ui .vh-50{height:50vh}.swagger-ui .vh-75{height:75vh}.swagger-ui .vh-100{height:100vh}.swagger-ui .min-vh-100{min-height:100vh}.img_ev3q,.swagger-ui .h-auto{height:auto}.swagger-ui .h-inherit{height:inherit}.swagger-ui .tracked{letter-spacing:.1em}.swagger-ui .tracked-tight{letter-spacing:-.05em}.swagger-ui .tracked-mega{letter-spacing:.25em}.swagger-ui .lh-solid{line-height:1}.swagger-ui .lh-title,.swagger-ui .nested-headline-line-height h1,.swagger-ui .nested-headline-line-height h2,.swagger-ui .nested-headline-line-height h3,.swagger-ui .nested-headline-line-height h4,.swagger-ui .nested-headline-line-height h5,.swagger-ui .nested-headline-line-height h6{line-height:1.25}.swagger-ui .lh-copy,.swagger-ui .nested-copy-line-height ol,.swagger-ui .nested-copy-line-height p,.swagger-ui .nested-copy-line-height ul{line-height:1.5}.swagger-ui .link:focus{outline:currentColor dotted 1px}.swagger-ui .mw1{max-width:1rem}.swagger-ui .mw2{max-width:2rem}.swagger-ui .mw3{max-width:4rem}.swagger-ui .mw4{max-width:8rem}.swagger-ui .mw5{max-width:16rem}.swagger-ui .mw6{max-width:32rem}.swagger-ui .mw7{max-width:48rem}.swagger-ui .mw8{max-width:64rem}.swagger-ui .mw9{max-width:96rem}.swagger-ui .mw-none{max-width:none}.swagger-ui .w1{width:1rem}.swagger-ui .w2{width:2rem}.swagger-ui .w3{width:4rem}.swagger-ui .w4{width:8rem}.swagger-ui .w5{width:16rem}.swagger-ui .w-10{width:10%}.swagger-ui .w-20{width:20%}.swagger-ui .w-25{width:25%}.swagger-ui .w-30{width:30%}.swagger-ui .w-33{width:33%}.swagger-ui .w-34{width:34%}.swagger-ui .w-40{width:40%}.swagger-ui .w-50{width:50%}.swagger-ui .w-60{width:60%}.swagger-ui .w-70{width:70%}.swagger-ui .w-75{width:75%}.swagger-ui .w-80{width:80%}.swagger-ui .w-90{width:90%}.swagger-ui .examples-select .examples-select-element,.swagger-ui .inner-object,.swagger-ui .w-100{width:100%}.swagger-ui .w-third{width:33.3333333333%}.swagger-ui .w-two-thirds{width:66.6666666667%}.swagger-ui .w-auto{width:auto}.swagger-ui .overflow-scroll{overflow:scroll}.swagger-ui .overflow-auto{overflow:auto}.swagger-ui .overflow-x-visible{overflow-x:visible}.swagger-ui .overflow-x-hidden{overflow-x:hidden}.swagger-ui .overflow-x-scroll{overflow-x:scroll}.swagger-ui .overflow-x-auto{overflow-x:auto}.swagger-ui .overflow-y-visible{overflow-y:visible}.swagger-ui .overflow-y-hidden{overflow-y:hidden}.swagger-ui .overflow-container,.swagger-ui .overflow-y-scroll{overflow-y:scroll}.swagger-ui .overflow-y-auto{overflow-y:auto}.swagger-ui .static{position:static}.swagger-ui .absolute{position:absolute}.swagger-ui .fixed{position:fixed}.swagger-ui .o-90{opacity:.9}.swagger-ui .model-box.deprecated,.swagger-ui .o-50{opacity:.5}.swagger-ui .o-40{opacity:.4}.swagger-ui .o-30{opacity:.3}.swagger-ui .o-20{opacity:.2}.swagger-ui .o-10{opacity:.1}.swagger-ui .o-05{opacity:.05}.swagger-ui .o-025{opacity:.025}.swagger-ui .o-0{opacity:0}.swagger-ui .rotate-45{transform:rotate(45deg)}.details_lb9f[data-collapsed=false].isBrowser_bmU9>summary:before,.details_lb9f[open]:not(.isBrowser_bmU9)>summary:before,.swagger-ui .rotate-90{transform:rotate(90deg)}.swagger-ui .rotate-135{transform:rotate(135deg)}.swagger-ui .rotate-180{transform:rotate(180deg)}.swagger-ui .rotate-225{transform:rotate(225deg)}.swagger-ui .rotate-315{transform:rotate(315deg)}.swagger-ui .grow,.swagger-ui .grow-large{-moz-osx-font-smoothing:grayscale;transform:translateZ(0);backface-visibility:hidden}.swagger-ui .black-90,.swagger-ui .hover-black-90:focus,.swagger-ui .hover-black-90:hover{color:#000000e6}.swagger-ui .black-80,.swagger-ui .hover-black-80:focus,.swagger-ui .hover-black-80:hover{color:#000c}.swagger-ui .black-70,.swagger-ui .hover-black-70:focus,.swagger-ui .hover-black-70:hover{color:#000000b3}.swagger-ui .black-60,.swagger-ui .hover-black-60:focus,.swagger-ui .hover-black-60:hover{color:#0009}.swagger-ui .black-50,.swagger-ui .hover-black-50:focus,.swagger-ui .hover-black-50:hover{color:#00000080}.swagger-ui .black-40,.swagger-ui .hover-black-40:focus,.swagger-ui .hover-black-40:hover{color:#0006}.swagger-ui .black-30,.swagger-ui .hover-black-30:focus,.swagger-ui .hover-black-30:hover{color:#0000004d}.swagger-ui .black-20,.swagger-ui .hover-black-20:focus,.swagger-ui .hover-black-20:hover{color:#0003}.swagger-ui .black-10,.swagger-ui .hover-black-10:focus,.swagger-ui .hover-black-10:hover{color:#0000001a}.swagger-ui .black-05{color:#0000000d}.swagger-ui .hover-white-90:focus,.swagger-ui .hover-white-90:hover,.swagger-ui .white-90{color:#ffffffe6}.swagger-ui .hover-white-80:focus,.swagger-ui .hover-white-80:hover,.swagger-ui .white-80{color:#fffc}.swagger-ui .hover-white-70:focus,.swagger-ui .hover-white-70:hover,.swagger-ui .white-70{color:#ffffffb3}.swagger-ui .hover-white-60:focus,.swagger-ui .hover-white-60:hover,.swagger-ui .white-60{color:#fff9}.swagger-ui .hover-white-50:focus,.swagger-ui .hover-white-50:hover,.swagger-ui .white-50{color:#ffffff80}.swagger-ui .hover-white-40:focus,.swagger-ui .hover-white-40:hover,.swagger-ui .white-40{color:#fff6}.swagger-ui .hover-white-30:focus,.swagger-ui .hover-white-30:hover,.swagger-ui .white-30{color:#ffffff4d}.swagger-ui .hover-white-20:focus,.swagger-ui .hover-white-20:hover,.swagger-ui .white-20{color:#fff3}.swagger-ui .hover-white-10:focus,.swagger-ui .hover-white-10:hover,.swagger-ui .white-10{color:#ffffff1a}.swagger-ui .black,.swagger-ui .hover-black:focus,.swagger-ui .hover-black:hover{color:#000}.swagger-ui .hover-near-black:focus,.swagger-ui .hover-near-black:hover,.swagger-ui .near-black{color:#111}.swagger-ui .dark-gray,.swagger-ui .hover-dark-gray:focus,.swagger-ui .hover-dark-gray:hover{color:#333}.swagger-ui .hover-mid-gray:focus,.swagger-ui .hover-mid-gray:hover,.swagger-ui .mid-gray,.swagger-ui span.token-string{color:#555}.swagger-ui .gray,.swagger-ui .hover-gray:focus,.swagger-ui .hover-gray:hover,.swagger-ui table.model tr.extension{color:#777}.swagger-ui .hover-silver:focus,.swagger-ui .hover-silver:hover,.swagger-ui .silver{color:#999}.swagger-ui .download-url-wrapper .loading,.swagger-ui .filter .loading,.swagger-ui .hover-light-silver:focus,.swagger-ui .hover-light-silver:hover,.swagger-ui .light-silver{color:#aaa}.swagger-ui .hover-moon-gray:focus,.swagger-ui .hover-moon-gray:hover,.swagger-ui .moon-gray{color:#ccc}.swagger-ui .hover-light-gray:focus,.swagger-ui .hover-light-gray:hover,.swagger-ui .light-gray{color:#eee}.swagger-ui .hover-near-white:focus,.swagger-ui .hover-near-white:hover,.swagger-ui .near-white{color:#f4f4f4}.swagger-ui .hover-white:focus,.swagger-ui .hover-white:hover,.swagger-ui .white{color:#fff}.swagger-ui .dark-red,.swagger-ui .hover-dark-red:focus,.swagger-ui .hover-dark-red:hover{color:#e7040f}.swagger-ui .hover-red:focus,.swagger-ui .hover-red:hover,.swagger-ui .red{color:#ff4136}.swagger-ui .hover-light-red:focus,.swagger-ui .hover-light-red:hover,.swagger-ui .light-red{color:#ff725c}.swagger-ui .hover-orange:focus,.swagger-ui .hover-orange:hover,.swagger-ui .orange{color:#ff6300}.swagger-ui .gold,.swagger-ui .hover-gold:focus,.swagger-ui .hover-gold:hover{color:#ffb700}.swagger-ui .hover-yellow:focus,.swagger-ui .hover-yellow:hover,.swagger-ui .yellow{color:gold}.swagger-ui .hover-light-yellow:focus,.swagger-ui .hover-light-yellow:hover,.swagger-ui .light-yellow{color:#fbf1a9}.swagger-ui .hover-purple:focus,.swagger-ui .hover-purple:hover,.swagger-ui .purple{color:#5e2ca5}.swagger-ui .hover-light-purple:focus,.swagger-ui .hover-light-purple:hover,.swagger-ui .light-purple{color:#a463f2}.swagger-ui .dark-pink,.swagger-ui .hover-dark-pink:focus,.swagger-ui .hover-dark-pink:hover{color:#d5008f}.swagger-ui .hot-pink,.swagger-ui .hover-hot-pink:focus,.swagger-ui .hover-hot-pink:hover{color:#ff41b4}.swagger-ui .hover-pink:focus,.swagger-ui .hover-pink:hover,.swagger-ui .pink{color:#ff80cc}.swagger-ui .hover-light-pink:focus,.swagger-ui .hover-light-pink:hover,.swagger-ui .light-pink{color:#ffa3d7}.swagger-ui .dark-green,.swagger-ui .hover-dark-green:focus,.swagger-ui .hover-dark-green:hover{color:#137752}.swagger-ui .green,.swagger-ui .hover-green:focus,.swagger-ui .hover-green:hover{color:#19a974}.swagger-ui .hover-light-green:focus,.swagger-ui .hover-light-green:hover,.swagger-ui .light-green{color:#9eebcf}.swagger-ui .hover-navy:focus,.swagger-ui .hover-navy:hover,.swagger-ui .navy{color:#001b44}.swagger-ui .dark-blue,.swagger-ui .hover-dark-blue:focus,.swagger-ui .hover-dark-blue:hover{color:#00449e}.swagger-ui .blue,.swagger-ui .hover-blue:focus,.swagger-ui .hover-blue:hover{color:#357edd}.swagger-ui .hover-light-blue:focus,.swagger-ui .hover-light-blue:hover,.swagger-ui .light-blue{color:#96ccff}.swagger-ui .hover-lightest-blue:focus,.swagger-ui .hover-lightest-blue:hover,.swagger-ui .lightest-blue{color:#cdecff}.swagger-ui .hover-washed-blue:focus,.swagger-ui .hover-washed-blue:hover,.swagger-ui .washed-blue{color:#f6fffe}.swagger-ui .hover-washed-green:focus,.swagger-ui .hover-washed-green:hover,.swagger-ui .washed-green{color:#e8fdf5}.swagger-ui .hover-washed-yellow:focus,.swagger-ui .hover-washed-yellow:hover,.swagger-ui .washed-yellow{color:#fffceb}.swagger-ui .hover-washed-red:focus,.swagger-ui .hover-washed-red:hover,.swagger-ui .washed-red{color:#ffdfdf}.swagger-ui .bg-black-90,.swagger-ui .hover-bg-black-90:focus,.swagger-ui .hover-bg-black-90:hover{background-color:#000000e6}.swagger-ui .bg-black-80,.swagger-ui .hover-bg-black-80:focus,.swagger-ui .hover-bg-black-80:hover{background-color:#000c}.swagger-ui .bg-black-70,.swagger-ui .hover-bg-black-70:focus,.swagger-ui .hover-bg-black-70:hover{background-color:#000000b3}.swagger-ui .bg-black-60,.swagger-ui .hover-bg-black-60:focus,.swagger-ui .hover-bg-black-60:hover{background-color:#0009}.swagger-ui .bg-black-50,.swagger-ui .hover-bg-black-50:focus,.swagger-ui .hover-bg-black-50:hover{background-color:#00000080}.swagger-ui .bg-black-40,.swagger-ui .hover-bg-black-40:focus,.swagger-ui .hover-bg-black-40:hover{background-color:#0006}.swagger-ui .bg-black-30,.swagger-ui .hover-bg-black-30:focus,.swagger-ui .hover-bg-black-30:hover{background-color:#0000004d}.swagger-ui .bg-black-20,.swagger-ui .hover-bg-black-20:focus,.swagger-ui .hover-bg-black-20:hover{background-color:#0003}.swagger-ui .bg-black-10,.swagger-ui .hover-bg-black-10:focus,.swagger-ui .hover-bg-black-10:hover,.swagger-ui .stripe-dark:nth-child(odd){background-color:#0000001a}.swagger-ui .bg-black-05{background-color:#0000000d}.swagger-ui .bg-white-90,.swagger-ui .hover-bg-white-90:focus,.swagger-ui .hover-bg-white-90:hover{background-color:#ffffffe6}.swagger-ui .bg-white-80,.swagger-ui .hover-bg-white-80:focus,.swagger-ui .hover-bg-white-80:hover{background-color:#fffc}.swagger-ui .bg-white-70,.swagger-ui .hover-bg-white-70:focus,.swagger-ui .hover-bg-white-70:hover{background-color:#ffffffb3}.swagger-ui .bg-white-60,.swagger-ui .hover-bg-white-60:focus,.swagger-ui .hover-bg-white-60:hover{background-color:#fff9}.swagger-ui .bg-white-50,.swagger-ui .hover-bg-white-50:focus,.swagger-ui .hover-bg-white-50:hover{background-color:#ffffff80}.swagger-ui .bg-white-40,.swagger-ui .hover-bg-white-40:focus,.swagger-ui .hover-bg-white-40:hover{background-color:#fff6}.swagger-ui .bg-white-30,.swagger-ui .hover-bg-white-30:focus,.swagger-ui .hover-bg-white-30:hover{background-color:#ffffff4d}.swagger-ui .bg-white-20,.swagger-ui .hover-bg-white-20:focus,.swagger-ui .hover-bg-white-20:hover{background-color:#fff3}.swagger-ui .bg-white-10,.swagger-ui .hover-bg-white-10:focus,.swagger-ui .hover-bg-white-10:hover,.swagger-ui .stripe-light:nth-child(odd){background-color:#ffffff1a}.swagger-ui .bg-black,.swagger-ui .hover-bg-black:focus,.swagger-ui .hover-bg-black:hover{background-color:#000}.swagger-ui .bg-near-black,.swagger-ui .hover-bg-near-black:focus,.swagger-ui .hover-bg-near-black:hover{background-color:#111}.swagger-ui .bg-dark-gray,.swagger-ui .hover-bg-dark-gray:focus,.swagger-ui .hover-bg-dark-gray:hover{background-color:#333}.swagger-ui .bg-mid-gray,.swagger-ui .hover-bg-mid-gray:focus,.swagger-ui .hover-bg-mid-gray:hover{background-color:#555}.swagger-ui .bg-gray,.swagger-ui .hover-bg-gray:focus,.swagger-ui .hover-bg-gray:hover{background-color:#777}.swagger-ui .bg-silver,.swagger-ui .hover-bg-silver:focus,.swagger-ui .hover-bg-silver:hover{background-color:#999}.swagger-ui .bg-light-silver,.swagger-ui .hover-bg-light-silver:focus,.swagger-ui .hover-bg-light-silver:hover,.swagger-ui .striped--light-silver:nth-child(odd){background-color:#aaa}.swagger-ui .bg-moon-gray,.swagger-ui .hover-bg-moon-gray:focus,.swagger-ui .hover-bg-moon-gray:hover{background-color:#ccc}.swagger-ui .bg-light-gray,.swagger-ui .hover-bg-light-gray:focus,.swagger-ui .hover-bg-light-gray:hover{background-color:#eee}.swagger-ui .bg-near-white,.swagger-ui .hover-bg-near-white:focus,.swagger-ui .hover-bg-near-white:hover{background-color:#f4f4f4}.swagger-ui .bg-white,.swagger-ui .hover-bg-white:focus,.swagger-ui .hover-bg-white:hover{background-color:#fff}.swagger-ui .bg-transparent,.swagger-ui .hover-bg-transparent:focus,.swagger-ui .hover-bg-transparent:hover{background-color:initial}.swagger-ui .bg-dark-red,.swagger-ui .hover-bg-dark-red:focus,.swagger-ui .hover-bg-dark-red:hover{background-color:#e7040f}.swagger-ui .bg-red,.swagger-ui .hover-bg-red:focus,.swagger-ui .hover-bg-red:hover{background-color:#ff4136}.swagger-ui .bg-light-red,.swagger-ui .hover-bg-light-red:focus,.swagger-ui .hover-bg-light-red:hover{background-color:#ff725c}.swagger-ui .bg-orange,.swagger-ui .hover-bg-orange:focus,.swagger-ui .hover-bg-orange:hover{background-color:#ff6300}.swagger-ui .bg-gold,.swagger-ui .hover-bg-gold:focus,.swagger-ui .hover-bg-gold:hover{background-color:#ffb700}.swagger-ui .bg-yellow,.swagger-ui .hover-bg-yellow:focus,.swagger-ui .hover-bg-yellow:hover{background-color:gold}.swagger-ui .bg-light-yellow,.swagger-ui .hover-bg-light-yellow:focus,.swagger-ui .hover-bg-light-yellow:hover{background-color:#fbf1a9}.swagger-ui .bg-purple,.swagger-ui .hover-bg-purple:focus,.swagger-ui .hover-bg-purple:hover{background-color:#5e2ca5}.swagger-ui .bg-light-purple,.swagger-ui .hover-bg-light-purple:focus,.swagger-ui .hover-bg-light-purple:hover{background-color:#a463f2}.swagger-ui .bg-dark-pink,.swagger-ui .hover-bg-dark-pink:focus,.swagger-ui .hover-bg-dark-pink:hover{background-color:#d5008f}.swagger-ui .bg-hot-pink,.swagger-ui .hover-bg-hot-pink:focus,.swagger-ui .hover-bg-hot-pink:hover{background-color:#ff41b4}.swagger-ui .bg-pink,.swagger-ui .hover-bg-pink:focus,.swagger-ui .hover-bg-pink:hover{background-color:#ff80cc}.swagger-ui .bg-light-pink,.swagger-ui .hover-bg-light-pink:focus,.swagger-ui .hover-bg-light-pink:hover{background-color:#ffa3d7}.swagger-ui .bg-dark-green,.swagger-ui .hover-bg-dark-green:focus,.swagger-ui .hover-bg-dark-green:hover{background-color:#137752}.swagger-ui .bg-green,.swagger-ui .hover-bg-green:focus,.swagger-ui .hover-bg-green:hover{background-color:#19a974}.swagger-ui .bg-light-green,.swagger-ui .hover-bg-light-green:focus,.swagger-ui .hover-bg-light-green:hover{background-color:#9eebcf}.swagger-ui .bg-navy,.swagger-ui .hover-bg-navy:focus,.swagger-ui .hover-bg-navy:hover{background-color:#001b44}.swagger-ui .bg-dark-blue,.swagger-ui .hover-bg-dark-blue:focus,.swagger-ui .hover-bg-dark-blue:hover{background-color:#00449e}.swagger-ui .bg-blue,.swagger-ui .hover-bg-blue:focus,.swagger-ui .hover-bg-blue:hover{background-color:#357edd}.swagger-ui .bg-light-blue,.swagger-ui .hover-bg-light-blue:focus,.swagger-ui .hover-bg-light-blue:hover{background-color:#96ccff}.swagger-ui .bg-lightest-blue,.swagger-ui .hover-bg-lightest-blue:focus,.swagger-ui .hover-bg-lightest-blue:hover{background-color:#cdecff}.swagger-ui .bg-washed-blue,.swagger-ui .hover-bg-washed-blue:focus,.swagger-ui .hover-bg-washed-blue:hover{background-color:#f6fffe}.swagger-ui .bg-washed-green,.swagger-ui .hover-bg-washed-green:focus,.swagger-ui .hover-bg-washed-green:hover{background-color:#e8fdf5}.swagger-ui .bg-washed-yellow,.swagger-ui .hover-bg-washed-yellow:focus,.swagger-ui .hover-bg-washed-yellow:hover{background-color:#fffceb}.swagger-ui .bg-washed-red,.swagger-ui .hover-bg-washed-red:focus,.swagger-ui .hover-bg-washed-red:hover{background-color:#ffdfdf}.swagger-ui .bg-inherit,.swagger-ui .hover-bg-inherit:focus,.swagger-ui .hover-bg-inherit:hover{background-color:inherit}.swagger-ui .pa1{padding:.25rem}.swagger-ui .pa2{padding:.5rem}.swagger-ui .pa3{padding:1rem}.swagger-ui .pa5{padding:4rem}.swagger-ui .pa6{padding:8rem}.swagger-ui .pa7{padding:16rem}.swagger-ui .opblock-external-docs-wrapper h4,.swagger-ui .pl0,:not(.containsTaskList_mC6p>li)>.containsTaskList_mC6p{padding-left:0}.swagger-ui .pl1{padding-left:.25rem}.swagger-ui .pl2{padding-left:.5rem}.swagger-ui .pl4{padding-left:2rem}.swagger-ui .pl5{padding-left:4rem}.swagger-ui .pl6{padding-left:8rem}.swagger-ui .pl7{padding-left:16rem}.swagger-ui .pr1{padding-right:.25rem}.swagger-ui .pr2{padding-right:.5rem}.swagger-ui .pr3{padding-right:1rem}.swagger-ui .pr4{padding-right:2rem}.swagger-ui .pr5{padding-right:4rem}.swagger-ui .pr6{padding-right:8rem}.swagger-ui .pr7{padding-right:16rem}.swagger-ui .pb1{padding-bottom:.25rem}.swagger-ui .pb2{padding-bottom:.5rem}.swagger-ui .pb4{padding-bottom:2rem}.swagger-ui .pb5{padding-bottom:4rem}.swagger-ui .pb6{padding-bottom:8rem}.swagger-ui .pb7{padding-bottom:16rem}.swagger-ui .pt1{padding-top:.25rem}.swagger-ui .pt2{padding-top:.5rem}.swagger-ui .pt3{padding-top:1rem}.swagger-ui .pt4{padding-top:2rem}.swagger-ui .pt5{padding-top:4rem}.swagger-ui .pt6{padding-top:8rem}.swagger-ui .pt7{padding-top:16rem}.swagger-ui .pv0{padding-bottom:0;padding-top:0}.swagger-ui .pv1{padding-bottom:.25rem;padding-top:.25rem}.swagger-ui .pv2{padding-bottom:.5rem;padding-top:.5rem}.swagger-ui .pv3{padding-bottom:1rem;padding-top:1rem}.swagger-ui .pv4{padding-bottom:2rem;padding-top:2rem}.swagger-ui .pv5{padding-bottom:4rem;padding-top:4rem}.swagger-ui .pv6{padding-bottom:8rem;padding-top:8rem}.swagger-ui .pv7{padding-bottom:16rem;padding-top:16rem}.swagger-ui .ph1{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7{padding-left:16rem;padding-right:16rem}.swagger-ui .ma1{margin:.25rem}.swagger-ui .ma2,.swagger-ui table.model{margin:.5rem}.swagger-ui .ma3{margin:1rem}.swagger-ui .ma4{margin:2rem}.swagger-ui .ma5{margin:4rem}.swagger-ui .ma6{margin:8rem}.swagger-ui .ma7{margin:16rem}.swagger-ui .ml0{margin-left:0}.swagger-ui .ml1{margin-left:.25rem}.swagger-ui .ml2{margin-left:.5rem}.swagger-ui .ml3,.swagger-ui .model>span>:not(.model-box-control){margin-left:1rem}.swagger-ui .ml6{margin-left:8rem}.swagger-ui .ml7{margin-left:16rem}.swagger-ui .mr1{margin-right:.25rem}.swagger-ui .mr2{margin-right:.5rem}.swagger-ui .mr3{margin-right:1rem}.swagger-ui .mr4{margin-right:2rem}.swagger-ui .mr5{margin-right:4rem}.swagger-ui .mr6{margin-right:8rem}.swagger-ui .mr7{margin-right:16rem}.swagger-ui .mb1{margin-bottom:.25rem}.swagger-ui .mb2{margin-bottom:.5rem}.swagger-ui .mb4{margin-bottom:2rem}.swagger-ui .mb5{margin-bottom:4rem}.swagger-ui .mb6{margin-bottom:8rem}.swagger-ui .mb7{margin-bottom:16rem}.swagger-ui .mt2{margin-top:.5rem}.swagger-ui .brace-open,.swagger-ui .mt3{margin-top:1rem}.swagger-ui .mt4{margin-top:2rem}.swagger-ui .mt5{margin-top:4rem}.swagger-ui .mt6{margin-top:8rem}.swagger-ui .mt7{margin-top:16rem}.swagger-ui .mv0{margin-bottom:0;margin-top:0}.swagger-ui .mv1{margin-bottom:.25rem;margin-top:.25rem}.swagger-ui .mv2{margin-bottom:.5rem;margin-top:.5rem}.swagger-ui .mv3{margin-bottom:1rem;margin-top:1rem}.swagger-ui .mv4{margin-bottom:2rem;margin-top:2rem}.swagger-ui .mv5{margin-bottom:4rem;margin-top:4rem}.swagger-ui .mv6{margin-bottom:8rem;margin-top:8rem}.swagger-ui .mv7{margin-bottom:16rem;margin-top:16rem}.swagger-ui .mh1{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7{margin-left:16rem;margin-right:16rem}.swagger-ui .na1{margin:-.25rem}.swagger-ui .na2{margin:-.5rem}.swagger-ui .na3{margin:-1rem}.swagger-ui .na4{margin:-2rem}.swagger-ui .na5{margin:-4rem}.swagger-ui .na6{margin:-8rem}.swagger-ui .na7{margin:-16rem}.swagger-ui .nl1{margin-left:-.25rem}.swagger-ui .nl2{margin-left:-.5rem}.swagger-ui .nl3{margin-left:-1rem}.swagger-ui .nl4{margin-left:-2rem}.swagger-ui .nl5{margin-left:-4rem}.swagger-ui .nl6{margin-left:-8rem}.swagger-ui .nl7{margin-left:-16rem}.swagger-ui .nr1{margin-right:-.25rem}.swagger-ui .nr2{margin-right:-.5rem}.swagger-ui .nr3{margin-right:-1rem}.swagger-ui .nr4{margin-right:-2rem}.swagger-ui .nr5{margin-right:-4rem}.swagger-ui .nr6{margin-right:-8rem}.swagger-ui .nr7{margin-right:-16rem}.swagger-ui .nb1{margin-bottom:-.25rem}.swagger-ui .nb2{margin-bottom:-.5rem}.swagger-ui .nb3{margin-bottom:-1rem}.swagger-ui .nb4{margin-bottom:-2rem}.swagger-ui .nb5{margin-bottom:-4rem}.swagger-ui .nb6{margin-bottom:-8rem}.swagger-ui .nb7{margin-bottom:-16rem}.swagger-ui .nt1{margin-top:-.25rem}.swagger-ui .nt2{margin-top:-.5rem}.swagger-ui .nt3{margin-top:-1rem}.swagger-ui .nt4{margin-top:-2rem}.swagger-ui .nt5{margin-top:-4rem}.swagger-ui .nt6{margin-top:-8rem}.swagger-ui .nt7{margin-top:-16rem}.swagger-ui .collapse{border-spacing:0}.swagger-ui .striped--moon-gray:nth-child(odd){background-color:#ccc}.swagger-ui .striped--light-gray:nth-child(odd){background-color:#eee}.swagger-ui .striped--near-white:nth-child(odd){background-color:#f4f4f4}.swagger-ui .model .deprecated>td:first-of-type,.swagger-ui .opblock .opblock-summary-path__deprecated,.swagger-ui .strike{-webkit-text-decoration:line-through;text-decoration:line-through}.swagger-ui .f-6,.swagger-ui .f-headline{font-size:6rem}.swagger-ui .f-5,.swagger-ui .f-subheadline{font-size:5rem}.swagger-ui .f2{font-size:2.25rem}.swagger-ui .f4{font-size:1.25rem}.swagger-ui .f7{font-size:.75rem}.swagger-ui .measure{max-width:30em}.swagger-ui .measure-wide{max-width:34em}.swagger-ui .measure-narrow{max-width:20em}.swagger-ui .indent{margin-bottom:0;margin-top:0;text-indent:1em}.swagger-ui .small-caps{font-feature-settings:"smcp","smcp";font-variant:small-caps}.swagger-ui .center{margin-left:auto;margin-right:auto}.swagger-ui .mr-auto{margin-right:auto}.swagger-ui .ml-auto{margin-left:auto}.swagger-ui .clip{clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);position:fixed!important}.swagger-ui .nowrap{white-space:nowrap}.swagger-ui .pre{white-space:pre}.swagger-ui .v-mid{vertical-align:middle}.swagger-ui .v-top,.swagger-ui table.model tr.extension td:last-child,.swagger-ui table.model tr.property-row td{vertical-align:top}.swagger-ui .v-btm{vertical-align:bottom}.swagger-ui .dim,.swagger-ui .glow:focus,.swagger-ui .glow:hover,.swagger-ui .hide-child:active .child,.swagger-ui .hide-child:focus .child,.swagger-ui .hide-child:hover .child{opacity:1;transition:opacity .15s ease-in}.swagger-ui .dim:focus,.swagger-ui .dim:hover{opacity:.5;transition:opacity .15s ease-in}.swagger-ui .dim:active{opacity:.8;transition:opacity .15s ease-out}.swagger-ui .glow,.swagger-ui .hide-child .child{transition:opacity .15s ease-in}.swagger-ui .hide-child .child{opacity:0}.swagger-ui .grow{transition:transform .25s ease-out}.swagger-ui .grow:focus,.swagger-ui .grow:hover{transform:scale(1.05)}.swagger-ui .checkbox input[type=checkbox]+label>.item:active,.swagger-ui .grow:active{transform:scale(.9)}.swagger-ui .grow-large{transition:transform .25s ease-in-out}.swagger-ui .grow-large:focus,.swagger-ui .grow-large:hover{transform:scale(1.2)}.swagger-ui .grow-large:active{transform:scale(.95)}.swagger-ui .shadow-hover{cursor:pointer;position:relative;transition:.5s cubic-bezier(.165,.84,.44,1)}.swagger-ui .shadow-hover:after{border-radius:inherit;box-shadow:0 0 16px 2px #0003;content:"";height:100%;left:0;opacity:0;position:absolute;top:0;transition:opacity .5s cubic-bezier(.165,.84,.44,1);width:100%;z-index:-1}.swagger-ui .bg-animate,.swagger-ui .bg-animate:focus,.swagger-ui .bg-animate:hover{transition:background-color .15s ease-in-out}.swagger-ui .z-0{z-index:0}.swagger-ui .z-1{z-index:1}.swagger-ui .z-2{z-index:2}.swagger-ui .z-3{z-index:3}.swagger-ui .z-4{z-index:4}.swagger-ui .z-5{z-index:5}.swagger-ui .z-999{z-index:999}.swagger-ui .z-9999{z-index:9999}.swagger-ui .z-max{z-index:2147483647}.swagger-ui .z-inherit{z-index:inherit}.swagger-ui .z-initial{z-index:auto}.swagger-ui .z-unset{z-index:unset}.swagger-ui .nested-list-reset ol,.swagger-ui .nested-list-reset ul{list-style-type:none;margin-left:0;padding-left:0}.swagger-ui .nested-copy-indent p+p{margin-bottom:0;margin-top:0;text-indent:.1em}.swagger-ui .example__section,.swagger-ui .examples__section,.swagger-ui .nested-copy-seperator p+p{margin-top:1.5em}.swagger-ui .nested-img img{display:block;max-width:100%;width:100%}.swagger-ui .nested-links a{color:#357edd}.swagger-ui .nested-links a:focus,.swagger-ui .nested-links a:hover{color:#96ccff;transition:color .15s ease-in}.swagger-ui .opblock-tag,.swagger-ui .opblock-tag small,.swagger-ui .parameter__type{color:var(--ifm-color-primary-contrast-foreground)}.swagger-ui .wrapper{box-sizing:border-box;margin:0 auto;max-width:var(--ifm-container-width-xl);padding:0;width:100%}.opblock-tag-section:before{content:"ENDPOINTS RELATED TO";display:block;flex-grow:100;font-size:12px;margin-bottom:-12px}.swagger-ui .opblock-tag-section{display:flex;flex-direction:column;gap:16px;margin-bottom:16px}.swagger-ui .try-out.btn-group{display:flex;flex:0.1 2 auto;padding:0}.swagger-ui .try-out__btn{margin-left:1.25rem}.swagger-ui .opblock-tag{align-items:center;border-bottom:1px solid #3b41514d;cursor:pointer;display:flex;font-size:24px;padding:0 0 16px;transition:.2s}.swagger-ui .opblock-tag+.swagger-ui .opblock-tag{margin-top:50px}.swagger-ui .opblock-tag:hover,.swagger-ui section.models h4:hover{background:#00000005}.swagger-ui .opblock-tag.no-desc span,.swagger-ui section.models h4 span{color:var(--ifm-color-primary-contrast-foreground);flex:1}.swagger-ui .opblock-tag svg,.swagger-ui section.models h4 svg{transition:.4s}.swagger-ui .opblock-tag small{flex:2;font-size:14px;font-weight:400;padding:0 10px}.swagger-ui .opblock-tag>div{flex:1 1 150px;font-weight:400;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.swagger-ui .parameter__type{font-family:monospace;font-size:12px;font-weight:600;padding:5px 0}.swagger-ui .parameter-controls{margin-top:.75em}.swagger-ui .examples__title{display:block;font-size:1.1em;font-weight:700;margin-bottom:.75em}.swagger-ui .examples__section-header{font-size:.9rem;font-weight:700;margin-bottom:.5rem}.swagger-ui .examples-select{display:inline-block;margin-bottom:.75em}.swagger-ui .examples-select__section-label{font-size:.9rem;font-weight:700;margin-right:.5rem}.swagger-ui .example__section-header{font-size:.9rem;font-weight:700;margin-bottom:.5rem}.swagger-ui .view-line-link{cursor:pointer;margin:0 5px;top:3px;transition:.5s;width:20px}.swagger-ui .opblock{border:1px solid #000;border-radius:4px;margin:0 0 32px}.swagger-ui .opblock .tab-header{display:flex;flex:1}.swagger-ui .opblock .tab-header .tab-item{cursor:pointer;padding:0 40px}.swagger-ui .opblock .tab-header .tab-item:first-of-type{padding:0 40px 0 0}.swagger-ui .opblock .tab-header .tab-item.active h4 span:after{background:gray;bottom:-15px;content:"";height:4px;left:50%;position:absolute;transform:translateX(-50%);width:120%}.swagger-ui .opblock.is-open .opblock-summary{border-bottom:#0000}.swagger-ui .opblock .opblock-section-header{align-items:center;display:flex;min-height:50px}.swagger-ui .opblock .opblock-section-header>label{align-items:center;display:flex;font-size:12px;font-weight:700;margin:0 0 0 auto}.swagger-ui .opblock .opblock-section-header>label>span{color:var(--ofga-neutral-base);font-weight:400;padding:0 10px 0 0}.swagger-ui .opblock .opblock-section-header h4{color:var(--ofga-color-foreground);flex:1;font-size:18px;font-weight:400;margin:0}.swagger-ui .opblock .opblock-summary-method{background:#000;border-radius:3px;color:var(--ofga-color-foreground);font-size:1rem;font-weight:400;min-width:70px;padding:8px 0;text-align:center}.swagger-ui .opblock .opblock-summary-operation-id,.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{align-items:center;color:var(--ifm-color-primary-contrast-foreground);display:flex;font-family:monospace;font-size:16px;font-weight:400;letter-spacing:.15px;padding:0 10px;word-break:break-word}.swagger-ui .opblock .opblock-summary-path{flex-shrink:0}.swagger-ui .opblock .opblock-summary-path-description-wrapper{align-items:center;display:flex;flex-wrap:wrap}.swagger-ui .info pre,.swagger-ui .opblock .opblock-summary-operation-id{font-size:14px}.swagger-ui .opblock .opblock-summary-description{color:var(--ifm-color-primary-contrast-foreground);flex:1 1 auto;font-size:13px;word-break:break-word}.swagger-ui .opblock .opblock-summary{align-items:center;cursor:pointer;display:flex}.swagger-ui .opblock .opblock-summary .view-line-link{cursor:pointer;margin:0 -28px 0 0;opacity:0;position:relative;top:2px;transition:.5s}.swagger-ui .opblock:hover .opblock-summary .view-line-link{margin:0 -30px 0 0}.swagger-ui .opblock .opblock-summary:hover .view-line-link{opacity:1;width:32px}.swagger-ui .opblock.opblock-post .opblock-summary-method{background:var(--ofga-color-primary);color:var(--ofga-color-background)}.swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span:after{background:var(--ofga-color-primary)}.swagger-ui .opblock.opblock-put .opblock-summary-method{background:#fca130;color:var(--ofga-color-background)}.swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span:after{background:#fca130}.swagger-ui .opblock.opblock-delete{background:unset;border:unset}.swagger-ui .opblock.opblock-delete .opblock-summary-method,.swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span:after{background:#f93e3e}.swagger-ui .opblock.opblock-delete .opblock-summary{border-color:#f93e3e}.swagger-ui .opblock.opblock-get{background:#0000;border-color:#0000}.swagger-ui .opblock.opblock-get .opblock-summary-method{background-color:var(--ofga-color-secondary);color:var(--ofga-color-background)}.swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span:after{border-color:var(--ofga-color-secondary)}.swagger-ui .opblock.opblock-patch{background:#50e3c21a;border-color:#50e3c2}.swagger-ui .opblock.opblock-patch .opblock-summary-method,.swagger-ui .opblock.opblock-patch .tab-header .tab-item.active h4 span:after{background:#50e3c2}.swagger-ui .opblock.opblock-patch .opblock-summary{border-color:#50e3c2}.swagger-ui .opblock.opblock-head{background:#9012fe1a;border-color:#9012fe}.swagger-ui .opblock.opblock-head .opblock-summary-method,.swagger-ui .opblock.opblock-head .tab-header .tab-item.active h4 span:after{background:#9012fe}.swagger-ui .opblock.opblock-head .opblock-summary{border-color:#9012fe}.swagger-ui .opblock.opblock-options{background:#0d5aa71a;border-color:#0d5aa7}.swagger-ui .opblock.opblock-options .opblock-summary-method,.swagger-ui .opblock.opblock-options .tab-header .tab-item.active h4 span:after{background:#0d5aa7}.swagger-ui .opblock.opblock-options .opblock-summary{border-color:#0d5aa7}.swagger-ui .opblock.opblock-deprecated{background:#ebebeb1a;border-color:#ebebeb;opacity:.6}.swagger-ui .opblock.opblock-deprecated .opblock-summary-method,.swagger-ui .opblock.opblock-deprecated .tab-header .tab-item.active h4 span:after{background:#ebebeb}.swagger-ui .opblock.opblock-deprecated .opblock-summary{border-color:#ebebeb}.swagger-ui .opblock .opblock-schemes{padding:8px 20px}.swagger-ui .opblock .opblock-schemes .schemes-title{padding:0 10px 0 0}.swagger-ui .filter .operation-filter-input{border:2px solid #d8dde7;margin:20px 0;padding:10px;width:100%}.swagger-ui .download-url-wrapper .failed,.swagger-ui .filter .failed,.swagger-ui table.model tr.property-row .star{color:red}.swagger-ui .model-example{margin-top:1em}.swagger-ui .tab{display:flex;list-style:none;padding:0}.swagger-ui .tab li{color:#3b4151;cursor:pointer;font-size:12px;min-width:60px;padding:0}.swagger-ui .tab li:first-of-type{padding-left:0;padding-right:12px;position:relative}.swagger-ui .tab li:first-of-type:after{background:#0003;content:"";height:100%;position:absolute;right:6px;top:0;width:1px}.swagger-ui .tab li button.tablinks{background:none;border:0;color:var(--ifm-color-primary-contrast-foreground);font-family:inherit;font-weight:inherit;padding:0}.swagger-ui .opblock-description-wrapper,.swagger-ui .opblock-external-docs-wrapper,.swagger-ui .opblock-title_normal{color:var(--ifm-color-primary-contrast-foreground);font-size:12px;margin:32px 0;padding:0 32px}.swagger-ui .opblock.opblock-get .opblock-description-wrapper{border-left:1px solid var(--ofga-color-secondary-dark)}.swagger-ui .opblock.opblock-post .opblock-description-wrapper{border-left:1px solid var(--ofga-color-primary)}.swagger-ui .opblock-description-wrapper h4,.swagger-ui .opblock-external-docs-wrapper h4,.swagger-ui .opblock-title_normal h4{color:var(--ifm-color-primary-contrast-foreground);font-size:12px;margin:0 0 5px}.swagger-ui .opblock-description-wrapper p,.swagger-ui .opblock-external-docs-wrapper p,.swagger-ui .opblock-title_normal p{color:var(--ifm-color-primary-contrast-foreground);font-size:14px;margin:0}.swagger-ui .execute-wrapper{padding:20px;text-align:right}.swagger-ui .execute-wrapper .btn{padding:8px 40px;width:100%}.swagger-ui .body-param-options{display:flex;flex-direction:column}.swagger-ui .body-param-options .body-param-edit{padding:10px 0}.swagger-ui .body-param-options label{color:var(--ifm-color-primary-contrast-foreground);padding:8px 0}.swagger-ui .body-param-options label select{margin:3px 0 0}.swagger-ui .responses-inner h4,.swagger-ui .responses-inner h5{color:#3b4151;font-size:12px;margin:10px 0 5px}.swagger-ui .info li,.swagger-ui .info p,.swagger-ui .info table,.swagger-ui .response-col_status{color:var(--ifm-color-primary-contrast-foreground);font-size:14px}.swagger-ui .response-col_links .response-undocumented,.swagger-ui .response-col_status .response-undocumented{color:#909090;font-family:monospace;font-size:11px;font-weight:600}.swagger-ui .response-col_links{color:#3b4151;font-size:14px;max-width:40em;padding-left:2em;min-width:6em}.swagger-ui .response-col_links .operation-link{margin-bottom:1.5em}.swagger-ui .response-col_links .operation-link .description{margin-bottom:.5em}.swagger-ui .opblock-body .opblock-loading-animation{display:block;margin:3em auto}.swagger-ui .opblock-body pre.microlight{word-wrap:break-word;background:var(--ofga-neutral-black)!important;border-radius:4px;color:#fff;font-family:monospace;font-size:12px;font-weight:400;-webkit-hyphens:auto;hyphens:auto;margin:0;padding:10px;white-space:pre-wrap;word-break:break-all;word-break:break-word}.swagger-ui .highlight-code>.microlight{max-height:400px;min-height:6em;overflow-y:auto}.swagger-ui .highlight-code>.microlight code{white-space:pre-wrap!important;word-break:break-all}.swagger-ui .download-contents{align-items:center;background:#7d8293;border-radius:4px;bottom:10px;color:#fff;cursor:pointer;display:flex;font-size:14px;font-weight:600;height:30px;justify-content:center;padding:5px;position:absolute;right:10px;text-align:center}.swagger-ui .scheme-container{box-shadow:0 1px 2px 0 #00000026;margin:0 0 20px;padding:30px 0}.swagger-ui .scheme-container .schemes{align-items:flex-end;display:flex}.swagger-ui .scheme-container .schemes label{color:var(--ifm-color-primary-contrast-foreground);display:flex;flex-direction:column;font-size:12px;font-weight:700;margin:-20px 15px 0 0}.swagger-ui .scheme-container .schemes label select{min-width:130px;text-transform:uppercase}.swagger-ui .loading-container{align-items:center;display:flex;flex-direction:column;justify-content:center;margin-top:1em;min-height:1px;padding:40px 0 60px}.swagger-ui .loading-container .loading:after{color:#fff;content:"loading";font-size:10px;font-weight:700;left:50%;position:absolute;text-transform:uppercase;top:50%;transform:translate(-50%,-50%)}.swagger-ui .loading-container .loading:before{animation:1s linear infinite b,.5s opacity;backface-visibility:hidden;border:2px solid var(--ofga-neutral-dark);border-radius:100%;border-top-color:var(--ofga-neutral-white);content:"";display:block;height:60px;left:50%;margin:-30px;opacity:1;position:absolute;top:50%;width:60px}@keyframes b{to{transform:rotate(1turn)}}.swagger-ui .response-controls{display:flex;padding-top:1em}.swagger-ui .auth-btn-wrapper .btn-done,.swagger-ui .response-control-media-type{margin-right:1em}.swagger-ui .response-control-media-type--accept-controller select{border-color:green}.swagger-ui .response-control-media-type__accept-message{color:green;font-size:.7em}.swagger-ui .response-control-examples__title,.swagger-ui .response-control-media-type__title{display:block;font-size:.7em;margin-bottom:.2em}.swagger-ui .no-margin{border:none;height:auto;margin:0;padding:0}.swagger-ui .svg-assets{height:0;position:absolute;width:0}.swagger-ui a.nostyle,.swagger-ui a.nostyle:visited{color:var(--ifm-color-primary-contrast-foreground);cursor:pointer;text-decoration:inherit}.documentation-card-box-link_yEiX:hover:after,.swagger-ui .topbar a,.tag_zVej:hover{-webkit-text-decoration:none;text-decoration:none}.swagger-ui .fallback{color:#aaa;padding:1em}.swagger-ui .version-pragma{height:100%;padding:5em 0}.swagger-ui .version-pragma__message{display:flex;font-size:1.2em;height:100%;justify-content:center;line-height:1.5em;padding:0 .6em;text-align:center}.swagger-ui .btn,.swagger-ui select{font-size:14px;font-weight:700;color:#3b4151}.swagger-ui .version-pragma__message>div{flex:1;max-width:55ch}.swagger-ui .version-pragma__message code{background-color:#dedede;padding:4px 4px 2px;white-space:pre}.swagger-ui span.token-not-formatted{color:#555;font-weight:700}.swagger-ui .btn{background:#0000;border:2px solid gray;border-radius:4px;box-shadow:0 1px 2px #0000001a;padding:5px 23px;transition:.3s}.swagger-ui .btn.btn-sm{font-size:12px;padding:4px 23px}.swagger-ui .btn[disabled]{cursor:not-allowed;opacity:.3}.swagger-ui .btn:hover{box-shadow:0 0 5px #0000004d}.swagger-ui .btn.cancel{background-color:initial;border-color:#ff6060;color:#ff6060}.swagger-ui .btn.authorize{background-color:initial;border-color:#49cc90;color:#49cc90;display:inline;line-height:1}.swagger-ui .btn.authorize span{float:left;padding:4px 20px 0 0}.swagger-ui .btn.authorize svg{fill:#49cc90}.swagger-ui .btn.execute{background-color:#4990e2;border-color:#4990e2;color:#fff}.swagger-ui .btn-group{display:flex;padding:30px}.swagger-ui .btn-group .btn{flex:1}.swagger-ui .btn-group .btn:first-child{border-radius:4px 0 0 4px}.swagger-ui .btn-group .btn:last-child{border-radius:0 4px 4px 0}.swagger-ui .authorization__btn{background:none;border:none;margin:0 -8px 0 10px}.swagger-ui .authorization__btn.locked{opacity:1}.swagger-ui .authorization__btn.unlocked,.theme-code-block:hover .buttonGroup__atx button{opacity:.4}.swagger-ui .model-box-control,.swagger-ui .models-control,.swagger-ui .opblock-summary-control{all:inherit;align-items:center;border-bottom:0;cursor:pointer;display:flex;flex:1;padding:0}.swagger-ui .model-box-control{flex-direction:row;grid-gap:.5rem}.swagger-ui .model-box-control:focus,.swagger-ui .models-control:focus,.swagger-ui .opblock-summary-control:focus{background-color:var(--ofga-color-background);outline:0}.swagger-ui .expand-methods,.swagger-ui .expand-operation{background:none;border:none;padding:0}.swagger-ui .expand-methods svg,.swagger-ui .expand-operation svg{height:20px;width:20px;fill:var(--ofga-neutral-light)}.swagger-ui .expand-methods{padding:0 10px}.swagger-ui .expand-methods:hover svg{fill:#404040}.swagger-ui .expand-methods svg{fill:#707070;transition:.3s}.swagger-ui button.invalid,.swagger-ui input[type=email].invalid,.swagger-ui input[type=file].invalid,.swagger-ui input[type=password].invalid,.swagger-ui input[type=search].invalid,.swagger-ui input[type=text].invalid,.swagger-ui select.invalid,.swagger-ui textarea.invalid{animation:.4s c;background:#feebeb;border-color:#f93e3e}.swagger-ui .copy-to-clipboard{align-items:center;border:none;border-radius:4px;bottom:10px;display:flex;height:30px;justify-content:center;position:absolute;right:100px;width:30px}.swagger-ui .copy-to-clipboard:before{content:"copy";display:block;font-size:12px;margin-left:-32px;margin-right:6px;overflow:visible}.swagger-ui .copy-to-clipboard button{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='15' aria-hidden='true'%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M4 12h4v1H4zm5-6H4v1h5zm2 3V7l-3 3 3 3v-2h5V9zM6.5 8H4v1h2.5zM4 11h2.5v-1H4zm9 1h1v2c-.02.28-.11.52-.3.7s-.42.28-.7.3H3c-.55 0-1-.45-1-1V3c0-.55.45-1 1-1h3c0-1.11.89-2 2-2s2 .89 2 2h3c.55 0 1 .45 1 1v5h-1V5H3v9h10zM4 4h8c0-.55-.45-1-1-1h-1c-.55 0-1-.45-1-1s-.45-1-1-1-1 .45-1 1-.45 1-1 1H5c-.55 0-1 .45-1 1'/%3E%3C/svg%3E") 50% no-repeat;border:none;flex-grow:1;flex-shrink:1;height:25px}.swagger-ui .curl-command .copy-to-clipboard{bottom:5px;height:20px;right:10px;width:20px}.swagger-ui .curl-command .copy-to-clipboard button{height:18px}.swagger-ui select{appearance:none;background:url('data:image/svg+xml;charset=utf-8,') right 10px center/20px no-repeat #f7f7f7;border:2px solid #41444e;border-radius:4px;box-shadow:0 1px 2px 0 #00000040;padding:5px 40px 5px 10px}.swagger-ui select[multiple]{background:#f7f7f7;margin:5px 0;padding:5px}.swagger-ui .auth-container input[type=password],.swagger-ui .auth-container input[type=text],.swagger-ui .opblock-body select{min-width:230px}.swagger-ui label{font-size:12px;font-weight:700;margin:0 0 5px}.swagger-ui input[type=email],.swagger-ui input[type=file],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text],.swagger-ui textarea{background:#fff;border:1px solid #d9d9d9;border-radius:4px;margin:5px 0;min-width:100px;padding:8px 10px}.swagger-ui textarea,.swagger-ui textarea.curl{padding:10px;font-size:12px;font-weight:600;font-family:monospace}.swagger-ui input[disabled],.swagger-ui select[disabled],.swagger-ui textarea[disabled]{background-color:var(--ofga-color-background);border:0;color:#fff}.swagger-ui select[disabled]{border-color:#888}.swagger-ui textarea[disabled]{background-color:#41444e;color:#fff}@keyframes c{10%,90%{transform:translate3d(-1px,0,0)}20%,80%{transform:translate3d(2px,0,0)}30%,50%,70%{transform:translate3d(-4px,0,0)}40%,60%{transform:translate3d(4px,0,0)}}.swagger-ui textarea{overflow:auto;background:#fffc;border:none;border-radius:4px;color:#3b4151;min-height:280px;outline:0;width:100%}.buttonGroup__atx button,.codeBlockContainer_Ckt0{background:var(--prism-background-color);color:var(--prism-color)}.swagger-ui textarea:focus{border:2px solid #61affe}.swagger-ui textarea.curl{background:#41444e;border-radius:4px;color:#fff;margin:0;min-height:100px;resize:none}.swagger-ui .checkbox{color:#303030;padding:5px 0 10px;transition:opacity .5s}.swagger-ui .checkbox p{color:#3b4151;font-family:monospace;font-style:italic;font-weight:400!important;margin:0!important}.swagger-ui .checkbox input[type=checkbox]+label>.item{background:#e8e8e8;border-radius:1px;box-shadow:0 0 0 2px #e8e8e8;cursor:pointer;display:inline-block;flex:none;height:16px;margin:0 8px 0 0;padding:5px;position:relative;top:3px;width:16px}.swagger-ui .checkbox input[type=checkbox]:checked+label>.item{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='8' viewBox='3 7 10 8'%3E%3Cpath fill='%2341474E' fill-rule='evenodd' d='M6.333 15 3 11.667l1.333-1.334 2 2L11.667 7 13 8.333z'/%3E%3C/svg%3E") 50% no-repeat #e8e8e8}.swagger-ui .dialog-ux{bottom:0;left:0;position:fixed;right:0;top:0;z-index:9999}.swagger-ui .model-jump-to-path,.swagger-ui .model-toggle{position:relative;cursor:pointer}.swagger-ui .dialog-ux .backdrop-ux{background:#000c;bottom:0;left:0;position:fixed;right:0;top:0}.swagger-ui .dialog-ux .modal-ux{background:#fff;border:1px solid #ebebeb;border-radius:4px;box-shadow:0 10px 30px 0 #0003;left:50%;max-width:650px;min-width:300px;position:absolute;top:50%;transform:translate(-50%,-50%);width:100%;z-index:9999}.swagger-ui .dialog-ux .modal-ux-content{max-height:540px;overflow-y:auto;padding:20px}.swagger-ui .dialog-ux .modal-ux-content p{color:#3b4151;font-size:12px;margin:0 0 5px}.swagger-ui .dialog-ux .modal-ux-content h4{color:#3b4151;font-size:18px;font-weight:600;margin:15px 0 0}.swagger-ui .dialog-ux .modal-ux-header{align-items:center;border-bottom:1px solid #ebebeb;display:flex;padding:12px 0}.swagger-ui .dialog-ux .modal-ux-header .close-modal{appearance:none;background:none;border:none;padding:0 10px}.swagger-ui .dialog-ux .modal-ux-header h3{color:#3b4151;flex:1;font-size:20px;font-weight:600;margin:0;padding:0 20px}.swagger-ui .model{color:var(--ifm-color-primary-contrast-foreground);font-family:monospace;font-size:16px;font-weight:300}.swagger-ui .model>span{align-items:stretch;display:flex;flex-direction:column}.swagger-ui .model .deprecated span,.swagger-ui .model .deprecated td{color:#a0a0a0!important}.swagger-ui .model-toggle{display:inline-block;font-size:10px;margin:0;transform:rotate(90deg);transform-origin:50% 50%;transition:transform .15s ease-in}.swagger-ui .model-toggle.collapsed{transform:rotate(0)}.swagger-ui .model-toggle:after{background:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='%23d3d8df'%3E%3Cpath d='M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z'/%3E%3C/svg%3E") 50%/100% no-repeat;content:"";display:block;height:20px;width:20px}.swagger-ui .model-jump-to-path .view-line-link{cursor:pointer;position:absolute;top:-.4em}.swagger-ui .model-title{font-weight:600;position:relative}.swagger-ui .model-title:hover .model-hint{visibility:visible}.swagger-ui .model-hint{background:#000000b3;border-radius:4px;color:#ebebeb;padding:.1em .5em;position:absolute;top:-1.8em;visibility:hidden;white-space:nowrap}.swagger-ui .model p{margin:0 0 1em}.swagger-ui .model .property,.swagger-ui table.headers .header-example{color:#999;font-style:italic}.swagger-ui .model .property.primitive{color:var(--ofga-neutral-dark)}.swagger-ui table.model,.swagger-ui table.model tbody,.swagger-ui table.model td,.swagger-ui table.model tr{border:none}.swagger-ui table.model tr.description{color:#666;font-weight:400}.swagger-ui table.model tr.property-row td:first-child{padding-right:.2em}.swagger-ui section.models{border-radius:4px;margin:30px 0}.swagger-ui .scope-def,.swagger-ui section.models.is-open{padding:0 0 20px}.swagger-ui section.models.is-open h4{border-bottom:1px solid #3b41514d}.swagger-ui section.models h4{align-items:center;color:#606060;cursor:pointer;display:flex;font-size:24px;margin:0;padding:16px 16px 16px 0;transition:.2s}.swagger-ui section.models h5{color:#707070;font-size:16px;margin:0 0 10px}.swagger-ui section.models .model-jump-to-path{position:relative;top:5px}.swagger-ui section.models .model-container{border-bottom:1px solid var(--ofga-neutral-darker);border-radius:4px;color:var(--ifm-color-primary-contrast-foreground);padding:0 .75rem;position:relative;transition:.5s}.swagger-ui section.models .model-container:hover{background:#00000012}.swagger-ui section.models .model-container .models-jump-to-path{opacity:.65;position:absolute;right:5px;top:8px}.swagger-ui section.models .model-box{background:none}.swagger-ui .model-box{display:block;padding:16px 0}.swagger-ui .model-box>.model-box{border:0}.swagger-ui .model-box .model-jump-to-path{position:relative;top:4px}.swagger-ui button .model-box{border:0;margin:0;padding:0}.swagger-ui .model-title{color:var(--ifm-color-primary-contrast-foreground);font-size:16px}.swagger-ui .model-title img{bottom:0;margin-left:1em;position:relative}.swagger-ui .model-deprecated-warning{color:#f93e3e;font-size:16px;font-weight:600;margin-right:1em}.swagger-ui span>span.model .brace-close{padding:0 0 0 10px}.swagger-ui .prop-name{display:inline-block;margin-right:1em}.swagger-ui .errors-wrapper .errors small,.swagger-ui .prop-format{color:#606060}.swagger-ui .servers>label{color:#3b4151;font-size:12px;margin:-20px 15px 0 0}.swagger-ui .servers>label select{max-width:100%;min-width:130px}.swagger-ui .servers h4.message{padding-bottom:2em}.swagger-ui .servers table tr{width:30em}.swagger-ui .servers table td{display:inline-block;max-width:15em;padding-bottom:10px;padding-top:10px;vertical-align:middle}.swagger-ui .servers table td:first-of-type{padding-right:1em}.swagger-ui .servers table td input{height:100%;width:100%}.swagger-ui .servers .computed-url{margin:2em 0}.swagger-ui .servers .computed-url code{display:inline-block;font-size:16px;margin:0 1em;padding:4px}.swagger-ui .servers-title{font-size:12px;font-weight:700}.swagger-ui .operation-servers h4.message{margin-bottom:2em}.swagger-ui table{width:100%}.swagger-ui table.model tbody tr td{padding:0;vertical-align:top}.swagger-ui table.model tbody tr td:first-of-type{padding:0 0 0 2em}.swagger-ui table.headers td{color:#3b4151;font-family:monospace;font-size:12px;font-weight:600;vertical-align:middle}.swagger-ui table tbody tr td{padding:12px;vertical-align:top}.swagger-ui table tbody tr td:first-of-type{min-width:6em;padding:12px}.swagger-ui table thead tr td,.swagger-ui table thead tr th{border-bottom:1px solid #3b415133;color:var(--ifm-color-primary-contrast-foreground);font-size:12px;font-weight:700;padding:12px;text-align:left}.swagger-ui .parameters-col_description{margin-bottom:2em;width:99%}.swagger-ui .parameters-col_description input[type=text]{max-width:340px;width:100%}.swagger-ui .parameters-col_description select{border-width:1px}.swagger-ui .parameter__name{color:var(--ifm-color-primary-contrast-foreground);font-size:16px;font-weight:400;margin-right:.75em}.swagger-ui .parameter__name.required{font-weight:700}.swagger-ui .parameter__name.required span{color:#0000}.swagger-ui .parameter__name.required:after{color:var(--ofga-neon-green);content:"required";font-size:12px;left:.5em;position:relative}.swagger-ui .parameter__extension,.swagger-ui .parameter__in,.swagger-ui .response__extension{color:gray;font-family:monospace;font-size:12px;font-style:italic;font-weight:600}.swagger-ui .parameter__deprecated{color:red;font-family:monospace;font-size:12px;font-style:italic;font-weight:600}.swagger-ui .parameter__empty_value_toggle{display:block;font-size:13px;padding-bottom:12px;padding-top:5px}.swagger-ui .parameter__empty_value_toggle input{margin-right:7px}.swagger-ui .parameter__empty_value_toggle.disabled{opacity:.7}.swagger-ui .response-col_description{width:99%}.swagger-ui .topbar{background-color:#1b1b1b;padding:10px 0}.documentation-card-box-alignment-left__zex,.swagger-ui .errors-wrapper hgroup,.swagger-ui .topbar .topbar-wrapper,.swagger-ui .topbar a{align-items:center;display:flex}.swagger-ui .topbar a{color:#fff;flex:1;font-size:1.5em;font-weight:700;max-width:300px}.swagger-ui .topbar a span{margin:0;padding:0 10px}.swagger-ui .topbar .download-url-wrapper{display:flex;flex:3;justify-content:flex-end}.swagger-ui .topbar .download-url-wrapper input[type=text]{border:2px solid #62a03f;border-radius:4px 0 0 4px;margin:0;outline:0;width:100%}.swagger-ui .topbar .download-url-wrapper .select-label{align-items:center;color:#f0f0f0;display:flex;margin:0;max-width:600px;width:100%}.swagger-ui .topbar .download-url-wrapper .select-label span{flex:1;font-size:16px;padding:0 10px 0 0;text-align:right}.swagger-ui .topbar .download-url-wrapper .select-label select{border:2px solid #62a03f;box-shadow:none;flex:2;outline:0;width:100%}.swagger-ui .topbar .download-url-wrapper .download-url-button{background:#62a03f;border:none;border-radius:0 4px 4px 0;color:#fff;font-size:16px;font-weight:700;padding:4px 30px}.swagger-ui .info{margin:64px 0}.description:before{content:"DESCRIPTION";display:block;font-size:12px;line-height:2}.swagger-ui .description p{font-size:18px!important}.swagger-ui .info .description{background-color:var(--ofga-neutral-darker);border-radius:0;margin:32px -32px;padding:48px 32px}.swagger-ui .info.failed-config{margin-left:auto;margin-right:auto;max-width:880px;text-align:center}.swagger-ui .info hgroup.main{margin:0 0 20px}.swagger-ui .info hgroup.main a{font-size:12px}.swagger-ui .info a{color:var(--ofga-color-primary);font-size:14px;transition:.4s}.swagger-ui .info a:hover{color:var(--ofga-color-primary-light)}.swagger-ui .info>div{margin:0 0 5px}.swagger-ui .info .base-url{color:#3b4151;font-family:monospace;font-size:12px;font-weight:300!important;margin:0}.swagger-ui .info .title{color:var(--ifm-color-primary-contrast-foreground);font-size:48px;margin:0}.swagger-ui .info .title:after{color:var(--ofga-neutral-light);content:" API Documentation"}.swagger-ui .url:before{color:#fff;content:"JSON REFERENCE URL";display:block;font-size:12px;line-height:2;margin-top:32px}.swagger-ui .url{font-size:16px}.swagger-ui .info .title small{background:#7d8492;border-radius:57px;font-size:10px;margin:0 0 0 5px;padding:2px 4px;position:relative;top:-5px;vertical-align:super;display:none}.swagger-ui .info .title small.version-stamp{background-color:#89bf04}.swagger-ui .info .title small pre{color:#fff;margin:0;padding:0}.swagger-ui .auth-btn-wrapper{display:flex;justify-content:center;padding:10px 0}.swagger-ui .auth-wrapper{display:flex;flex:1;justify-content:flex-end}.swagger-ui .auth-wrapper .authorize{margin-right:10px;padding-right:20px}.swagger-ui .auth-container{border-bottom:1px solid #ebebeb;margin:0 0 10px;padding:10px 20px}.swagger-ui .auth-container:last-of-type{border:0;margin:0;padding:10px 20px}.swagger-ui .auth-container h4{margin:5px 0 15px!important}.swagger-ui .auth-container .wrapper{margin:0;padding:0}.swagger-ui .auth-container .errors{background-color:#fee;border-radius:4px;color:#3b4151;font-family:monospace;font-size:12px;font-weight:600;margin:1em;padding:10px}.swagger-ui .auth-container .errors b{margin-right:1em;text-transform:capitalize}.swagger-ui .scopes h2{color:#3b4151;font-size:14px}.swagger-ui .scopes h2 a{color:#4990e2;cursor:pointer;font-size:12px;padding-left:10px}.swagger-ui .errors-wrapper{animation:.5s d;background:#f93e3e1a;border:2px solid #f93e3e;border-radius:4px;margin:20px;padding:10px 20px}.swagger-ui .errors-wrapper .error-wrapper{margin:0 0 10px}.swagger-ui .errors-wrapper .errors h4{color:#3b4151;font-family:monospace;font-size:14px;font-weight:600;margin:0}.swagger-ui .errors-wrapper .errors .message{color:var(--ifm-color-primary-contrast-foreground);white-space:pre-line}.swagger-ui .errors-wrapper .errors .error-line{cursor:pointer}.swagger-ui .errors-wrapper hgroup h4{color:var(--ifm-color-primary-contrast-foreground);flex:1;font-size:20px;margin:0}@keyframes d{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:scale(1)}}.swagger-ui .markdown p,.swagger-ui .markdown pre,.swagger-ui .renderedMarkdown p,.swagger-ui .renderedMarkdown pre{color:var(--ifm-color-primary-contrast-foreground);margin:0 auto 1em;word-break:break-all;word-break:break-word}.swagger-ui .markdown pre,.swagger-ui .renderedMarkdown pre{background:none;color:#000;font-weight:400;padding:0;white-space:pre-wrap}.swagger-ui .markdown code,.swagger-ui .renderedMarkdown code{background:var(--ofga-color-background);border-radius:4px;color:var(--ofga-color-primary-light);font-family:monospace;font-size:14px;font-weight:400;padding:8px}.swagger-ui .markdown p code{margin:0 4px;padding:2px 4px}.codeBlockContainer_Ckt0{border-radius:var(--ifm-code-border-radius);box-shadow:var(--ifm-global-shadow-lw);margin-bottom:var(--ifm-leading)}.codeBlockContent_biex{border-radius:inherit;direction:ltr;position:relative}.codeBlockTitle_Ktv7{border-bottom:1px solid var(--ifm-color-emphasis-300);border-top-left-radius:inherit;border-top-right-radius:inherit;font-size:var(--ifm-code-font-size);font-weight:500;padding:.75rem var(--ifm-pre-padding)}.codeBlock_bY9V{--ifm-pre-background:var(--prism-background-color);margin:0;padding:0}.codeBlockLines_e6Vv{float:left;font:inherit;min-width:100%;padding:var(--ifm-pre-padding)}.codeBlockLinesWithNumbering_o6Pm{display:table;padding:var(--ifm-pre-padding) 0}.buttonGroup__atx{column-gap:.2rem;display:flex;position:absolute;right:calc(var(--ifm-pre-padding)/2);top:calc(var(--ifm-pre-padding)/2)}.buttonGroup__atx button{align-items:center;border:1px solid var(--ifm-color-emphasis-300);border-radius:var(--ifm-global-radius);display:flex;line-height:0;opacity:0;padding:.4rem;transition:opacity var(--ifm-transition-fast) ease-in-out}.buttonGroup__atx button:focus-visible,.buttonGroup__atx button:hover{opacity:1!important}:where(:root){--docusaurus-highlighted-code-line-bg:#484d5b}:where([data-theme=dark]){--docusaurus-highlighted-code-line-bg:#646464}.theme-code-block-highlighted-line{background-color:var(--docusaurus-highlighted-code-line-bg);display:block;margin:0 calc(var(--ifm-pre-padding)*-1);padding:0 var(--ifm-pre-padding)}.codeLine_lJS_{counter-increment:a;display:table-row}.codeLineNumber_Tfdd{background:var(--ifm-pre-background);display:table-cell;left:0;overflow-wrap:normal;padding:0 var(--ifm-pre-padding);position:sticky;text-align:right;width:1%}.codeLineNumber_Tfdd:before{content:counter(a);opacity:.4}.codeLineContent_feaV{padding-right:var(--ifm-pre-padding)}.tag_zVej{border:1px solid var(--docusaurus-tag-list-border);transition:border var(--ifm-transition-fast)}.tag_zVej:hover{--docusaurus-tag-list-border:var(--ifm-link-color)}.tagRegular_sFm0{border-radius:var(--ifm-global-radius);font-size:90%;padding:.2rem .5rem .3rem}.tagWithCount_h2kH{align-items:center;border-left:0;display:flex;padding:0 .5rem 0 1rem;position:relative}.tag_Nnez,.tag_QGVx{display:inline-block}.tagWithCount_h2kH:after,.tagWithCount_h2kH:before{border:1px solid var(--docusaurus-tag-list-border);content:"";position:absolute;top:50%;transition:inherit}.tagWithCount_h2kH:before{border-bottom:0;border-right:0;height:1.18rem;right:100%;transform:translate(50%,-50%) rotate(-45deg);width:1.18rem}.tagWithCount_h2kH:after{border-radius:50%;height:.5rem;left:0;transform:translateY(-50%);width:.5rem}.tagWithCount_h2kH span{background:var(--ifm-color-secondary);border-radius:var(--ifm-global-radius);color:var(--ifm-color-black);font-size:.7rem;line-height:1.2;margin-left:.3rem;padding:.1rem .4rem}.tag_Nnez{margin:.5rem .5rem 0 1rem}.theme-code-block:hover .copyButtonCopied_obH4{opacity:1!important}.copyButtonIcons_eSgA{height:1.125rem;position:relative;width:1.125rem}.copyButtonIcon_y97N,.copyButtonSuccessIcon_LjdS{left:0;position:absolute;top:0;fill:currentColor;height:inherit;opacity:inherit;transition:all var(--ifm-transition-fast) ease;width:inherit}.copyButtonSuccessIcon_LjdS{color:#00d600;left:50%;opacity:0;top:50%;transform:translate(-50%,-50%) scale(.33)}.copyButtonCopied_obH4 .copyButtonIcon_y97N{opacity:0;transform:scale(.33)}.copyButtonCopied_obH4 .copyButtonSuccessIcon_LjdS{opacity:1;transform:translate(-50%,-50%) scale(1);transition-delay:75ms}.tag_QGVx{margin:0 .4rem .5rem 0}.iconEdit_Z9Sw{margin-right:.3em;vertical-align:sub}.lastUpdated_JAkA{font-size:smaller;font-style:italic;margin-top:.2rem}.tocCollapsibleButton_TO0P{align-items:center;display:flex;font-size:inherit;justify-content:space-between;padding:.4rem .8rem;width:100%}.tocCollapsibleButton_TO0P:after{background:var(--ifm-menu-link-sublist-icon) 50% 50%/2rem 2rem no-repeat;content:"";filter:var(--ifm-menu-link-sublist-icon-filter);height:1.25rem;transform:rotate(180deg);transition:transform var(--ifm-transition-fast);width:1.25rem}.tocCollapsibleButtonExpanded_MG3E:after,.tocCollapsibleExpanded_sAul{transform:none}.tocCollapsible_ETCw{background-color:var(--ifm-menu-color-background-active);border-radius:var(--ifm-global-radius);margin:1rem 0}.tocCollapsibleContent_vkbj>ul{border-left:none;border-top:1px solid var(--ifm-color-emphasis-300);font-size:15px;padding:.2rem 0}.tocCollapsibleContent_vkbj ul li{margin:.4rem .8rem}.wordWrapButtonIcon_Bwma{height:1.2rem;width:1.2rem}.admonition_xJq3{margin-bottom:1em}.admonitionHeading_Gvgb{font:var(--ifm-heading-font-weight) var(--ifm-h5-font-size)/var(--ifm-heading-line-height) var(--ifm-heading-font-family);text-transform:uppercase}.admonitionHeading_Gvgb:not(:last-child){margin-bottom:.3rem}.admonitionIcon_Rf37{display:inline-block;margin-right:.4em;vertical-align:middle}.admonitionIcon_Rf37 svg{display:inline-block;height:1.6em;width:1.6em;fill:var(--ifm-alert-foreground-color)}.documentation-banner_hL3X{align-items:center;background-color:#f6f7fa;border:none;border-radius:24px;display:flex;flex-direction:row;margin-bottom:32px;margin-top:2rem;padding:32px;position:relative}.documentation-banner_hL3X *,.documentation-card-box-content_Z5TD *{font-family:Inter}.documentation-banner_hL3X:hover{box-shadow:0 0 5px #0000001a,0 6px 8px #0000001a;transition:.3s}.documentation-banner_hL3X:not(:hover){transition:.3s}.documentation-banner_hL3X:focus{box-shadow:0 0 0 5px #635dff40!important}.documentation-banner_hL3X .documentation-banner-icon_zVr_{align-items:center;background-color:#fff;border-radius:24px;display:flex;height:94px;justify-content:center;margin-right:32px;width:94px}.documentation-banner_hL3X .documentation-banner-icon-slack__g7S{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MyIgaGVpZ2h0PSI2MyIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI0UwMUU1QSIgZD0iTTEzLjA4NyA0MC4xNGE2LjUwNyA2LjUwNyAwIDAgMS02LjUxMyA2LjUxNEE2LjUwNyA2LjUwNyAwIDAgMSAuMDYgNDAuMTRhNi41MDcgNi41MDcgMCAwIDEgNi41MTMtNi41MTNoNi41MTN6TTE2LjM0NCA0MC4xNGE2LjUwNyA2LjUwNyAwIDAgMSA2LjUxMy02LjUxMyA2LjUwNyA2LjUwNyAwIDAgMSA2LjUxNCA2LjUxM3YxNi4yODRhNi41MDcgNi41MDcgMCAwIDEtNi41MTQgNi41MTMgNi41MDcgNi41MDcgMCAwIDEtNi41MTMtNi41MTN6Ii8+PHBhdGggZmlsbD0iIzM2QzVGMCIgZD0iTTIyLjg1NyAxMy45OWE2LjUwNyA2LjUwNyAwIDAgMS02LjUxMy02LjUxNEE2LjUwNyA2LjUwNyAwIDAgMSAyMi44NTcuOTYzYTYuNTA3IDYuNTA3IDAgMCAxIDYuNTE0IDYuNTEzdjYuNTE0ek0yMi44NTggMTcuMjk1YTYuNTA3IDYuNTA3IDAgMCAxIDYuNTEzIDYuNTEzIDYuNTA3IDYuNTA3IDAgMCAxLTYuNTEzIDYuNTE0SDYuNTI1YTYuNTA3IDYuNTA3IDAgMCAxLTYuNTEzLTYuNTE0IDYuNTA3IDYuNTA3IDAgMCAxIDYuNTEzLTYuNTEzeiIvPjxwYXRoIGZpbGw9IiMyRUI2N0QiIGQ9Ik00OC45NTkgMjMuODA4YTYuNTA3IDYuNTA3IDAgMCAxIDYuNTEzLTYuNTEzIDYuNTA3IDYuNTA3IDAgMCAxIDYuNTE0IDYuNTEzIDYuNTA3IDYuNTA3IDAgMCAxLTYuNTE0IDYuNTE0SDQ4Ljk2ek00NS43MDMgMjMuODFhNi41MDcgNi41MDcgMCAwIDEtNi41MTQgNi41MTMgNi41MDcgNi41MDcgMCAwIDEtNi41MTMtNi41MTRWNy40NzZBNi41MDcgNi41MDcgMCAwIDEgMzkuMTg5Ljk2M2E2LjUwNyA2LjUwNyAwIDAgMSA2LjUxNCA2LjUxM3oiLz48cGF0aCBmaWxsPSIjRUNCMjJFIiBkPSJNMzkuMTkgNDkuOTFhNi41MDcgNi41MDcgMCAwIDEgNi41MTMgNi41MTQgNi41MDcgNi41MDcgMCAwIDEtNi41MTQgNi41MTMgNi41MDcgNi41MDcgMCAwIDEtNi41MTMtNi41MTRWNDkuOTF6TTM5LjE5IDQ2LjY1NGE2LjUwNyA2LjUwNyAwIDAgMS02LjUxNC02LjUxNCA2LjUwNyA2LjUwNyAwIDAgMSA2LjUxMy02LjUxM2gxNi4zMzNhNi41MDcgNi41MDcgMCAwIDEgNi41MTMgNi41MTMgNi41MDcgNi41MDcgMCAwIDEtNi41MTMgNi41MTR6Ii8+PC9zdmc+) no-repeat;height:63px;width:62px}.documentation-banner_hL3X .documentation-banner-icon-drive_FABO{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MCIgaGVpZ2h0PSI1NCIgZmlsbD0ibm9uZSI+PG1hc2sgaWQ9ImEiIHdpZHRoPSI2MCIgaGVpZ2h0PSI1NCIgeD0iMCIgeT0iMCIgbWFza1VuaXRzPSJ1c2VyU3BhY2VPblVzZSIgc3R5bGU9Im1hc2stdHlwZTphbHBoYSI+PHBhdGggZmlsbD0iI0M0QzRDNCIgZD0iTTAgMGg1OS42ODR2NTRIMHoiLz48L21hc2s+PGcgbWFzaz0idXJsKCNhKSI+PHBhdGggZmlsbD0iIzExQTY2MSIgZD0iTTI5Ljg0MiAxNy42OTMgMTkuODk1LjY0MSAwIDM0Ljc0NmwxMS4zNjggMTcuMDUyeiIvPjxwYXRoIGZpbGw9IiNGREQwNTAiIGQ9Ik0zOS43OSAzNC43NDNoMTkuODk1TDQxLjA1OC42MzZIMTkuODk1eiIvPjxwYXRoIGZpbGw9IiMzNDdBRUYiIGQ9Im0yMC40NTIgMzQuNzQzLTkuMDg0IDE3LjA1MyAzOC43NzMuMjY0IDkuNTQzLTE3LjMxN3oiLz48L2c+PC9zdmc+) no-repeat;height:54px;width:60px}.documentation-banner_hL3X .documentation-banner-icon-github_p3sP{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MiIgaGVpZ2h0PSI2MiIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTAgMGg2MnY2MkgweiIvPjxwYXRoIGZpbGw9IiMxNjE1MTQiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTMwLjk5Ny44ODdDMTMuODgxLjg4NyAwIDE0LjcxIDAgMzEuNzY0YzAgMTMuNjQyIDguODgyIDI1LjIxNCAyMS4yIDI5LjI5NyAxLjU1MS4yODQgMi4xMTYtLjY3IDIuMTE2LTEuNDg4IDAtLjczMi0uMDI2LTIuNjc1LS4wNDEtNS4yNS04LjYyMyAxLjg2NC0xMC40NDMtNC4xNC0xMC40NDMtNC4xNC0xLjQxLTMuNTY4LTMuNDQyLTQuNTE3LTMuNDQyLTQuNTE3LTIuODE1LTEuOTE1LjIxMy0xLjg3Ny4yMTMtMS44NzcgMy4xMTEuMjE4IDQuNzQ4IDMuMTgyIDQuNzQ4IDMuMTgyIDIuNzY1IDQuNzE4IDcuMjU2IDMuMzU2IDkuMDIyIDIuNTY1LjI4Mi0xLjk5NCAxLjA4My0zLjM1NSAxLjk2OC00LjEyNi02Ljg4My0uNzgtMTQuMTItMy40My0xNC4xMi0xNS4yNiAwLTMuMzcxIDEuMjA4LTYuMTI5IDMuMTktOC4yODYtLjMxOS0uNzgxLTEuMzgzLTMuOTIyLjMwNS04LjE3MSAwIDAgMi42MDItLjgzIDguNTI0IDMuMTY1IDIuNDcyLS42ODYgNS4xMjUtMS4wMjcgNy43NjEtMS4wNCAyLjYzNC4wMTMgNS4yODUuMzU0IDcuNzYgMS4wNCA1LjkyLTMuOTk2IDguNTE3LTMuMTY1IDguNTE3LTMuMTY1IDEuNjkyIDQuMjUuNjI4IDcuMzkuMzEgOC4xNzEgMS45ODcgMi4xNTcgMy4xODYgNC45MTUgMy4xODYgOC4yODUgMCAxMS44NjItNy4yNDkgMTQuNDcyLTE0LjE1MyAxNS4yMzYgMS4xMTEuOTUzIDIuMTAzIDIuODM3IDIuMTAzIDUuNzE5IDAgNC4xMjYtLjAzOCA3LjQ1Ni0uMDM4IDguNDY5IDAgLjgyNi41NTkgMS43ODcgMi4xMzEgMS40ODZDNTMuMTI2IDU2Ljk2NiA2MiA0NS40MDIgNjIgMzEuNzY0IDYyIDE0LjcxIDQ4LjExOS44ODcgMzAuOTk3Ljg4NyIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+) no-repeat;height:62px;width:62px}.documentation-banner_hL3X .documentation-banner-icon-iot_nAKg{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI3OCIgaGVpZ2h0PSI3OCIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI0QwQ0VGRiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNjEuMDk5IDI2LjMzMWgyLjczN2M2LjAwMSAwIDEwLjg2NSA0LjkwNCAxMC44NjUgMTAuOTVzLTQuODY0IDEwLjk0NS0xMC44NjUgMTAuOTQ1SDQ0LjI4cS0uOTkyIDAtMS45Ni0uMTA5LS44MzguMTEtMS43MDEuMTFIMjYuMDYzYy00LjQ2NSAwLTguMDg1LTMuNTc5LTguMDg1LTcuOTkzIDAtNC40MTUgMy42Mi03Ljk5NSA4LjA4NS03Ljk5NWguODhjLS43NC04LjM4IDQuNjIxLTE2LjMxMiAxMi45NzUtMTguNDg2IDkuMjk4LTIuNDIxIDE4Ljc3OSAzLjIxNCAyMS4xODEgMTIuNTc4IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48cGF0aCBmaWxsPSIjNjM1REZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik02NS40MyAzNy44NzhhNS43NCA1Ljc0IDAgMCAwLTcuMzUgMCAuNjYuNjYgMCAwIDEtLjg0NC0xLjAxNCA3LjA2IDcuMDYgMCAwIDEgOS4wMzggMCAuNjYuNjYgMCAwIDEtLjg0NCAxLjAxNCIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iIzYzNURGRiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNjcuNDUyIDM1LjhhOC42NSA4LjY1IDAgMCAwLTExLjQ0MiAwIC42Ni42NiAwIDAgMS0uODcyLS45OSA5Ljk3IDkuOTcgMCAwIDEgMTMuMTg2IDAgLjY2LjY2IDAgMSAxLS44NzIuOTlNNjMuMzczIDM5Ljk4YTIuODMgMi44MyAwIDAgMC0zLjI4IDAgLjY2LjY2IDAgMSAxLS43NjUtMS4wNzYgNC4xNSA0LjE1IDAgMCAxIDQuODEgMCAuNjYuNjYgMCAxIDEtLjc2NSAxLjA3NSIgY2xpcC1ydWxlPSJldmVub2RkIi8+PHBhdGggZmlsbD0iIzYzNURGRiIgZD0iTTYyLjU1NyA0MS45OThhLjg3My44NzMgMCAxIDEtMS43NDYgMCAuODczLjg3MyAwIDAgMSAxLjc0NSAwIi8+PHBhdGggZmlsbD0iIzYzNURGRiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNNjEuNjg0IDQxLjU1MmEuNDQ2LjQ0NiAwIDEgMCAwIC44OTIuNDQ2LjQ0NiAwIDAgMCAwLS44OTJtMCAxLjMxOWEuODczLjg3MyAwIDEgMCAwLTEuNzQ2Ljg3My44NzMgMCAwIDAgMCAxLjc0NiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+) no-repeat;height:62px;width:90px}.documentation-banner_hL3X .documentation-banner-icon-playground_sgp9{background:url(/pr-preview/pr-921/assets/images/banner-playground-icon-aad8d03c3300233154438dc9eb98541c.svg) no-repeat;height:62px;width:62px}.documentation-banner_hL3X .documentation-banner-icon-entitlements_QMIV{background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2MiIgaGVpZ2h0PSI2MiIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iIzYzNURGRiIgZD0iTTUwLjQ1MyAxOS40NDhjMC01Ljc0Ni00LjY2LTEwLjQwNy0xMC40MDctMTAuNDA3LTUuNzQ4IDAtMTAuNDA2IDQuNjYtMTAuNDA2IDEwLjQwN3M0LjY2IDEwLjQwNiAxMC40MDcgMTAuNDA2IDEwLjQwNi00LjY1NyAxMC40MDYtMTAuNDA2Ii8+PHBhdGggZmlsbD0iI0QwQ0VGRiIgZD0iTTUzLjUzNSAzNi44OGExMS4yNiAxMS4yNiAwIDAgMC03Ljk2NS0zLjI5OEgzNC41MjJhMTEuMjYgMTEuMjYgMCAwIDAtMTEuMjY0IDExLjI2NHYyLjI0NGE0LjUxNSA0LjUxNSAwIDAgMCA0LjUxNSA0LjUxNGgyNC41NDZhNC41MTUgNC41MTUgMCAwIDAgNC41MTUtNC41MTR2LTIuMjQ0YzAtMi45ODUtMS4xODYtNS44NTItMy4yOTktNy45NjUiLz48cGF0aCBmaWxsPSIjNjM1REZGIiBkPSJNNy45MTQgMzkuMDUzYTYuNSA2LjUgMCAwIDAgNC41NiAxLjkxaC4wODhhNi40OCA2LjQ4IDAgMCAwIDQuNTg4LTEuOTkgNi40NyA2LjQ3IDAgMCAwIDEuODI4LTQuNjM5IDYuNDkgNi40OSAwIDAgMC01LjE0LTYuMjZWMTYuMjg1YTEuMjg2IDEuMjg2IDAgMCAwLTIuNTcxIDB2MS43MTJoLTIuNzVjLS43MSAwLTEuMjg2LjU3Ni0xLjI4NiAxLjI4NnY0LjA5N2MwIC43MS41NzYgMS4yODMgMS4yODYgMS4yODZoMi43NXYzLjM4NGMtMi45NzkuNTgyLTUuMjQ1IDMuMjAxLTUuMjY2IDYuMzUxYTYuNSA2LjUgMCAwIDAgMS45MTMgNC42NTJtNi43MjMtNi43NzVhMy4wNCAzLjA0IDAgMCAxIC44OTIgMi4xMTcgMy4wNjcgMy4wNjcgMCAwIDEtMy4wMSAzLjExNmgtLjAzYTMuMDcgMy4wNyAwIDAgMS0zLjA0My0zLjA4MmMuMDA2LS44Mi4zMjktMS41ODQuOTEtMi4xNmEzLjA0IDMuMDQgMCAwIDEgMi4xMzMtLjg4M2guMDNjLjgzMi4wMTIgMS41NzkuMzUgMi4xMTguODkyIi8+PC9zdmc+) no-repeat;height:62px;width:62px}.documentation-banner_hL3X .documentation-banner-content_N4KI{display:flex;flex-direction:column;height:100%;width:calc(100% - 165px)}.documentation-banner_hL3X .documentation-banner-content_N4KI .documentation-banner-title_tH3s{color:#1e212a;font-size:32px;font-weight:500;letter-spacing:-.5px;line-height:40px;margin-bottom:8px}.documentation-banner_hL3X .documentation-banner-content_N4KI .documentation-banner-description_rLpl{color:#42464d}.documentation-banner_hL3X .documentation-banner-chevron_qBL2{position:absolute;right:32px;top:calc(50% - 12px)}.documentation-card-box-link_yEiX,.documentation-link_vRVq{transition:.2s linear}.documentation-link-show-arrow-on-hover_XIYB:hover:after{content:"→";margin-left:4px;opacity:1;text-indent:0;transition:.2s linear}.documentation-card-box_SNqO{border:1px solid #bdc4cf;border-radius:24px;padding:32px}.documentation-card-box-border_zlYB{border:1px solid #bdc4cf!important}.documentation-card-box-fitcontent_koVg{height:fit-content}.documentation-card-box-children_i280{font-size:16px;font-weight:400;line-height:28px;margin:0!important}.documentation-card-box-children-small_Bayp ul{padding-left:14px}.documentation-card-box-children-small_Bayp li,.documentation-card-box-children-small_Bayp p,.documentation-card-box-children-small_Bayp ul{font-size:14px;font-weight:400;line-height:18px;margin:0!important}.documentation-card-box-children-mono_WQfY li,.documentation-card-box-children-mono_WQfY p,.documentation-card-box-children-mono_WQfY ul{font-size:14px;letter-spacing:1.5px;line-height:20px;margin:0!important}.documentation-card-box-icon_ZcC1{height:36px;width:36px}.documentation-card-box-icon-large_nsCS,.documentation-card-box-icon_ZcC1{align-items:center;background-color:#eff0f2;border-radius:6px;display:flex;justify-content:center}.documentation-card-box-icon-large_nsCS{height:48px;width:48px}.documentation-card-box-icon-label_ctwe{font-size:18px;font-weight:400;letter-spacing:-.05px;line-height:28px}.documentation-card-box-icon-title_zmVE{font-size:28px;font-weight:500;letter-spacing:-.3px;line-height:36px}.documentation-card-box-alignment-left__zex p{margin:0 0 0 10px}.documentation-card-box-alignment-left__zex span{margin:0 0 0 24px}.documentation-card-box-alignment-center_zUxy{align-items:center;display:flex;flex-direction:column;justify-content:center}.documentation-card-box-alignment-center_zUxy p{margin-top:10px}.documentation-card-box-gradient_ZcEA{background:linear-gradient(90deg,#635dff .01%,#3885ff 100.01%);border-radius:24px;padding:32px}.documentation-card-box-gradient_ZcEA *{color:#fff!important}.documentation-card-box-filled_F0BA{background-color:var(--ifm-color-emphasis-200);border:none;border-radius:24px;padding:32px}.documentation-card-box-content_Z5TD{display:flex;flex-direction:column;height:100%}.documentation-card-box-content_Z5TD code{background-color:var(--ifm-color-emphasis-300);font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.documentation-card-box-links_XUmL{color:var(--ifm-link-color);display:flex;flex-direction:column;font-size:16px;font-weight:500;height:100%;justify-content:flex-end;letter-spacing:0;line-height:24.4px;margin-top:16px}.documentation-card-box-links-justify-start_wwT4{justify-content:start}.documentation-card-box-link_yEiX:hover:after{content:"→";margin-left:.5rem;opacity:1;text-indent:0;transition:.2s linear}.documentation-card-box-links-numbered_Ebqk ul{list-style-type:decimal-leading-zero}.documentation-card-box-title_sKX3{font-size:20px;font-weight:500;letter-spacing:-.1px;line-height:26px;margin-bottom:16px}.documentation-card-box-title-center_Hqm8{font-size:20px;font-weight:500;letter-spacing:-.1px;line-height:26px;margin-bottom:0;text-align:center}.documentation-card-box-description_u7_j{font-size:16px;font-weight:400;letter-spacing:0;line-height:24px;margin:0}.column-layout-2_O2db{display:grid;gap:2rem;grid-template-columns:repeat(2,1fr)}.column-layout-3_YXBy{display:grid;gap:2rem;grid-template-columns:repeat(3,1fr)}.column-layout-4-equal-width_WOGz,.column-layout-4_SipK{display:grid;gap:1rem;grid-template-columns:repeat(4,1fr)}.column-layout-5-equal-width_CiKk,.column-layout-5_K6O8{display:grid;gap:1rem;grid-template-columns:repeat(5,1fr)}.documentation-feedback_yGAr{background:linear-gradient(333.17deg,#3ec6eb -1.51%,#635dff 101.22%);border-radius:24px;margin:48px 40px;max-height:213px;overflow:hidden;padding:32px;position:relative}.documentation-feedback-title_ZTWW{color:#fff;font-family:Inter;font-size:32px;font-weight:500;letter-spacing:-.5px;line-height:40px;margin-bottom:8px}.documentation-feedback-text_SR2j{color:#fff;font-family:Inter;font-size:16px;font-weight:400;letter-spacing:-.01px;line-height:24px;margin-bottom:18px}.documentation-feedback-pattern_jV72{border-radius:24px;position:absolute;right:0;top:0}.documentation-feedback-img_QGMs{margin-top:-16px}.documentation-feedback-button_kOg2{background-color:#1e212a;border:none;border-radius:8px;color:#fff!important;font-family:Inter;font-size:16px;font-weight:500;letter-spacing:-.05px;line-height:28px;padding:4.81px 18.65px}.documentation-feedback-button_kOg2 svg{margin-left:8px}.documentation-feedback-button_kOg2:hover{background-color:#42464d;cursor:pointer;transition:background-color .25s}.documentation-feedback-button_kOg2:not(hover){transition:background-color .25s}.documentation-feedback-button_kOg2:focus{box-shadow:0 0 0 .25em #000}.documentation-related-section-title_FCU2 h2{font-family:Inter;font-size:32px;font-weight:500;letter-spacing:-.5px;line-height:40px;margin-bottom:24px}.documentation-related-section-description_Un_N{font-size:18px;font-weight:400;letter-spacing:-.5;line-height:28px;margin-bottom:32px}.details_lb9f{--docusaurus-details-summary-arrow-size:0.38rem;--docusaurus-details-transition:transform 200ms ease;--docusaurus-details-decoration-color:grey}.details_lb9f>summary{cursor:pointer;list-style:none;padding-left:1rem;position:relative}.details_lb9f>summary::-webkit-details-marker{display:none}.details_lb9f>summary:before{border-color:#0000 #0000 #0000 var(--docusaurus-details-decoration-color);border-style:solid;border-width:var(--docusaurus-details-summary-arrow-size);content:"";left:0;position:absolute;top:.45rem;transform:rotate(0);transform-origin:calc(var(--docusaurus-details-summary-arrow-size)/2) 50%;transition:var(--docusaurus-details-transition)}.collapsibleContent_i85q{border-top:1px solid var(--docusaurus-details-decoration-color);margin-top:1rem;padding-top:1rem}.details_b_Ee{--docusaurus-details-decoration-color:var(--ifm-alert-border-color);--docusaurus-details-transition:transform var(--ifm-transition-fast) ease;border:1px solid var(--ifm-alert-border-color);margin:0 0 var(--ifm-spacing-vertical)}.containsTaskList_mC6p{list-style:none}.tableOfContents_bqdL{max-height:calc(100vh - var(--ifm-navbar-height) - 2rem);overflow-y:auto;position:sticky;top:calc(var(--ifm-navbar-height) + 1rem)}.breadcrumbHomeIcon_YNFT{height:1.1rem;position:relative;top:1px;vertical-align:top;width:1.1rem}.breadcrumbsContainer_Z_bl{--ifm-breadcrumb-size-multiplier:0.8;margin-bottom:.8rem}@media screen and (min-width:30em){.swagger-ui .aspect-ratio-ns{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-ns{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-ns{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-ns{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-ns{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-ns{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-ns{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-ns{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-ns{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-ns{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-ns{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-ns{padding-bottom:100%}.swagger-ui .aspect-ratio--object-ns{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%;z-index:100}.swagger-ui .cover-ns{background-size:cover!important}.swagger-ui .contain-ns{background-size:contain!important}.swagger-ui .bg-center-ns{background-position:50%;background-repeat:no-repeat}.swagger-ui .bg-top-ns{background-position:top;background-repeat:no-repeat}.swagger-ui .bg-right-ns{background-position:100%;background-repeat:no-repeat}.swagger-ui .bg-bottom-ns{background-position:bottom;background-repeat:no-repeat}.swagger-ui .bg-left-ns{background-position:0;background-repeat:no-repeat}.swagger-ui .outline-ns{outline:solid 1px}.swagger-ui .outline-transparent-ns{outline:#0000 solid 1px}.swagger-ui .outline-0-ns{outline:0}.swagger-ui .ba-ns{border-style:solid;border-width:1px}.swagger-ui .bt-ns{border-top-style:solid;border-top-width:1px}.swagger-ui .br-ns{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-ns{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-ns{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-ns{border-style:none;border-width:0}.swagger-ui .br0-ns{border-radius:0}.swagger-ui .br1-ns{border-radius:.125rem}.swagger-ui .br2-ns{border-radius:.25rem}.swagger-ui .br3-ns{border-radius:.5rem}.swagger-ui .br4-ns{border-radius:1rem}.swagger-ui .br-100-ns{border-radius:100%}.swagger-ui .br-pill-ns{border-radius:9999px}.swagger-ui .br--bottom-ns{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-ns{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-ns{border-bottom-left-radius:0;border-top-left-radius:0}.swagger-ui .br--left-ns{border-bottom-right-radius:0;border-top-right-radius:0}.swagger-ui .b--dotted-ns{border-style:dotted}.swagger-ui .b--dashed-ns{border-style:dashed}.swagger-ui .b--solid-ns{border-style:solid}.swagger-ui .b--none-ns{border-style:none}.swagger-ui .bw0-ns{border-width:0}.swagger-ui .bw1-ns{border-width:.125rem}.swagger-ui .bw2-ns{border-width:.25rem}.swagger-ui .bw3-ns{border-width:.5rem}.swagger-ui .bw4-ns{border-width:1rem}.swagger-ui .bw5-ns{border-width:2rem}.swagger-ui .bt-0-ns{border-top-width:0}.swagger-ui .br-0-ns{border-right-width:0}.swagger-ui .bb-0-ns{border-bottom-width:0}.swagger-ui .bl-0-ns{border-left-width:0}.swagger-ui .shadow-1-ns{box-shadow:0 0 4px 2px #0003}.swagger-ui .shadow-2-ns{box-shadow:0 0 8px 2px #0003}.swagger-ui .shadow-3-ns{box-shadow:2px 2px 4px 2px #0003}.swagger-ui .shadow-4-ns{box-shadow:2px 2px 8px 0 #0003}.swagger-ui .shadow-5-ns{box-shadow:4px 4px 8px 0 #0003}.swagger-ui .top-0-ns{top:0}.swagger-ui .left-0-ns{left:0}.swagger-ui .right-0-ns{right:0}.swagger-ui .bottom-0-ns{bottom:0}.swagger-ui .top-1-ns{top:1rem}.swagger-ui .left-1-ns{left:1rem}.swagger-ui .right-1-ns{right:1rem}.swagger-ui .bottom-1-ns{bottom:1rem}.swagger-ui .top-2-ns{top:2rem}.swagger-ui .left-2-ns{left:2rem}.swagger-ui .right-2-ns{right:2rem}.swagger-ui .bottom-2-ns{bottom:2rem}.swagger-ui .top--1-ns{top:-1rem}.swagger-ui .right--1-ns{right:-1rem}.swagger-ui .bottom--1-ns{bottom:-1rem}.swagger-ui .left--1-ns{left:-1rem}.swagger-ui .top--2-ns{top:-2rem}.swagger-ui .right--2-ns{right:-2rem}.swagger-ui .bottom--2-ns{bottom:-2rem}.swagger-ui .left--2-ns{left:-2rem}.swagger-ui .absolute--fill-ns{bottom:0;left:0;right:0;top:0}.swagger-ui .cl-ns{clear:left}.swagger-ui .cr-ns{clear:right}.swagger-ui .cb-ns{clear:both}.swagger-ui .cn-ns{clear:none}.swagger-ui .flex-ns{display:flex}.swagger-ui .inline-flex-ns{display:inline-flex}.swagger-ui .flex-auto-ns{flex:1 1 auto;min-height:0;min-width:0}.swagger-ui .flex-none-ns{flex:none}.swagger-ui .flex-column-ns{flex-direction:column}.swagger-ui .flex-row-ns{flex-direction:row}.swagger-ui .flex-wrap-ns{flex-wrap:wrap}.swagger-ui .flex-nowrap-ns{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-ns{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-ns{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-ns{flex-direction:row-reverse}.swagger-ui .items-start-ns{align-items:flex-start}.swagger-ui .items-end-ns{align-items:flex-end}.swagger-ui .items-center-ns{align-items:center}.swagger-ui .items-baseline-ns{align-items:baseline}.swagger-ui .items-stretch-ns{align-items:stretch}.swagger-ui .self-start-ns{align-self:flex-start}.swagger-ui .self-end-ns{align-self:flex-end}.swagger-ui .self-center-ns{align-self:center}.swagger-ui .self-baseline-ns{align-self:baseline}.swagger-ui .self-stretch-ns{align-self:stretch}.swagger-ui .justify-start-ns{justify-content:flex-start}.swagger-ui .justify-end-ns{justify-content:flex-end}.swagger-ui .justify-center-ns{justify-content:center}.swagger-ui .justify-between-ns{justify-content:space-between}.swagger-ui .justify-around-ns{justify-content:space-around}.swagger-ui .content-start-ns{align-content:flex-start}.swagger-ui .content-end-ns{align-content:flex-end}.swagger-ui .content-center-ns{align-content:center}.swagger-ui .content-between-ns{align-content:space-between}.swagger-ui .content-around-ns{align-content:space-around}.swagger-ui .content-stretch-ns{align-content:stretch}.swagger-ui .order-0-ns{order:0}.swagger-ui .order-1-ns{order:1}.swagger-ui .order-2-ns{order:2}.swagger-ui .order-3-ns{order:3}.swagger-ui .order-4-ns{order:4}.swagger-ui .order-5-ns{order:5}.swagger-ui .order-6-ns{order:6}.swagger-ui .order-7-ns{order:7}.swagger-ui .order-8-ns{order:8}.swagger-ui .order-last-ns{order:99999}.swagger-ui .flex-grow-0-ns{flex-grow:0}.swagger-ui .flex-grow-1-ns{flex-grow:1}.swagger-ui .flex-shrink-0-ns{flex-shrink:0}.swagger-ui .flex-shrink-1-ns{flex-shrink:1}.swagger-ui .dn-ns{display:none}.swagger-ui .di-ns{display:inline}.swagger-ui .db-ns{display:block}.swagger-ui .dib-ns{display:inline-block}.swagger-ui .dit-ns{display:inline-table}.swagger-ui .dt-ns{display:table}.swagger-ui .dtc-ns{display:table-cell}.swagger-ui .dt-row-ns{display:table-row}.swagger-ui .dt-row-group-ns{display:table-row-group}.swagger-ui .dt-column-ns{display:table-column}.swagger-ui .dt-column-group-ns{display:table-column-group}.swagger-ui .dt--fixed-ns{table-layout:fixed;width:100%}.swagger-ui .fl-ns{float:left}.swagger-ui .fr-ns{float:right}.swagger-ui .fn-ns{float:none}.swagger-ui .i-ns{font-style:italic}.swagger-ui .fs-normal-ns{font-style:normal}.swagger-ui .fw4-ns,.swagger-ui .normal-ns{font-weight:400}.swagger-ui .b-ns,.swagger-ui .fw7-ns{font-weight:700}.swagger-ui .fw1-ns{font-weight:100}.swagger-ui .fw2-ns{font-weight:200}.swagger-ui .fw3-ns{font-weight:300}.swagger-ui .fw5-ns{font-weight:500}.swagger-ui .fw6-ns{font-weight:600}.swagger-ui .fw8-ns{font-weight:800}.swagger-ui .fw9-ns{font-weight:900}.swagger-ui .h1-ns{height:1rem}.swagger-ui .h2-ns{height:2rem}.swagger-ui .h3-ns{height:4rem}.swagger-ui .h4-ns{height:8rem}.swagger-ui .h5-ns{height:16rem}.swagger-ui .h-25-ns{height:25%}.swagger-ui .h-50-ns{height:50%}.swagger-ui .h-75-ns{height:75%}.swagger-ui .h-100-ns{height:100%}.swagger-ui .min-h-100-ns{min-height:100%}.swagger-ui .vh-25-ns{height:25vh}.swagger-ui .vh-50-ns{height:50vh}.swagger-ui .vh-75-ns{height:75vh}.swagger-ui .vh-100-ns{height:100vh}.swagger-ui .min-vh-100-ns{min-height:100vh}.swagger-ui .h-auto-ns{height:auto}.swagger-ui .h-inherit-ns{height:inherit}.swagger-ui .tracked-ns{letter-spacing:.1em}.swagger-ui .tracked-tight-ns{letter-spacing:-.05em}.swagger-ui .tracked-mega-ns{letter-spacing:.25em}.swagger-ui .lh-solid-ns{line-height:1}.swagger-ui .lh-title-ns{line-height:1.25}.swagger-ui .lh-copy-ns{line-height:1.5}.swagger-ui .mw-100-ns{max-width:100%}.swagger-ui .mw1-ns{max-width:1rem}.swagger-ui .mw2-ns{max-width:2rem}.swagger-ui .mw3-ns{max-width:4rem}.swagger-ui .mw4-ns{max-width:8rem}.swagger-ui .mw5-ns{max-width:16rem}.swagger-ui .mw6-ns{max-width:32rem}.swagger-ui .mw7-ns{max-width:48rem}.swagger-ui .mw8-ns{max-width:64rem}.swagger-ui .mw9-ns{max-width:96rem}.swagger-ui .mw-none-ns{max-width:none}.swagger-ui .w1-ns{width:1rem}.swagger-ui .w2-ns{width:2rem}.swagger-ui .w3-ns{width:4rem}.swagger-ui .w4-ns{width:8rem}.swagger-ui .w5-ns{width:16rem}.swagger-ui .w-10-ns{width:10%}.swagger-ui .w-20-ns{width:20%}.swagger-ui .w-25-ns{width:25%}.swagger-ui .w-30-ns{width:30%}.swagger-ui .w-33-ns{width:33%}.swagger-ui .w-34-ns{width:34%}.swagger-ui .w-40-ns{width:40%}.swagger-ui .w-50-ns{width:50%}.swagger-ui .w-60-ns{width:60%}.swagger-ui .w-70-ns{width:70%}.swagger-ui .w-75-ns{width:75%}.swagger-ui .w-80-ns{width:80%}.swagger-ui .w-90-ns{width:90%}.swagger-ui .w-100-ns{width:100%}.swagger-ui .w-third-ns{width:33.3333333333%}.swagger-ui .w-two-thirds-ns{width:66.6666666667%}.swagger-ui .w-auto-ns{width:auto}.swagger-ui .overflow-visible-ns{overflow:visible}.swagger-ui .overflow-hidden-ns{overflow:hidden}.swagger-ui .overflow-scroll-ns{overflow:scroll}.swagger-ui .overflow-auto-ns{overflow:auto}.swagger-ui .overflow-x-visible-ns{overflow-x:visible}.swagger-ui .overflow-x-hidden-ns{overflow-x:hidden}.swagger-ui .overflow-x-scroll-ns{overflow-x:scroll}.swagger-ui .overflow-x-auto-ns{overflow-x:auto}.swagger-ui .overflow-y-visible-ns{overflow-y:visible}.swagger-ui .overflow-y-hidden-ns{overflow-y:hidden}.swagger-ui .overflow-y-scroll-ns{overflow-y:scroll}.swagger-ui .overflow-y-auto-ns{overflow-y:auto}.swagger-ui .static-ns{position:static}.swagger-ui .relative-ns{position:relative}.swagger-ui .absolute-ns{position:absolute}.swagger-ui .fixed-ns{position:fixed}.swagger-ui .rotate-45-ns{transform:rotate(45deg)}.swagger-ui .rotate-90-ns{transform:rotate(90deg)}.swagger-ui .rotate-135-ns{transform:rotate(135deg)}.swagger-ui .rotate-180-ns{transform:rotate(180deg)}.swagger-ui .rotate-225-ns{transform:rotate(225deg)}.swagger-ui .rotate-270-ns{transform:rotate(270deg)}.swagger-ui .rotate-315-ns{transform:rotate(315deg)}.swagger-ui .pa0-ns{padding:0}.swagger-ui .pa1-ns{padding:.25rem}.swagger-ui .pa2-ns{padding:.5rem}.swagger-ui .pa3-ns{padding:1rem}.swagger-ui .pa4-ns{padding:2rem}.swagger-ui .pa5-ns{padding:4rem}.swagger-ui .pa6-ns{padding:8rem}.swagger-ui .pa7-ns{padding:16rem}.swagger-ui .pl0-ns{padding-left:0}.swagger-ui .pl1-ns{padding-left:.25rem}.swagger-ui .pl2-ns{padding-left:.5rem}.swagger-ui .pl3-ns{padding-left:1rem}.swagger-ui .pl4-ns{padding-left:2rem}.swagger-ui .pl5-ns{padding-left:4rem}.swagger-ui .pl6-ns{padding-left:8rem}.swagger-ui .pl7-ns{padding-left:16rem}.swagger-ui .pr0-ns{padding-right:0}.swagger-ui .pr1-ns{padding-right:.25rem}.swagger-ui .pr2-ns{padding-right:.5rem}.swagger-ui .pr3-ns{padding-right:1rem}.swagger-ui .pr4-ns{padding-right:2rem}.swagger-ui .pr5-ns{padding-right:4rem}.swagger-ui .pr6-ns{padding-right:8rem}.swagger-ui .pr7-ns{padding-right:16rem}.swagger-ui .pb0-ns{padding-bottom:0}.swagger-ui .pb1-ns{padding-bottom:.25rem}.swagger-ui .pb2-ns{padding-bottom:.5rem}.swagger-ui .pb3-ns{padding-bottom:1rem}.swagger-ui .pb4-ns{padding-bottom:2rem}.swagger-ui .pb5-ns{padding-bottom:4rem}.swagger-ui .pb6-ns{padding-bottom:8rem}.swagger-ui .pb7-ns{padding-bottom:16rem}.swagger-ui .pt0-ns{padding-top:0}.swagger-ui .pt1-ns{padding-top:.25rem}.swagger-ui .pt2-ns{padding-top:.5rem}.swagger-ui .pt3-ns{padding-top:1rem}.swagger-ui .pt4-ns{padding-top:2rem}.swagger-ui .pt5-ns{padding-top:4rem}.swagger-ui .pt6-ns{padding-top:8rem}.swagger-ui .pt7-ns{padding-top:16rem}.swagger-ui .pv0-ns{padding-bottom:0;padding-top:0}.swagger-ui .pv1-ns{padding-bottom:.25rem;padding-top:.25rem}.swagger-ui .pv2-ns{padding-bottom:.5rem;padding-top:.5rem}.swagger-ui .pv3-ns{padding-bottom:1rem;padding-top:1rem}.swagger-ui .pv4-ns{padding-bottom:2rem;padding-top:2rem}.swagger-ui .pv5-ns{padding-bottom:4rem;padding-top:4rem}.swagger-ui .pv6-ns{padding-bottom:8rem;padding-top:8rem}.swagger-ui .pv7-ns{padding-bottom:16rem;padding-top:16rem}.swagger-ui .ph0-ns{padding-left:0;padding-right:0}.swagger-ui .ph1-ns{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-ns{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-ns{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-ns{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-ns{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-ns{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-ns{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-ns{margin:0}.swagger-ui .ma1-ns{margin:.25rem}.swagger-ui .ma2-ns{margin:.5rem}.swagger-ui .ma3-ns{margin:1rem}.swagger-ui .ma4-ns{margin:2rem}.swagger-ui .ma5-ns{margin:4rem}.swagger-ui .ma6-ns{margin:8rem}.swagger-ui .ma7-ns{margin:16rem}.swagger-ui .ml0-ns{margin-left:0}.swagger-ui .ml1-ns{margin-left:.25rem}.swagger-ui .ml2-ns{margin-left:.5rem}.swagger-ui .ml3-ns{margin-left:1rem}.swagger-ui .ml4-ns{margin-left:2rem}.swagger-ui .ml5-ns{margin-left:4rem}.swagger-ui .ml6-ns{margin-left:8rem}.swagger-ui .ml7-ns{margin-left:16rem}.swagger-ui .mr0-ns{margin-right:0}.swagger-ui .mr1-ns{margin-right:.25rem}.swagger-ui .mr2-ns{margin-right:.5rem}.swagger-ui .mr3-ns{margin-right:1rem}.swagger-ui .mr4-ns{margin-right:2rem}.swagger-ui .mr5-ns{margin-right:4rem}.swagger-ui .mr6-ns{margin-right:8rem}.swagger-ui .mr7-ns{margin-right:16rem}.swagger-ui .mb0-ns{margin-bottom:0}.swagger-ui .mb1-ns{margin-bottom:.25rem}.swagger-ui .mb2-ns{margin-bottom:.5rem}.swagger-ui .mb3-ns{margin-bottom:1rem}.swagger-ui .mb4-ns{margin-bottom:2rem}.swagger-ui .mb5-ns{margin-bottom:4rem}.swagger-ui .mb6-ns{margin-bottom:8rem}.swagger-ui .mb7-ns{margin-bottom:16rem}.swagger-ui .mt0-ns{margin-top:0}.swagger-ui .mt1-ns{margin-top:.25rem}.swagger-ui .mt2-ns{margin-top:.5rem}.swagger-ui .mt3-ns{margin-top:1rem}.swagger-ui .mt4-ns{margin-top:2rem}.swagger-ui .mt5-ns{margin-top:4rem}.swagger-ui .mt6-ns{margin-top:8rem}.swagger-ui .mt7-ns{margin-top:16rem}.swagger-ui .mv0-ns{margin-bottom:0;margin-top:0}.swagger-ui .mv1-ns{margin-bottom:.25rem;margin-top:.25rem}.swagger-ui .mv2-ns{margin-bottom:.5rem;margin-top:.5rem}.swagger-ui .mv3-ns{margin-bottom:1rem;margin-top:1rem}.swagger-ui .mv4-ns{margin-bottom:2rem;margin-top:2rem}.swagger-ui .mv5-ns{margin-bottom:4rem;margin-top:4rem}.swagger-ui .mv6-ns{margin-bottom:8rem;margin-top:8rem}.swagger-ui .mv7-ns{margin-bottom:16rem;margin-top:16rem}.swagger-ui .mh0-ns{margin-left:0;margin-right:0}.swagger-ui .mh1-ns{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-ns{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-ns{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-ns{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-ns{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-ns{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-ns{margin-left:16rem;margin-right:16rem}.swagger-ui .na1-ns{margin:-.25rem}.swagger-ui .na2-ns{margin:-.5rem}.swagger-ui .na3-ns{margin:-1rem}.swagger-ui .na4-ns{margin:-2rem}.swagger-ui .na5-ns{margin:-4rem}.swagger-ui .na6-ns{margin:-8rem}.swagger-ui .na7-ns{margin:-16rem}.swagger-ui .nl1-ns{margin-left:-.25rem}.swagger-ui .nl2-ns{margin-left:-.5rem}.swagger-ui .nl3-ns{margin-left:-1rem}.swagger-ui .nl4-ns{margin-left:-2rem}.swagger-ui .nl5-ns{margin-left:-4rem}.swagger-ui .nl6-ns{margin-left:-8rem}.swagger-ui .nl7-ns{margin-left:-16rem}.swagger-ui .nr1-ns{margin-right:-.25rem}.swagger-ui .nr2-ns{margin-right:-.5rem}.swagger-ui .nr3-ns{margin-right:-1rem}.swagger-ui .nr4-ns{margin-right:-2rem}.swagger-ui .nr5-ns{margin-right:-4rem}.swagger-ui .nr6-ns{margin-right:-8rem}.swagger-ui .nr7-ns{margin-right:-16rem}.swagger-ui .nb1-ns{margin-bottom:-.25rem}.swagger-ui .nb2-ns{margin-bottom:-.5rem}.swagger-ui .nb3-ns{margin-bottom:-1rem}.swagger-ui .nb4-ns{margin-bottom:-2rem}.swagger-ui .nb5-ns{margin-bottom:-4rem}.swagger-ui .nb6-ns{margin-bottom:-8rem}.swagger-ui .nb7-ns{margin-bottom:-16rem}.swagger-ui .nt1-ns{margin-top:-.25rem}.swagger-ui .nt2-ns{margin-top:-.5rem}.swagger-ui .nt3-ns{margin-top:-1rem}.swagger-ui .nt4-ns{margin-top:-2rem}.swagger-ui .nt5-ns{margin-top:-4rem}.swagger-ui .nt6-ns{margin-top:-8rem}.swagger-ui .nt7-ns{margin-top:-16rem}.swagger-ui .strike-ns{-webkit-text-decoration:line-through;text-decoration:line-through}.swagger-ui .underline-ns{-webkit-text-decoration:underline;text-decoration:underline}.swagger-ui .no-underline-ns{-webkit-text-decoration:none;text-decoration:none}.swagger-ui .tl-ns{text-align:left}.swagger-ui .tr-ns{text-align:right}.swagger-ui .tc-ns{text-align:center}.swagger-ui .tj-ns{text-align:justify}.swagger-ui .ttc-ns{text-transform:capitalize}.swagger-ui .ttl-ns{text-transform:lowercase}.swagger-ui .ttu-ns{text-transform:uppercase}.swagger-ui .ttn-ns{text-transform:none}.swagger-ui .f-6-ns,.swagger-ui .f-headline-ns{font-size:6rem}.swagger-ui .f-5-ns,.swagger-ui .f-subheadline-ns{font-size:5rem}.swagger-ui .f1-ns{font-size:3rem}.swagger-ui .f2-ns{font-size:2.25rem}.swagger-ui .f3-ns{font-size:1.5rem}.swagger-ui .f4-ns{font-size:1.25rem}.swagger-ui .f5-ns{font-size:1rem}.swagger-ui .f6-ns{font-size:.875rem}.swagger-ui .f7-ns{font-size:.75rem}.swagger-ui .measure-ns{max-width:30em}.swagger-ui .measure-wide-ns{max-width:34em}.swagger-ui .measure-narrow-ns{max-width:20em}.swagger-ui .indent-ns{margin-bottom:0;margin-top:0;text-indent:1em}.swagger-ui .small-caps-ns{font-feature-settings:"smcp","smcp";font-variant:small-caps}.swagger-ui .truncate-ns{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.swagger-ui .center-ns{margin-left:auto;margin-right:auto}.swagger-ui .mr-auto-ns{margin-right:auto}.swagger-ui .ml-auto-ns{margin-left:auto}.swagger-ui .clip-ns{clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);position:fixed!important}.swagger-ui .ws-normal-ns{white-space:normal}.swagger-ui .nowrap-ns{white-space:nowrap}.swagger-ui .pre-ns{white-space:pre}.swagger-ui .v-base-ns{vertical-align:initial}.swagger-ui .v-mid-ns{vertical-align:middle}.swagger-ui .v-top-ns{vertical-align:top}.swagger-ui .v-btm-ns{vertical-align:bottom}}@media screen and (min-width:30em) and (max-width:60em){.swagger-ui .aspect-ratio-m{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-m{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-m{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-m{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-m{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-m{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-m{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-m{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-m{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-m{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-m{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-m{padding-bottom:100%}.swagger-ui .aspect-ratio--object-m{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%;z-index:100}.swagger-ui .cover-m{background-size:cover!important}.swagger-ui .contain-m{background-size:contain!important}.swagger-ui .bg-center-m{background-position:50%;background-repeat:no-repeat}.swagger-ui .bg-top-m{background-position:top;background-repeat:no-repeat}.swagger-ui .bg-right-m{background-position:100%;background-repeat:no-repeat}.swagger-ui .bg-bottom-m{background-position:bottom;background-repeat:no-repeat}.swagger-ui .bg-left-m{background-position:0;background-repeat:no-repeat}.swagger-ui .outline-m{outline:solid 1px}.swagger-ui .outline-transparent-m{outline:#0000 solid 1px}.swagger-ui .outline-0-m{outline:0}.swagger-ui .ba-m{border-style:solid;border-width:1px}.swagger-ui .bt-m{border-top-style:solid;border-top-width:1px}.swagger-ui .br-m{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-m{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-m{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-m{border-style:none;border-width:0}.swagger-ui .br0-m{border-radius:0}.swagger-ui .br1-m{border-radius:.125rem}.swagger-ui .br2-m{border-radius:.25rem}.swagger-ui .br3-m{border-radius:.5rem}.swagger-ui .br4-m{border-radius:1rem}.swagger-ui .br-100-m{border-radius:100%}.swagger-ui .br-pill-m{border-radius:9999px}.swagger-ui .br--bottom-m{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-m{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-m{border-bottom-left-radius:0;border-top-left-radius:0}.swagger-ui .br--left-m{border-bottom-right-radius:0;border-top-right-radius:0}.swagger-ui .b--dotted-m{border-style:dotted}.swagger-ui .b--dashed-m{border-style:dashed}.swagger-ui .b--solid-m{border-style:solid}.swagger-ui .b--none-m{border-style:none}.swagger-ui .bw0-m{border-width:0}.swagger-ui .bw1-m{border-width:.125rem}.swagger-ui .bw2-m{border-width:.25rem}.swagger-ui .bw3-m{border-width:.5rem}.swagger-ui .bw4-m{border-width:1rem}.swagger-ui .bw5-m{border-width:2rem}.swagger-ui .bt-0-m{border-top-width:0}.swagger-ui .br-0-m{border-right-width:0}.swagger-ui .bb-0-m{border-bottom-width:0}.swagger-ui .bl-0-m{border-left-width:0}.swagger-ui .shadow-1-m{box-shadow:0 0 4px 2px #0003}.swagger-ui .shadow-2-m{box-shadow:0 0 8px 2px #0003}.swagger-ui .shadow-3-m{box-shadow:2px 2px 4px 2px #0003}.swagger-ui .shadow-4-m{box-shadow:2px 2px 8px 0 #0003}.swagger-ui .shadow-5-m{box-shadow:4px 4px 8px 0 #0003}.swagger-ui .top-0-m{top:0}.swagger-ui .left-0-m{left:0}.swagger-ui .right-0-m{right:0}.swagger-ui .bottom-0-m{bottom:0}.swagger-ui .top-1-m{top:1rem}.swagger-ui .left-1-m{left:1rem}.swagger-ui .right-1-m{right:1rem}.swagger-ui .bottom-1-m{bottom:1rem}.swagger-ui .top-2-m{top:2rem}.swagger-ui .left-2-m{left:2rem}.swagger-ui .right-2-m{right:2rem}.swagger-ui .bottom-2-m{bottom:2rem}.swagger-ui .top--1-m{top:-1rem}.swagger-ui .right--1-m{right:-1rem}.swagger-ui .bottom--1-m{bottom:-1rem}.swagger-ui .left--1-m{left:-1rem}.swagger-ui .top--2-m{top:-2rem}.swagger-ui .right--2-m{right:-2rem}.swagger-ui .bottom--2-m{bottom:-2rem}.swagger-ui .left--2-m{left:-2rem}.swagger-ui .absolute--fill-m{bottom:0;left:0;right:0;top:0}.swagger-ui .cl-m{clear:left}.swagger-ui .cr-m{clear:right}.swagger-ui .cb-m{clear:both}.swagger-ui .cn-m{clear:none}.swagger-ui .flex-m{display:flex}.swagger-ui .inline-flex-m{display:inline-flex}.swagger-ui .flex-auto-m{flex:1 1 auto;min-height:0;min-width:0}.swagger-ui .flex-none-m{flex:none}.swagger-ui .flex-column-m{flex-direction:column}.swagger-ui .flex-row-m{flex-direction:row}.swagger-ui .flex-wrap-m{flex-wrap:wrap}.swagger-ui .flex-nowrap-m{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-m{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-m{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-m{flex-direction:row-reverse}.swagger-ui .items-start-m{align-items:flex-start}.swagger-ui .items-end-m{align-items:flex-end}.swagger-ui .items-center-m{align-items:center}.swagger-ui .items-baseline-m{align-items:baseline}.swagger-ui .items-stretch-m{align-items:stretch}.swagger-ui .self-start-m{align-self:flex-start}.swagger-ui .self-end-m{align-self:flex-end}.swagger-ui .self-center-m{align-self:center}.swagger-ui .self-baseline-m{align-self:baseline}.swagger-ui .self-stretch-m{align-self:stretch}.swagger-ui .justify-start-m{justify-content:flex-start}.swagger-ui .justify-end-m{justify-content:flex-end}.swagger-ui .justify-center-m{justify-content:center}.swagger-ui .justify-between-m{justify-content:space-between}.swagger-ui .justify-around-m{justify-content:space-around}.swagger-ui .content-start-m{align-content:flex-start}.swagger-ui .content-end-m{align-content:flex-end}.swagger-ui .content-center-m{align-content:center}.swagger-ui .content-between-m{align-content:space-between}.swagger-ui .content-around-m{align-content:space-around}.swagger-ui .content-stretch-m{align-content:stretch}.swagger-ui .order-0-m{order:0}.swagger-ui .order-1-m{order:1}.swagger-ui .order-2-m{order:2}.swagger-ui .order-3-m{order:3}.swagger-ui .order-4-m{order:4}.swagger-ui .order-5-m{order:5}.swagger-ui .order-6-m{order:6}.swagger-ui .order-7-m{order:7}.swagger-ui .order-8-m{order:8}.swagger-ui .order-last-m{order:99999}.swagger-ui .flex-grow-0-m{flex-grow:0}.swagger-ui .flex-grow-1-m{flex-grow:1}.swagger-ui .flex-shrink-0-m{flex-shrink:0}.swagger-ui .flex-shrink-1-m{flex-shrink:1}.swagger-ui .dn-m{display:none}.swagger-ui .di-m{display:inline}.swagger-ui .db-m{display:block}.swagger-ui .dib-m{display:inline-block}.swagger-ui .dit-m{display:inline-table}.swagger-ui .dt-m{display:table}.swagger-ui .dtc-m{display:table-cell}.swagger-ui .dt-row-m{display:table-row}.swagger-ui .dt-row-group-m{display:table-row-group}.swagger-ui .dt-column-m{display:table-column}.swagger-ui .dt-column-group-m{display:table-column-group}.swagger-ui .dt--fixed-m{table-layout:fixed;width:100%}.swagger-ui .fl-m{float:left}.swagger-ui .fr-m{float:right}.swagger-ui .fn-m{float:none}.swagger-ui .i-m{font-style:italic}.swagger-ui .fs-normal-m{font-style:normal}.swagger-ui .fw4-m,.swagger-ui .normal-m{font-weight:400}.swagger-ui .b-m,.swagger-ui .fw7-m{font-weight:700}.swagger-ui .fw1-m{font-weight:100}.swagger-ui .fw2-m{font-weight:200}.swagger-ui .fw3-m{font-weight:300}.swagger-ui .fw5-m{font-weight:500}.swagger-ui .fw6-m{font-weight:600}.swagger-ui .fw8-m{font-weight:800}.swagger-ui .fw9-m{font-weight:900}.swagger-ui .h1-m{height:1rem}.swagger-ui .h2-m{height:2rem}.swagger-ui .h3-m{height:4rem}.swagger-ui .h4-m{height:8rem}.swagger-ui .h5-m{height:16rem}.swagger-ui .h-25-m{height:25%}.swagger-ui .h-50-m{height:50%}.swagger-ui .h-75-m{height:75%}.swagger-ui .h-100-m{height:100%}.swagger-ui .min-h-100-m{min-height:100%}.swagger-ui .vh-25-m{height:25vh}.swagger-ui .vh-50-m{height:50vh}.swagger-ui .vh-75-m{height:75vh}.swagger-ui .vh-100-m{height:100vh}.swagger-ui .min-vh-100-m{min-height:100vh}.swagger-ui .h-auto-m{height:auto}.swagger-ui .h-inherit-m{height:inherit}.swagger-ui .tracked-m{letter-spacing:.1em}.swagger-ui .tracked-tight-m{letter-spacing:-.05em}.swagger-ui .tracked-mega-m{letter-spacing:.25em}.swagger-ui .lh-solid-m{line-height:1}.swagger-ui .lh-title-m{line-height:1.25}.swagger-ui .lh-copy-m{line-height:1.5}.swagger-ui .mw-100-m{max-width:100%}.swagger-ui .mw1-m{max-width:1rem}.swagger-ui .mw2-m{max-width:2rem}.swagger-ui .mw3-m{max-width:4rem}.swagger-ui .mw4-m{max-width:8rem}.swagger-ui .mw5-m{max-width:16rem}.swagger-ui .mw6-m{max-width:32rem}.swagger-ui .mw7-m{max-width:48rem}.swagger-ui .mw8-m{max-width:64rem}.swagger-ui .mw9-m{max-width:96rem}.swagger-ui .mw-none-m{max-width:none}.swagger-ui .w1-m{width:1rem}.swagger-ui .w2-m{width:2rem}.swagger-ui .w3-m{width:4rem}.swagger-ui .w4-m{width:8rem}.swagger-ui .w5-m{width:16rem}.swagger-ui .w-10-m{width:10%}.swagger-ui .w-20-m{width:20%}.swagger-ui .w-25-m{width:25%}.swagger-ui .w-30-m{width:30%}.swagger-ui .w-33-m{width:33%}.swagger-ui .w-34-m{width:34%}.swagger-ui .w-40-m{width:40%}.swagger-ui .w-50-m{width:50%}.swagger-ui .w-60-m{width:60%}.swagger-ui .w-70-m{width:70%}.swagger-ui .w-75-m{width:75%}.swagger-ui .w-80-m{width:80%}.swagger-ui .w-90-m{width:90%}.swagger-ui .w-100-m{width:100%}.swagger-ui .w-third-m{width:33.3333333333%}.swagger-ui .w-two-thirds-m{width:66.6666666667%}.swagger-ui .w-auto-m{width:auto}.swagger-ui .overflow-visible-m{overflow:visible}.swagger-ui .overflow-hidden-m{overflow:hidden}.swagger-ui .overflow-scroll-m{overflow:scroll}.swagger-ui .overflow-auto-m{overflow:auto}.swagger-ui .overflow-x-visible-m{overflow-x:visible}.swagger-ui .overflow-x-hidden-m{overflow-x:hidden}.swagger-ui .overflow-x-scroll-m{overflow-x:scroll}.swagger-ui .overflow-x-auto-m{overflow-x:auto}.swagger-ui .overflow-y-visible-m{overflow-y:visible}.swagger-ui .overflow-y-hidden-m{overflow-y:hidden}.swagger-ui .overflow-y-scroll-m{overflow-y:scroll}.swagger-ui .overflow-y-auto-m{overflow-y:auto}.swagger-ui .static-m{position:static}.swagger-ui .relative-m{position:relative}.swagger-ui .absolute-m{position:absolute}.swagger-ui .fixed-m{position:fixed}.swagger-ui .rotate-45-m{transform:rotate(45deg)}.swagger-ui .rotate-90-m{transform:rotate(90deg)}.swagger-ui .rotate-135-m{transform:rotate(135deg)}.swagger-ui .rotate-180-m{transform:rotate(180deg)}.swagger-ui .rotate-225-m{transform:rotate(225deg)}.swagger-ui .rotate-270-m{transform:rotate(270deg)}.swagger-ui .rotate-315-m{transform:rotate(315deg)}.swagger-ui .pa0-m{padding:0}.swagger-ui .pa1-m{padding:.25rem}.swagger-ui .pa2-m{padding:.5rem}.swagger-ui .pa3-m{padding:1rem}.swagger-ui .pa4-m{padding:2rem}.swagger-ui .pa5-m{padding:4rem}.swagger-ui .pa6-m{padding:8rem}.swagger-ui .pa7-m{padding:16rem}.swagger-ui .pl0-m{padding-left:0}.swagger-ui .pl1-m{padding-left:.25rem}.swagger-ui .pl2-m{padding-left:.5rem}.swagger-ui .pl3-m{padding-left:1rem}.swagger-ui .pl4-m{padding-left:2rem}.swagger-ui .pl5-m{padding-left:4rem}.swagger-ui .pl6-m{padding-left:8rem}.swagger-ui .pl7-m{padding-left:16rem}.swagger-ui .pr0-m{padding-right:0}.swagger-ui .pr1-m{padding-right:.25rem}.swagger-ui .pr2-m{padding-right:.5rem}.swagger-ui .pr3-m{padding-right:1rem}.swagger-ui .pr4-m{padding-right:2rem}.swagger-ui .pr5-m{padding-right:4rem}.swagger-ui .pr6-m{padding-right:8rem}.swagger-ui .pr7-m{padding-right:16rem}.swagger-ui .pb0-m{padding-bottom:0}.swagger-ui .pb1-m{padding-bottom:.25rem}.swagger-ui .pb2-m{padding-bottom:.5rem}.swagger-ui .pb3-m{padding-bottom:1rem}.swagger-ui .pb4-m{padding-bottom:2rem}.swagger-ui .pb5-m{padding-bottom:4rem}.swagger-ui .pb6-m{padding-bottom:8rem}.swagger-ui .pb7-m{padding-bottom:16rem}.swagger-ui .pt0-m{padding-top:0}.swagger-ui .pt1-m{padding-top:.25rem}.swagger-ui .pt2-m{padding-top:.5rem}.swagger-ui .pt3-m{padding-top:1rem}.swagger-ui .pt4-m{padding-top:2rem}.swagger-ui .pt5-m{padding-top:4rem}.swagger-ui .pt6-m{padding-top:8rem}.swagger-ui .pt7-m{padding-top:16rem}.swagger-ui .pv0-m{padding-bottom:0;padding-top:0}.swagger-ui .pv1-m{padding-bottom:.25rem;padding-top:.25rem}.swagger-ui .pv2-m{padding-bottom:.5rem;padding-top:.5rem}.swagger-ui .pv3-m{padding-bottom:1rem;padding-top:1rem}.swagger-ui .pv4-m{padding-bottom:2rem;padding-top:2rem}.swagger-ui .pv5-m{padding-bottom:4rem;padding-top:4rem}.swagger-ui .pv6-m{padding-bottom:8rem;padding-top:8rem}.swagger-ui .pv7-m{padding-bottom:16rem;padding-top:16rem}.swagger-ui .ph0-m{padding-left:0;padding-right:0}.swagger-ui .ph1-m{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-m{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-m{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-m{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-m{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-m{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-m{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-m{margin:0}.swagger-ui .ma1-m{margin:.25rem}.swagger-ui .ma2-m{margin:.5rem}.swagger-ui .ma3-m{margin:1rem}.swagger-ui .ma4-m{margin:2rem}.swagger-ui .ma5-m{margin:4rem}.swagger-ui .ma6-m{margin:8rem}.swagger-ui .ma7-m{margin:16rem}.swagger-ui .ml0-m{margin-left:0}.swagger-ui .ml1-m{margin-left:.25rem}.swagger-ui .ml2-m{margin-left:.5rem}.swagger-ui .ml3-m{margin-left:1rem}.swagger-ui .ml4-m{margin-left:2rem}.swagger-ui .ml5-m{margin-left:4rem}.swagger-ui .ml6-m{margin-left:8rem}.swagger-ui .ml7-m{margin-left:16rem}.swagger-ui .mr0-m{margin-right:0}.swagger-ui .mr1-m{margin-right:.25rem}.swagger-ui .mr2-m{margin-right:.5rem}.swagger-ui .mr3-m{margin-right:1rem}.swagger-ui .mr4-m{margin-right:2rem}.swagger-ui .mr5-m{margin-right:4rem}.swagger-ui .mr6-m{margin-right:8rem}.swagger-ui .mr7-m{margin-right:16rem}.swagger-ui .mb0-m{margin-bottom:0}.swagger-ui .mb1-m{margin-bottom:.25rem}.swagger-ui .mb2-m{margin-bottom:.5rem}.swagger-ui .mb3-m{margin-bottom:1rem}.swagger-ui .mb4-m{margin-bottom:2rem}.swagger-ui .mb5-m{margin-bottom:4rem}.swagger-ui .mb6-m{margin-bottom:8rem}.swagger-ui .mb7-m{margin-bottom:16rem}.swagger-ui .mt0-m{margin-top:0}.swagger-ui .mt1-m{margin-top:.25rem}.swagger-ui .mt2-m{margin-top:.5rem}.swagger-ui .mt3-m{margin-top:1rem}.swagger-ui .mt4-m{margin-top:2rem}.swagger-ui .mt5-m{margin-top:4rem}.swagger-ui .mt6-m{margin-top:8rem}.swagger-ui .mt7-m{margin-top:16rem}.swagger-ui .mv0-m{margin-bottom:0;margin-top:0}.swagger-ui .mv1-m{margin-bottom:.25rem;margin-top:.25rem}.swagger-ui .mv2-m{margin-bottom:.5rem;margin-top:.5rem}.swagger-ui .mv3-m{margin-bottom:1rem;margin-top:1rem}.swagger-ui .mv4-m{margin-bottom:2rem;margin-top:2rem}.swagger-ui .mv5-m{margin-bottom:4rem;margin-top:4rem}.swagger-ui .mv6-m{margin-bottom:8rem;margin-top:8rem}.swagger-ui .mv7-m{margin-bottom:16rem;margin-top:16rem}.swagger-ui .mh0-m{margin-left:0;margin-right:0}.swagger-ui .mh1-m{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-m{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-m{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-m{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-m{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-m{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-m{margin-left:16rem;margin-right:16rem}.swagger-ui .na1-m{margin:-.25rem}.swagger-ui .na2-m{margin:-.5rem}.swagger-ui .na3-m{margin:-1rem}.swagger-ui .na4-m{margin:-2rem}.swagger-ui .na5-m{margin:-4rem}.swagger-ui .na6-m{margin:-8rem}.swagger-ui .na7-m{margin:-16rem}.swagger-ui .nl1-m{margin-left:-.25rem}.swagger-ui .nl2-m{margin-left:-.5rem}.swagger-ui .nl3-m{margin-left:-1rem}.swagger-ui .nl4-m{margin-left:-2rem}.swagger-ui .nl5-m{margin-left:-4rem}.swagger-ui .nl6-m{margin-left:-8rem}.swagger-ui .nl7-m{margin-left:-16rem}.swagger-ui .nr1-m{margin-right:-.25rem}.swagger-ui .nr2-m{margin-right:-.5rem}.swagger-ui .nr3-m{margin-right:-1rem}.swagger-ui .nr4-m{margin-right:-2rem}.swagger-ui .nr5-m{margin-right:-4rem}.swagger-ui .nr6-m{margin-right:-8rem}.swagger-ui .nr7-m{margin-right:-16rem}.swagger-ui .nb1-m{margin-bottom:-.25rem}.swagger-ui .nb2-m{margin-bottom:-.5rem}.swagger-ui .nb3-m{margin-bottom:-1rem}.swagger-ui .nb4-m{margin-bottom:-2rem}.swagger-ui .nb5-m{margin-bottom:-4rem}.swagger-ui .nb6-m{margin-bottom:-8rem}.swagger-ui .nb7-m{margin-bottom:-16rem}.swagger-ui .nt1-m{margin-top:-.25rem}.swagger-ui .nt2-m{margin-top:-.5rem}.swagger-ui .nt3-m{margin-top:-1rem}.swagger-ui .nt4-m{margin-top:-2rem}.swagger-ui .nt5-m{margin-top:-4rem}.swagger-ui .nt6-m{margin-top:-8rem}.swagger-ui .nt7-m{margin-top:-16rem}.swagger-ui .strike-m{-webkit-text-decoration:line-through;text-decoration:line-through}.swagger-ui .underline-m{-webkit-text-decoration:underline;text-decoration:underline}.swagger-ui .no-underline-m{-webkit-text-decoration:none;text-decoration:none}.swagger-ui .tl-m{text-align:left}.swagger-ui .tr-m{text-align:right}.swagger-ui .tc-m{text-align:center}.swagger-ui .tj-m{text-align:justify}.swagger-ui .ttc-m{text-transform:capitalize}.swagger-ui .ttl-m{text-transform:lowercase}.swagger-ui .ttu-m{text-transform:uppercase}.swagger-ui .ttn-m{text-transform:none}.swagger-ui .f-6-m,.swagger-ui .f-headline-m{font-size:6rem}.swagger-ui .f-5-m,.swagger-ui .f-subheadline-m{font-size:5rem}.swagger-ui .f1-m{font-size:3rem}.swagger-ui .f2-m{font-size:2.25rem}.swagger-ui .f3-m{font-size:1.5rem}.swagger-ui .f4-m{font-size:1.25rem}.swagger-ui .f5-m{font-size:1rem}.swagger-ui .f6-m{font-size:.875rem}.swagger-ui .f7-m{font-size:.75rem}.swagger-ui .measure-m{max-width:30em}.swagger-ui .measure-wide-m{max-width:34em}.swagger-ui .measure-narrow-m{max-width:20em}.swagger-ui .indent-m{margin-bottom:0;margin-top:0;text-indent:1em}.swagger-ui .small-caps-m{font-feature-settings:"smcp","smcp";font-variant:small-caps}.swagger-ui .truncate-m{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.swagger-ui .center-m{margin-left:auto;margin-right:auto}.swagger-ui .mr-auto-m{margin-right:auto}.swagger-ui .ml-auto-m{margin-left:auto}.swagger-ui .clip-m{clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);position:fixed!important}.swagger-ui .ws-normal-m{white-space:normal}.swagger-ui .nowrap-m{white-space:nowrap}.swagger-ui .pre-m{white-space:pre}.swagger-ui .v-base-m{vertical-align:initial}.swagger-ui .v-mid-m{vertical-align:middle}.swagger-ui .v-top-m{vertical-align:top}.swagger-ui .v-btm-m{vertical-align:bottom}}@media screen and (min-width:576px){.navbar .navbar__search-input{background:#0000;padding:0 5rem 0 1rem;width:unset}.navbar__search-input::placeholder{color:var(--ofga-neutral-light)}}@media screen and (min-width:600px){.buttons_qNcx{flex-direction:row}.container_Q0_S{margin:0 -1.75rem}}@media (min-width:768px){.swagger-ui .opblock .opblock-summary-method{min-width:100px;padding:8px 0}.swagger-ui .opblock .opblock-summary-path{flex-shrink:0}}@media screen and (min-width:60em){.swagger-ui .aspect-ratio-l{height:0;position:relative}.swagger-ui .aspect-ratio--16x9-l{padding-bottom:56.25%}.swagger-ui .aspect-ratio--9x16-l{padding-bottom:177.77%}.swagger-ui .aspect-ratio--4x3-l{padding-bottom:75%}.swagger-ui .aspect-ratio--3x4-l{padding-bottom:133.33%}.swagger-ui .aspect-ratio--6x4-l{padding-bottom:66.6%}.swagger-ui .aspect-ratio--4x6-l{padding-bottom:150%}.swagger-ui .aspect-ratio--8x5-l{padding-bottom:62.5%}.swagger-ui .aspect-ratio--5x8-l{padding-bottom:160%}.swagger-ui .aspect-ratio--7x5-l{padding-bottom:71.42%}.swagger-ui .aspect-ratio--5x7-l{padding-bottom:140%}.swagger-ui .aspect-ratio--1x1-l{padding-bottom:100%}.swagger-ui .aspect-ratio--object-l{bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%;z-index:100}.swagger-ui .cover-l{background-size:cover!important}.swagger-ui .contain-l{background-size:contain!important}.swagger-ui .bg-center-l{background-position:50%;background-repeat:no-repeat}.swagger-ui .bg-top-l{background-position:top;background-repeat:no-repeat}.swagger-ui .bg-right-l{background-position:100%;background-repeat:no-repeat}.swagger-ui .bg-bottom-l{background-position:bottom;background-repeat:no-repeat}.swagger-ui .bg-left-l{background-position:0;background-repeat:no-repeat}.swagger-ui .outline-l{outline:solid 1px}.swagger-ui .outline-transparent-l{outline:#0000 solid 1px}.swagger-ui .outline-0-l{outline:0}.swagger-ui .ba-l{border-style:solid;border-width:1px}.swagger-ui .bt-l{border-top-style:solid;border-top-width:1px}.swagger-ui .br-l{border-right-style:solid;border-right-width:1px}.swagger-ui .bb-l{border-bottom-style:solid;border-bottom-width:1px}.swagger-ui .bl-l{border-left-style:solid;border-left-width:1px}.swagger-ui .bn-l{border-style:none;border-width:0}.swagger-ui .br0-l{border-radius:0}.swagger-ui .br1-l{border-radius:.125rem}.swagger-ui .br2-l{border-radius:.25rem}.swagger-ui .br3-l{border-radius:.5rem}.swagger-ui .br4-l{border-radius:1rem}.swagger-ui .br-100-l{border-radius:100%}.swagger-ui .br-pill-l{border-radius:9999px}.swagger-ui .br--bottom-l{border-top-left-radius:0;border-top-right-radius:0}.swagger-ui .br--top-l{border-bottom-left-radius:0;border-bottom-right-radius:0}.swagger-ui .br--right-l{border-bottom-left-radius:0;border-top-left-radius:0}.swagger-ui .br--left-l{border-bottom-right-radius:0;border-top-right-radius:0}.swagger-ui .b--dotted-l{border-style:dotted}.swagger-ui .b--dashed-l{border-style:dashed}.swagger-ui .b--solid-l{border-style:solid}.swagger-ui .b--none-l{border-style:none}.swagger-ui .bw0-l{border-width:0}.swagger-ui .bw1-l{border-width:.125rem}.swagger-ui .bw2-l{border-width:.25rem}.swagger-ui .bw3-l{border-width:.5rem}.swagger-ui .bw4-l{border-width:1rem}.swagger-ui .bw5-l{border-width:2rem}.swagger-ui .bt-0-l{border-top-width:0}.swagger-ui .br-0-l{border-right-width:0}.swagger-ui .bb-0-l{border-bottom-width:0}.swagger-ui .bl-0-l{border-left-width:0}.swagger-ui .shadow-1-l{box-shadow:0 0 4px 2px #0003}.swagger-ui .shadow-2-l{box-shadow:0 0 8px 2px #0003}.swagger-ui .shadow-3-l{box-shadow:2px 2px 4px 2px #0003}.swagger-ui .shadow-4-l{box-shadow:2px 2px 8px 0 #0003}.swagger-ui .shadow-5-l{box-shadow:4px 4px 8px 0 #0003}.swagger-ui .top-0-l{top:0}.swagger-ui .left-0-l{left:0}.swagger-ui .right-0-l{right:0}.swagger-ui .bottom-0-l{bottom:0}.swagger-ui .top-1-l{top:1rem}.swagger-ui .left-1-l{left:1rem}.swagger-ui .right-1-l{right:1rem}.swagger-ui .bottom-1-l{bottom:1rem}.swagger-ui .top-2-l{top:2rem}.swagger-ui .left-2-l{left:2rem}.swagger-ui .right-2-l{right:2rem}.swagger-ui .bottom-2-l{bottom:2rem}.swagger-ui .top--1-l{top:-1rem}.swagger-ui .right--1-l{right:-1rem}.swagger-ui .bottom--1-l{bottom:-1rem}.swagger-ui .left--1-l{left:-1rem}.swagger-ui .top--2-l{top:-2rem}.swagger-ui .right--2-l{right:-2rem}.swagger-ui .bottom--2-l{bottom:-2rem}.swagger-ui .left--2-l{left:-2rem}.swagger-ui .absolute--fill-l{bottom:0;left:0;right:0;top:0}.swagger-ui .cl-l{clear:left}.swagger-ui .cr-l{clear:right}.swagger-ui .cb-l{clear:both}.swagger-ui .cn-l{clear:none}.swagger-ui .flex-l{display:flex}.swagger-ui .inline-flex-l{display:inline-flex}.swagger-ui .flex-auto-l{flex:1 1 auto;min-height:0;min-width:0}.swagger-ui .flex-none-l{flex:none}.swagger-ui .flex-column-l{flex-direction:column}.swagger-ui .flex-row-l{flex-direction:row}.swagger-ui .flex-wrap-l{flex-wrap:wrap}.swagger-ui .flex-nowrap-l{flex-wrap:nowrap}.swagger-ui .flex-wrap-reverse-l{flex-wrap:wrap-reverse}.swagger-ui .flex-column-reverse-l{flex-direction:column-reverse}.swagger-ui .flex-row-reverse-l{flex-direction:row-reverse}.swagger-ui .items-start-l{align-items:flex-start}.swagger-ui .items-end-l{align-items:flex-end}.swagger-ui .items-center-l{align-items:center}.swagger-ui .items-baseline-l{align-items:baseline}.swagger-ui .items-stretch-l{align-items:stretch}.swagger-ui .self-start-l{align-self:flex-start}.swagger-ui .self-end-l{align-self:flex-end}.swagger-ui .self-center-l{align-self:center}.swagger-ui .self-baseline-l{align-self:baseline}.swagger-ui .self-stretch-l{align-self:stretch}.swagger-ui .justify-start-l{justify-content:flex-start}.swagger-ui .justify-end-l{justify-content:flex-end}.swagger-ui .justify-center-l{justify-content:center}.swagger-ui .justify-between-l{justify-content:space-between}.swagger-ui .justify-around-l{justify-content:space-around}.swagger-ui .content-start-l{align-content:flex-start}.swagger-ui .content-end-l{align-content:flex-end}.swagger-ui .content-center-l{align-content:center}.swagger-ui .content-between-l{align-content:space-between}.swagger-ui .content-around-l{align-content:space-around}.swagger-ui .content-stretch-l{align-content:stretch}.swagger-ui .order-0-l{order:0}.swagger-ui .order-1-l{order:1}.swagger-ui .order-2-l{order:2}.swagger-ui .order-3-l{order:3}.swagger-ui .order-4-l{order:4}.swagger-ui .order-5-l{order:5}.swagger-ui .order-6-l{order:6}.swagger-ui .order-7-l{order:7}.swagger-ui .order-8-l{order:8}.swagger-ui .order-last-l{order:99999}.swagger-ui .flex-grow-0-l{flex-grow:0}.swagger-ui .flex-grow-1-l{flex-grow:1}.swagger-ui .flex-shrink-0-l{flex-shrink:0}.swagger-ui .flex-shrink-1-l{flex-shrink:1}.swagger-ui .dn-l{display:none}.swagger-ui .di-l{display:inline}.swagger-ui .db-l{display:block}.swagger-ui .dib-l{display:inline-block}.swagger-ui .dit-l{display:inline-table}.swagger-ui .dt-l{display:table}.swagger-ui .dtc-l{display:table-cell}.swagger-ui .dt-row-l{display:table-row}.swagger-ui .dt-row-group-l{display:table-row-group}.swagger-ui .dt-column-l{display:table-column}.swagger-ui .dt-column-group-l{display:table-column-group}.swagger-ui .dt--fixed-l{table-layout:fixed;width:100%}.swagger-ui .fl-l{float:left}.swagger-ui .fr-l{float:right}.swagger-ui .fn-l{float:none}.swagger-ui .i-l{font-style:italic}.swagger-ui .fs-normal-l{font-style:normal}.swagger-ui .fw4-l,.swagger-ui .normal-l{font-weight:400}.swagger-ui .b-l,.swagger-ui .fw7-l{font-weight:700}.swagger-ui .fw1-l{font-weight:100}.swagger-ui .fw2-l{font-weight:200}.swagger-ui .fw3-l{font-weight:300}.swagger-ui .fw5-l{font-weight:500}.swagger-ui .fw6-l{font-weight:600}.swagger-ui .fw8-l{font-weight:800}.swagger-ui .fw9-l{font-weight:900}.swagger-ui .h1-l{height:1rem}.swagger-ui .h2-l{height:2rem}.swagger-ui .h3-l{height:4rem}.swagger-ui .h4-l{height:8rem}.swagger-ui .h5-l{height:16rem}.swagger-ui .h-25-l{height:25%}.swagger-ui .h-50-l{height:50%}.swagger-ui .h-75-l{height:75%}.swagger-ui .h-100-l{height:100%}.swagger-ui .min-h-100-l{min-height:100%}.swagger-ui .vh-25-l{height:25vh}.swagger-ui .vh-50-l{height:50vh}.swagger-ui .vh-75-l{height:75vh}.swagger-ui .vh-100-l{height:100vh}.swagger-ui .min-vh-100-l{min-height:100vh}.swagger-ui .h-auto-l{height:auto}.swagger-ui .h-inherit-l{height:inherit}.swagger-ui .tracked-l{letter-spacing:.1em}.swagger-ui .tracked-tight-l{letter-spacing:-.05em}.swagger-ui .tracked-mega-l{letter-spacing:.25em}.swagger-ui .lh-solid-l{line-height:1}.swagger-ui .lh-title-l{line-height:1.25}.swagger-ui .lh-copy-l{line-height:1.5}.swagger-ui .mw-100-l{max-width:100%}.swagger-ui .mw1-l{max-width:1rem}.swagger-ui .mw2-l{max-width:2rem}.swagger-ui .mw3-l{max-width:4rem}.swagger-ui .mw4-l{max-width:8rem}.swagger-ui .mw5-l{max-width:16rem}.swagger-ui .mw6-l{max-width:32rem}.swagger-ui .mw7-l{max-width:48rem}.swagger-ui .mw8-l{max-width:64rem}.swagger-ui .mw9-l{max-width:96rem}.swagger-ui .mw-none-l{max-width:none}.swagger-ui .w1-l{width:1rem}.swagger-ui .w2-l{width:2rem}.swagger-ui .w3-l{width:4rem}.swagger-ui .w4-l{width:8rem}.swagger-ui .w5-l{width:16rem}.swagger-ui .w-10-l{width:10%}.swagger-ui .w-20-l{width:20%}.swagger-ui .w-25-l{width:25%}.swagger-ui .w-30-l{width:30%}.swagger-ui .w-33-l{width:33%}.swagger-ui .w-34-l{width:34%}.swagger-ui .w-40-l{width:40%}.swagger-ui .w-50-l{width:50%}.swagger-ui .w-60-l{width:60%}.swagger-ui .w-70-l{width:70%}.swagger-ui .w-75-l{width:75%}.swagger-ui .w-80-l{width:80%}.swagger-ui .w-90-l{width:90%}.swagger-ui .w-100-l{width:100%}.swagger-ui .w-third-l{width:33.3333333333%}.swagger-ui .w-two-thirds-l{width:66.6666666667%}.swagger-ui .w-auto-l{width:auto}.swagger-ui .overflow-visible-l{overflow:visible}.swagger-ui .overflow-hidden-l{overflow:hidden}.swagger-ui .overflow-scroll-l{overflow:scroll}.swagger-ui .overflow-auto-l{overflow:auto}.swagger-ui .overflow-x-visible-l{overflow-x:visible}.swagger-ui .overflow-x-hidden-l{overflow-x:hidden}.swagger-ui .overflow-x-scroll-l{overflow-x:scroll}.swagger-ui .overflow-x-auto-l{overflow-x:auto}.swagger-ui .overflow-y-visible-l{overflow-y:visible}.swagger-ui .overflow-y-hidden-l{overflow-y:hidden}.swagger-ui .overflow-y-scroll-l{overflow-y:scroll}.swagger-ui .overflow-y-auto-l{overflow-y:auto}.swagger-ui .static-l{position:static}.swagger-ui .relative-l{position:relative}.swagger-ui .absolute-l{position:absolute}.swagger-ui .fixed-l{position:fixed}.swagger-ui .rotate-45-l{transform:rotate(45deg)}.swagger-ui .rotate-90-l{transform:rotate(90deg)}.swagger-ui .rotate-135-l{transform:rotate(135deg)}.swagger-ui .rotate-180-l{transform:rotate(180deg)}.swagger-ui .rotate-225-l{transform:rotate(225deg)}.swagger-ui .rotate-270-l{transform:rotate(270deg)}.swagger-ui .rotate-315-l{transform:rotate(315deg)}.swagger-ui .pa0-l{padding:0}.swagger-ui .pa1-l{padding:.25rem}.swagger-ui .pa2-l{padding:.5rem}.swagger-ui .pa3-l{padding:1rem}.swagger-ui .pa4-l{padding:2rem}.swagger-ui .pa5-l{padding:4rem}.swagger-ui .pa6-l{padding:8rem}.swagger-ui .pa7-l{padding:16rem}.swagger-ui .pl0-l{padding-left:0}.swagger-ui .pl1-l{padding-left:.25rem}.swagger-ui .pl2-l{padding-left:.5rem}.swagger-ui .pl3-l{padding-left:1rem}.swagger-ui .pl4-l{padding-left:2rem}.swagger-ui .pl5-l{padding-left:4rem}.swagger-ui .pl6-l{padding-left:8rem}.swagger-ui .pl7-l{padding-left:16rem}.swagger-ui .pr0-l{padding-right:0}.swagger-ui .pr1-l{padding-right:.25rem}.swagger-ui .pr2-l{padding-right:.5rem}.swagger-ui .pr3-l{padding-right:1rem}.swagger-ui .pr4-l{padding-right:2rem}.swagger-ui .pr5-l{padding-right:4rem}.swagger-ui .pr6-l{padding-right:8rem}.swagger-ui .pr7-l{padding-right:16rem}.swagger-ui .pb0-l{padding-bottom:0}.swagger-ui .pb1-l{padding-bottom:.25rem}.swagger-ui .pb2-l{padding-bottom:.5rem}.swagger-ui .pb3-l{padding-bottom:1rem}.swagger-ui .pb4-l{padding-bottom:2rem}.swagger-ui .pb5-l{padding-bottom:4rem}.swagger-ui .pb6-l{padding-bottom:8rem}.swagger-ui .pb7-l{padding-bottom:16rem}.swagger-ui .pt0-l{padding-top:0}.swagger-ui .pt1-l{padding-top:.25rem}.swagger-ui .pt2-l{padding-top:.5rem}.swagger-ui .pt3-l{padding-top:1rem}.swagger-ui .pt4-l{padding-top:2rem}.swagger-ui .pt5-l{padding-top:4rem}.swagger-ui .pt6-l{padding-top:8rem}.swagger-ui .pt7-l{padding-top:16rem}.swagger-ui .pv0-l{padding-bottom:0;padding-top:0}.swagger-ui .pv1-l{padding-bottom:.25rem;padding-top:.25rem}.swagger-ui .pv2-l{padding-bottom:.5rem;padding-top:.5rem}.swagger-ui .pv3-l{padding-bottom:1rem;padding-top:1rem}.swagger-ui .pv4-l{padding-bottom:2rem;padding-top:2rem}.swagger-ui .pv5-l{padding-bottom:4rem;padding-top:4rem}.swagger-ui .pv6-l{padding-bottom:8rem;padding-top:8rem}.swagger-ui .pv7-l{padding-bottom:16rem;padding-top:16rem}.swagger-ui .ph0-l{padding-left:0;padding-right:0}.swagger-ui .ph1-l{padding-left:.25rem;padding-right:.25rem}.swagger-ui .ph2-l{padding-left:.5rem;padding-right:.5rem}.swagger-ui .ph3-l{padding-left:1rem;padding-right:1rem}.swagger-ui .ph4-l{padding-left:2rem;padding-right:2rem}.swagger-ui .ph5-l{padding-left:4rem;padding-right:4rem}.swagger-ui .ph6-l{padding-left:8rem;padding-right:8rem}.swagger-ui .ph7-l{padding-left:16rem;padding-right:16rem}.swagger-ui .ma0-l{margin:0}.swagger-ui .ma1-l{margin:.25rem}.swagger-ui .ma2-l{margin:.5rem}.swagger-ui .ma3-l{margin:1rem}.swagger-ui .ma4-l{margin:2rem}.swagger-ui .ma5-l{margin:4rem}.swagger-ui .ma6-l{margin:8rem}.swagger-ui .ma7-l{margin:16rem}.swagger-ui .ml0-l{margin-left:0}.swagger-ui .ml1-l{margin-left:.25rem}.swagger-ui .ml2-l{margin-left:.5rem}.swagger-ui .ml3-l{margin-left:1rem}.swagger-ui .ml4-l{margin-left:2rem}.swagger-ui .ml5-l{margin-left:4rem}.swagger-ui .ml6-l{margin-left:8rem}.swagger-ui .ml7-l{margin-left:16rem}.swagger-ui .mr0-l{margin-right:0}.swagger-ui .mr1-l{margin-right:.25rem}.swagger-ui .mr2-l{margin-right:.5rem}.swagger-ui .mr3-l{margin-right:1rem}.swagger-ui .mr4-l{margin-right:2rem}.swagger-ui .mr5-l{margin-right:4rem}.swagger-ui .mr6-l{margin-right:8rem}.swagger-ui .mr7-l{margin-right:16rem}.swagger-ui .mb0-l{margin-bottom:0}.swagger-ui .mb1-l{margin-bottom:.25rem}.swagger-ui .mb2-l{margin-bottom:.5rem}.swagger-ui .mb3-l{margin-bottom:1rem}.swagger-ui .mb4-l{margin-bottom:2rem}.swagger-ui .mb5-l{margin-bottom:4rem}.swagger-ui .mb6-l{margin-bottom:8rem}.swagger-ui .mb7-l{margin-bottom:16rem}.swagger-ui .mt0-l{margin-top:0}.swagger-ui .mt1-l{margin-top:.25rem}.swagger-ui .mt2-l{margin-top:.5rem}.swagger-ui .mt3-l{margin-top:1rem}.swagger-ui .mt4-l{margin-top:2rem}.swagger-ui .mt5-l{margin-top:4rem}.swagger-ui .mt6-l{margin-top:8rem}.swagger-ui .mt7-l{margin-top:16rem}.swagger-ui .mv0-l{margin-bottom:0;margin-top:0}.swagger-ui .mv1-l{margin-bottom:.25rem;margin-top:.25rem}.swagger-ui .mv2-l{margin-bottom:.5rem;margin-top:.5rem}.swagger-ui .mv3-l{margin-bottom:1rem;margin-top:1rem}.swagger-ui .mv4-l{margin-bottom:2rem;margin-top:2rem}.swagger-ui .mv5-l{margin-bottom:4rem;margin-top:4rem}.swagger-ui .mv6-l{margin-bottom:8rem;margin-top:8rem}.swagger-ui .mv7-l{margin-bottom:16rem;margin-top:16rem}.swagger-ui .mh0-l{margin-left:0;margin-right:0}.swagger-ui .mh1-l{margin-left:.25rem;margin-right:.25rem}.swagger-ui .mh2-l{margin-left:.5rem;margin-right:.5rem}.swagger-ui .mh3-l{margin-left:1rem;margin-right:1rem}.swagger-ui .mh4-l{margin-left:2rem;margin-right:2rem}.swagger-ui .mh5-l{margin-left:4rem;margin-right:4rem}.swagger-ui .mh6-l{margin-left:8rem;margin-right:8rem}.swagger-ui .mh7-l{margin-left:16rem;margin-right:16rem}.swagger-ui .na1-l{margin:-.25rem}.swagger-ui .na2-l{margin:-.5rem}.swagger-ui .na3-l{margin:-1rem}.swagger-ui .na4-l{margin:-2rem}.swagger-ui .na5-l{margin:-4rem}.swagger-ui .na6-l{margin:-8rem}.swagger-ui .na7-l{margin:-16rem}.swagger-ui .nl1-l{margin-left:-.25rem}.swagger-ui .nl2-l{margin-left:-.5rem}.swagger-ui .nl3-l{margin-left:-1rem}.swagger-ui .nl4-l{margin-left:-2rem}.swagger-ui .nl5-l{margin-left:-4rem}.swagger-ui .nl6-l{margin-left:-8rem}.swagger-ui .nl7-l{margin-left:-16rem}.swagger-ui .nr1-l{margin-right:-.25rem}.swagger-ui .nr2-l{margin-right:-.5rem}.swagger-ui .nr3-l{margin-right:-1rem}.swagger-ui .nr4-l{margin-right:-2rem}.swagger-ui .nr5-l{margin-right:-4rem}.swagger-ui .nr6-l{margin-right:-8rem}.swagger-ui .nr7-l{margin-right:-16rem}.swagger-ui .nb1-l{margin-bottom:-.25rem}.swagger-ui .nb2-l{margin-bottom:-.5rem}.swagger-ui .nb3-l{margin-bottom:-1rem}.swagger-ui .nb4-l{margin-bottom:-2rem}.swagger-ui .nb5-l{margin-bottom:-4rem}.swagger-ui .nb6-l{margin-bottom:-8rem}.swagger-ui .nb7-l{margin-bottom:-16rem}.swagger-ui .nt1-l{margin-top:-.25rem}.swagger-ui .nt2-l{margin-top:-.5rem}.swagger-ui .nt3-l{margin-top:-1rem}.swagger-ui .nt4-l{margin-top:-2rem}.swagger-ui .nt5-l{margin-top:-4rem}.swagger-ui .nt6-l{margin-top:-8rem}.swagger-ui .nt7-l{margin-top:-16rem}.swagger-ui .strike-l{-webkit-text-decoration:line-through;text-decoration:line-through}.swagger-ui .underline-l{-webkit-text-decoration:underline;text-decoration:underline}.swagger-ui .no-underline-l{-webkit-text-decoration:none;text-decoration:none}.swagger-ui .tl-l{text-align:left}.swagger-ui .tr-l{text-align:right}.swagger-ui .tc-l{text-align:center}.swagger-ui .tj-l{text-align:justify}.swagger-ui .ttc-l{text-transform:capitalize}.swagger-ui .ttl-l{text-transform:lowercase}.swagger-ui .ttu-l{text-transform:uppercase}.swagger-ui .ttn-l{text-transform:none}.swagger-ui .f-6-l,.swagger-ui .f-headline-l{font-size:6rem}.swagger-ui .f-5-l,.swagger-ui .f-subheadline-l{font-size:5rem}.swagger-ui .f1-l{font-size:3rem}.swagger-ui .f2-l{font-size:2.25rem}.swagger-ui .f3-l{font-size:1.5rem}.swagger-ui .f4-l{font-size:1.25rem}.swagger-ui .f5-l{font-size:1rem}.swagger-ui .f6-l{font-size:.875rem}.swagger-ui .f7-l{font-size:.75rem}.swagger-ui .measure-l{max-width:30em}.swagger-ui .measure-wide-l{max-width:34em}.swagger-ui .measure-narrow-l{max-width:20em}.swagger-ui .indent-l{margin-bottom:0;margin-top:0;text-indent:1em}.swagger-ui .small-caps-l{font-feature-settings:"smcp","smcp";font-variant:small-caps}.swagger-ui .truncate-l{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.swagger-ui .center-l{margin-left:auto;margin-right:auto}.swagger-ui .mr-auto-l{margin-right:auto}.swagger-ui .ml-auto-l{margin-left:auto}.swagger-ui .clip-l{clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px);position:fixed!important}.swagger-ui .ws-normal-l{white-space:normal}.swagger-ui .nowrap-l{white-space:nowrap}.swagger-ui .pre-l{white-space:pre}.swagger-ui .v-base-l{vertical-align:initial}.swagger-ui .v-mid-l{vertical-align:middle}.swagger-ui .v-top-l{vertical-align:top}.swagger-ui .v-btm-l{vertical-align:bottom}}@media (min-width:996px){.grid_OmBo{display:grid}}@media screen and (min-width:996px){.hideOnMobile_oZZF{display:block}.container_Xn_q{align-items:center;justify-content:space-between;padding:8rem 2rem}.content_mBeF{max-width:calc(50% + 50px);padding-right:32px;width:auto}.heading_OPPZ svg{height:auto;height:unset;width:25.8rem}.headingSubtitle_qc__{font-size:2.7rem}.buttons_qNcx,.container_bmt1{flex-direction:row}.heroPattern_dn9n{display:flex;height:100%;max-width:calc(50% - 50px);padding-left:32px;width:100%}.section_VjpN{padding:9.25rem 0 10.25rem}.content_APwV{width:calc(50% - 5rem)}.content_APwV p{margin-bottom:2rem}.terminalContainer_peeJ{display:flex;justify-content:center;margin-top:0;width:calc(50% + 1.125rem)}.container_Q0_S{padding:0 2.75rem}}@media (min-width:997px){.collapseSidebarButton_PEFL,.expandButton_TmdG{background-color:var(--docusaurus-collapse-button-bg)}:root{--docusaurus-announcement-bar-height:30px}.announcementBarClose_gvF7,.announcementBarPlaceholder_vyr4{flex-basis:50px}.collapseSidebarButton_PEFL{border:1px solid var(--ifm-toc-border-color);border-radius:0;bottom:0;display:block!important;height:40px;position:sticky}.collapseSidebarButtonIcon_kv0_{margin-top:4px;transform:rotate(180deg)}.expandButtonIcon_i1dp,[dir=rtl] .collapseSidebarButtonIcon_kv0_{transform:rotate(0)}.collapseSidebarButton_PEFL:focus,.collapseSidebarButton_PEFL:hover,.expandButton_TmdG:focus,.expandButton_TmdG:hover{background-color:var(--docusaurus-collapse-button-bg-hover)}.menuHtmlItem_M9Kj{padding:var(--ifm-menu-link-padding-vertical) var(--ifm-menu-link-padding-horizontal)}.menu_SIkG{flex-grow:1;padding:.5rem}@supports (scrollbar-gutter:stable){.menu_SIkG{padding:.5rem 0 .5rem .5rem;scrollbar-gutter:stable}}.menuWithAnnouncementBar_GW3s{margin-bottom:var(--docusaurus-announcement-bar-height)}.sidebar_njMd{display:flex;flex-direction:column;height:100%;padding-top:var(--ifm-navbar-height);width:var(--doc-sidebar-width)}.sidebarWithHideableNavbar_wUlq{padding-top:0}.sidebarHidden_VK0M{opacity:0;visibility:hidden}.sidebarLogo_isFc{align-items:center;color:inherit!important;display:flex!important;margin:0 var(--ifm-navbar-padding-horizontal);max-height:var(--ifm-navbar-height);min-height:var(--ifm-navbar-height);-webkit-text-decoration:none!important;text-decoration:none!important}.sidebarLogo_isFc img{height:2rem;margin-right:.5rem}.expandButton_TmdG{align-items:center;display:flex;height:100%;justify-content:center;position:absolute;right:0;top:0;transition:background-color var(--ifm-transition-fast) ease;width:100%}[dir=rtl] .expandButtonIcon_i1dp{transform:rotate(180deg)}.docSidebarContainer_YfHR{border-right:1px solid var(--ifm-toc-border-color);clip-path:inset(0);display:block;margin-top:calc(var(--ifm-navbar-height)*-1);transition:width var(--ifm-transition-fast) ease;width:var(--doc-sidebar-width);will-change:width}.docSidebarContainerHidden_DPk8{cursor:pointer;width:var(--doc-sidebar-hidden-width)}.sidebarViewport_aRkj{height:100%;max-height:100vh;position:sticky;top:0}.docMainContainer_TBSr{flex-grow:1;max-width:calc(100% - var(--doc-sidebar-width))}.docMainContainerEnhanced_lQrH{max-width:calc(100% - var(--doc-sidebar-hidden-width))}.docItemWrapperEnhanced_JWYK{max-width:calc(var(--ifm-container-width) + var(--doc-sidebar-width))!important}.navbarSearchContainer_Bca1{padding:var(--ifm-navbar-item-padding-vertical) var(--ifm-navbar-item-padding-horizontal)}.lastUpdated_JAkA{text-align:right}.tocMobile_ITEo{display:none}.docItemCol_VOVn{max-width:75%!important}}@media (min-width:1200px){.section_sUhq{padding:10rem 0}.grid_f5pM{display:grid;grid-template-columns:1fr 1fr;grid-gap:5rem 6.25rem}.container_Q0_S{height:auto}.links_JbSJ{margin-bottom:0}.links_JbSJ li{margin-bottom:1rem}.links_JbSJ li:last-of-type{margin-bottom:unset}.mainArea_jMsm{padding:3.75rem}.mainArea_jMsm h2{margin:0 4rem 3rem 0}}@media screen and (min-width:1200px){.container_Q0_S,.footer .container{padding:0}.display-on-desktop{display:inline}}@media (min-width:1440px){.container,.grid_OmBo{max-width:var(--ifm-container-width-xl)}}@media only screen and (min-width:1440px){.container__no-padding,.navbar__inner{max-width:var(--ifm-container-width-xl)}}@media (max-width:1536px){.column-layout-4_SipK,.column-layout-5_K6O8{display:grid;grid-template-columns:repeat(2,1fr)}.column-layout-4-equal-width_WOGz,.column-layout-5-equal-width_CiKk{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.column-layout-2_O2db,.column-layout-3_YXBy{display:grid;grid-template-columns:repeat(1,1fr)}.documentation-feedback_yGAr{grid-template-columns:repeat(1,1fr)}.documentation-feedback-img_QGMs,.documentation-feedback-pattern_jV72{visibility:hidden}}@media screen and (max-width:1460px){.swagger-ui .wrapper{padding:0 16px}}@media (max-width:996px){.col{--ifm-col-width:100%;flex-basis:var(--ifm-col-width);margin-left:0}.footer{--ifm-footer-padding-horizontal:0}.colorModeToggle_DEke,.footer__link-separator,.navbar__item,.sidebar_re4s,.tableOfContents_bqdL{display:none}.footer__col{margin-bottom:calc(var(--ifm-spacing-vertical)*3)}.footer__link-item{display:block;width:max-content}.hero{padding-left:0;padding-right:0}.navbar>.container,.navbar>.container-fluid{padding:0}.navbar__toggle{display:inherit}.navbar__search-input{width:9rem}.pills--block,.tabs--block{flex-direction:column}.navbarSearchContainer_Bca1{position:absolute;right:var(--ifm-navbar-padding-horizontal)}.documentation-feedback_yGAr{margin:48px 24px}.docItemContainer_F8PC{padding:0 .3rem}}@media not (max-width:996px){.searchBar_RVTs.searchBarLeft_MXDe .dropdownMenu_qbY6{left:0!important;right:auto!important}}@media only screen and (max-width:996px){.header-social{display:none}.searchQueryColumn_q7nx{max-width:60%!important}.searchContextColumn_oWAF{max-width:40%!important}.social-media-banner_EIek{display:flex;gap:2rem;justify-content:space-evenly;padding:.625rem 2rem}}@media (max-width:768px){.swagger-ui .opblock .opblock-summary-operation-id,.swagger-ui .opblock .opblock-summary-path,.swagger-ui .opblock .opblock-summary-path__deprecated{font-size:12px}.swagger-ui .opblock .opblock-summary-description{display:none}.swagger-ui .opblock-body select{min-width:180px}.swagger-ui input[type=email],.swagger-ui input[type=file],.swagger-ui input[type=password],.swagger-ui input[type=search],.swagger-ui input[type=text]{max-width:175px}}@media (max-width:576px){.markdown h1:first-child{--ifm-h1-font-size:2rem}.markdown>h2{--ifm-h2-font-size:1.5rem}.markdown>h3{--ifm-h3-font-size:1.25rem}.navbar__search-input:not(:focus){width:2rem}.searchBar_RVTs .dropdownMenu_qbY6{max-width:calc(100vw - var(--ifm-navbar-padding-horizontal)*2);width:var(--search-local-modal-width-sm,340px)}.searchBarContainer_NW3z:not(.focused_OWtg) .searchClearButton_qk4g,.searchHintContainer_Pkmr{display:none}.title_f1Hy{font-size:2rem}}@media screen and (max-width:576px){.navbar__search-input{background-color:var(--ofga-neutral-light);color:var(--ofga-neutral-darkest)}.navbar__search-input:focus{width:8rem}.navbar__search-input:not(:focus){background-position:50%;color:#0000;cursor:pointer;height:2rem;padding:0;width:2rem}.navbar__search button{color:var(--ofga-neutral-darkest);cursor:pointer}.navbar__search-input:not(:focus)::placeholder{color:#0000}.navbar__search-input::placeholder{color:var(--ofga-neutral-darkest)}.searchQueryColumn_q7nx{max-width:100%!important}.searchContextColumn_oWAF{max-width:100%!important;padding-left:var(--ifm-spacing-horizontal)!important}}@media only screen and (max-width:375px){.social-media-banner_EIek{font-size:.8rem;gap:1rem}}@media (hover:hover){.backToTopButton_sjWU:hover{background-color:var(--ifm-color-emphasis-300)}}@media (pointer:fine){.thin-scrollbar{scrollbar-width:thin}.thin-scrollbar::-webkit-scrollbar{height:var(--ifm-scrollbar-size);width:var(--ifm-scrollbar-size)}.thin-scrollbar::-webkit-scrollbar-track{background:var(--ifm-scrollbar-track-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb{background:var(--ifm-scrollbar-thumb-background-color);border-radius:10px}.thin-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--ifm-scrollbar-thumb-hover-background-color)}}@media (prefers-reduced-motion:reduce){:root{--ifm-transition-fast:0ms;--ifm-transition-slow:0ms}}@media print{.announcementBar_mb4j,.footer,.menu,.navbar,.pagination-nav,.table-of-contents,.tocMobile_ITEo{display:none}.tabs{page-break-inside:avoid}.codeBlockLines_e6Vv{white-space:pre-wrap}} \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/banner-playground-icon-aad8d03c3300233154438dc9eb98541c.svg b/pr-preview/pr-921/assets/images/banner-playground-icon-aad8d03c3300233154438dc9eb98541c.svg new file mode 100644 index 000000000..8e9fa32b3 --- /dev/null +++ b/pr-preview/pr-921/assets/images/banner-playground-icon-aad8d03c3300233154438dc9eb98541c.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/assets/images/custom-roles-expectations-f015ffb4203247a03815859fb0844f95.svg b/pr-preview/pr-921/assets/images/custom-roles-expectations-f015ffb4203247a03815859fb0844f95.svg new file mode 100644 index 000000000..00f8433c3 --- /dev/null +++ b/pr-preview/pr-921/assets/images/custom-roles-expectations-f015ffb4203247a03815859fb0844f95.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/custom-roles-membership-checks-057e971c8b2def87ea3c405352a0f100.svg b/pr-preview/pr-921/assets/images/custom-roles-membership-checks-057e971c8b2def87ea3c405352a0f100.svg new file mode 100644 index 000000000..7292cde90 --- /dev/null +++ b/pr-preview/pr-921/assets/images/custom-roles-membership-checks-057e971c8b2def87ea3c405352a0f100.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/custom-roles-roles-and-permissions-ca8254c87a37e52fea450bdeb634b39c.svg b/pr-preview/pr-921/assets/images/custom-roles-roles-and-permissions-ca8254c87a37e52fea450bdeb634b39c.svg new file mode 100644 index 000000000..96acc05d5 --- /dev/null +++ b/pr-preview/pr-921/assets/images/custom-roles-roles-and-permissions-ca8254c87a37e52fea450bdeb634b39c.svg @@ -0,0 +1,648 @@ + + + + diff --git a/pr-preview/pr-921/assets/images/entitlements-image-github-draft-pr-2ee031c09e3924b41681861e56aab2e7.svg b/pr-preview/pr-921/assets/images/entitlements-image-github-draft-pr-2ee031c09e3924b41681861e56aab2e7.svg new file mode 100644 index 000000000..5a10d79b1 --- /dev/null +++ b/pr-preview/pr-921/assets/images/entitlements-image-github-draft-pr-2ee031c09e3924b41681861e56aab2e7.svg @@ -0,0 +1,1327 @@ + + + + diff --git a/pr-preview/pr-921/assets/images/entitlements-image-github-no-draft-pr-785626465cfe1b8183918ee6bd3aefb1.svg b/pr-preview/pr-921/assets/images/entitlements-image-github-no-draft-pr-785626465cfe1b8183918ee6bd3aefb1.svg new file mode 100644 index 000000000..ee23f767f --- /dev/null +++ b/pr-preview/pr-921/assets/images/entitlements-image-github-no-draft-pr-785626465cfe1b8183918ee6bd3aefb1.svg @@ -0,0 +1,771 @@ + + + + diff --git a/pr-preview/pr-921/assets/images/entitlements-image-pricing-github-2276507856dd07b091bcecc2376dde05.svg b/pr-preview/pr-921/assets/images/entitlements-image-pricing-github-2276507856dd07b091bcecc2376dde05.svg new file mode 100644 index 000000000..b1ef45135 --- /dev/null +++ b/pr-preview/pr-921/assets/images/entitlements-image-pricing-github-2276507856dd07b091bcecc2376dde05.svg @@ -0,0 +1,3680 @@ + + + + diff --git a/pr-preview/pr-921/assets/images/entitlements-requirements-fdd4048edc4d4b3b78785f4c0671e0b1.svg b/pr-preview/pr-921/assets/images/entitlements-requirements-fdd4048edc4d4b3b78785f4c0671e0b1.svg new file mode 100644 index 000000000..01fa6be5b --- /dev/null +++ b/pr-preview/pr-921/assets/images/entitlements-requirements-fdd4048edc4d4b3b78785f4c0671e0b1.svg @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/assets/images/fgn-2023-12-bdd-919c556a442e23bdac6643a34267ea70.png b/pr-preview/pr-921/assets/images/fgn-2023-12-bdd-919c556a442e23bdac6643a34267ea70.png new file mode 100644 index 000000000..7ddbc5943 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2023-12-bdd-919c556a442e23bdac6643a34267ea70.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2023-12-canonical-38a8b58970e46161957f5acb3ed43a46.png b/pr-preview/pr-921/assets/images/fgn-2023-12-canonical-38a8b58970e46161957f5acb3ed43a46.png new file mode 100644 index 000000000..0fa39cff5 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2023-12-canonical-38a8b58970e46161957f5acb3ed43a46.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2023-12-language-8a3e7f852814fa536430c8e3f81e57f1.png b/pr-preview/pr-921/assets/images/fgn-2023-12-language-8a3e7f852814fa536430c8e3f81e57f1.png new file mode 100644 index 000000000..b9c3eb0bf Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2023-12-language-8a3e7f852814fa536430c8e3f81e57f1.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2023-12-validation-b3df7ed681e938abf6f1d43c02423439.png b/pr-preview/pr-921/assets/images/fgn-2023-12-validation-b3df7ed681e938abf6f1d43c02423439.png new file mode 100644 index 000000000..cbfdc847d Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2023-12-validation-b3df7ed681e938abf6f1d43c02423439.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-01-team-fdc90c95b67c4a2f60a3235944480b1d.png b/pr-preview/pr-921/assets/images/fgn-2024-01-team-fdc90c95b67c4a2f60a3235944480b1d.png new file mode 100644 index 000000000..a2e74c882 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-01-team-fdc90c95b67c4a2f60a3235944480b1d.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-01-vscode-d007f1d2381717433705be88761959e2.gif b/pr-preview/pr-921/assets/images/fgn-2024-01-vscode-d007f1d2381717433705be88761959e2.gif new file mode 100644 index 000000000..6baf785f4 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-01-vscode-d007f1d2381717433705be88761959e2.gif differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-06-securitycon-booth-b547906de2fa364259b5ba8c112ba91c.png b/pr-preview/pr-921/assets/images/fgn-2024-06-securitycon-booth-b547906de2fa364259b5ba8c112ba91c.png new file mode 100644 index 000000000..4606e5c18 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-06-securitycon-booth-b547906de2fa364259b5ba8c112ba91c.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-06-securitycon-talk-57abfc6e4e3f7e573481a2fdfe30692c.jpg b/pr-preview/pr-921/assets/images/fgn-2024-06-securitycon-talk-57abfc6e4e3f7e573481a2fdfe30692c.jpg new file mode 100644 index 000000000..f418cfacc Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-06-securitycon-talk-57abfc6e4e3f7e573481a2fdfe30692c.jpg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-10-andrea-chiarelli-c078f103fd5b28ef4dfff0b1245aae0e.jpeg b/pr-preview/pr-921/assets/images/fgn-2024-10-andrea-chiarelli-c078f103fd5b28ef4dfff0b1245aae0e.jpeg new file mode 100644 index 000000000..1a64f7844 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-10-andrea-chiarelli-c078f103fd5b28ef4dfff0b1245aae0e.jpeg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-10-andres-aguiar-68c2e8b22fedf6e908b5f6bb6ccbc920.jpg b/pr-preview/pr-921/assets/images/fgn-2024-10-andres-aguiar-68c2e8b22fedf6e908b5f6bb6ccbc920.jpg new file mode 100644 index 000000000..957a736fa Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-10-andres-aguiar-68c2e8b22fedf6e908b5f6bb6ccbc920.jpg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-10-kiah-imani-eceac7fa9e3d3ea9257956280ed9007c.jpeg b/pr-preview/pr-921/assets/images/fgn-2024-10-kiah-imani-eceac7fa9e3d3ea9257956280ed9007c.jpeg new file mode 100644 index 000000000..4d7a323ea Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-10-kiah-imani-eceac7fa9e3d3ea9257956280ed9007c.jpeg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-andrea-chiarelli1-8b865d5915d209e4ba425ec08706268e.png b/pr-preview/pr-921/assets/images/fgn-2024-11-andrea-chiarelli1-8b865d5915d209e4ba425ec08706268e.png new file mode 100644 index 000000000..94868c373 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-andrea-chiarelli1-8b865d5915d209e4ba425ec08706268e.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-andrea-chiarelli2-678faee102f1bf7a25d178f91f8bbc92.png b/pr-preview/pr-921/assets/images/fgn-2024-11-andrea-chiarelli2-678faee102f1bf7a25d178f91f8bbc92.png new file mode 100644 index 000000000..de94e74b8 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-andrea-chiarelli2-678faee102f1bf7a25d178f91f8bbc92.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-chicago-offsite-team-photo-eb4af67e361d204336a083503595de2f.png b/pr-preview/pr-921/assets/images/fgn-2024-11-chicago-offsite-team-photo-eb4af67e361d204336a083503595de2f.png new file mode 100644 index 000000000..08f76f0ae Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-chicago-offsite-team-photo-eb4af67e361d204336a083503595de2f.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-kubecon1-85f27733b8385fd1339ec1c2e168741c.jpg b/pr-preview/pr-921/assets/images/fgn-2024-11-kubecon1-85f27733b8385fd1339ec1c2e168741c.jpg new file mode 100644 index 000000000..2e9b5c0a0 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-kubecon1-85f27733b8385fd1339ec1c2e168741c.jpg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-kubecon2-10ef89f7b795d8b870ad8deca04926aa.jpg b/pr-preview/pr-921/assets/images/fgn-2024-11-kubecon2-10ef89f7b795d8b870ad8deca04926aa.jpg new file mode 100644 index 000000000..8c0c11ef5 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-kubecon2-10ef89f7b795d8b870ad8deca04926aa.jpg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-linkedin-9463378da14cb33d27b81eb8fb461a86.png b/pr-preview/pr-921/assets/images/fgn-2024-11-linkedin-9463378da14cb33d27b81eb8fb461a86.png new file mode 100644 index 000000000..4b78fa4d6 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-linkedin-9463378da14cb33d27b81eb8fb461a86.png differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-open-fga-ranks-5th-3bc380d0478b8988d07beaeca665cca2.jpeg b/pr-preview/pr-921/assets/images/fgn-2024-11-open-fga-ranks-5th-3bc380d0478b8988d07beaeca665cca2.jpeg new file mode 100644 index 000000000..ddc3a90b8 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-open-fga-ranks-5th-3bc380d0478b8988d07beaeca665cca2.jpeg differ diff --git a/pr-preview/pr-921/assets/images/fgn-2024-11-stars-d961d19917669492d95418e8f8ab7233.png b/pr-preview/pr-921/assets/images/fgn-2024-11-stars-d961d19917669492d95418e8f8ab7233.png new file mode 100644 index 000000000..d7e2a8f40 Binary files /dev/null and b/pr-preview/pr-921/assets/images/fgn-2024-11-stars-d961d19917669492d95418e8f8ab7233.png differ diff --git a/pr-preview/pr-921/assets/images/gdrive-gdrive1-22dac26c1f55a55daeb65acff88ee193.svg b/pr-preview/pr-921/assets/images/gdrive-gdrive1-22dac26c1f55a55daeb65acff88ee193.svg new file mode 100644 index 000000000..4b14f9a27 --- /dev/null +++ b/pr-preview/pr-921/assets/images/gdrive-gdrive1-22dac26c1f55a55daeb65acff88ee193.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/gdrive-gdrive2-abe697d20cfce6658d6a09aed7af8d97.svg b/pr-preview/pr-921/assets/images/gdrive-gdrive2-abe697d20cfce6658d6a09aed7af8d97.svg new file mode 100644 index 000000000..b6c47a445 --- /dev/null +++ b/pr-preview/pr-921/assets/images/gdrive-gdrive2-abe697d20cfce6658d6a09aed7af8d97.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/gdrive-gdrive3-e82c9d5308de7d3b5e7b74b59d87044f.svg b/pr-preview/pr-921/assets/images/gdrive-gdrive3-e82c9d5308de7d3b5e7b74b59d87044f.svg new file mode 100644 index 000000000..6a103bdbb --- /dev/null +++ b/pr-preview/pr-921/assets/images/gdrive-gdrive3-e82c9d5308de7d3b5e7b74b59d87044f.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/gdrive-gdrive4-9b75eafa345dde22742988b225671a69.svg b/pr-preview/pr-921/assets/images/gdrive-gdrive4-9b75eafa345dde22742988b225671a69.svg new file mode 100644 index 000000000..5e39ada56 --- /dev/null +++ b/pr-preview/pr-921/assets/images/gdrive-gdrive4-9b75eafa345dde22742988b225671a69.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + domain:xyz + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/gdrive-org-fe69008225e62f28ff2280708e875f09.svg b/pr-preview/pr-921/assets/images/gdrive-org-fe69008225e62f28ff2280708e875f09.svg new file mode 100644 index 000000000..834bd206e --- /dev/null +++ b/pr-preview/pr-921/assets/images/gdrive-org-fe69008225e62f28ff2280708e875f09.svg @@ -0,0 +1,10 @@ + + + + + + XYZ + + XYZ + + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/gdrive-roles-ac60dede6567bd76e873d1a81d642532.svg b/pr-preview/pr-921/assets/images/gdrive-roles-ac60dede6567bd76e873d1a81d642532.svg new file mode 100644 index 000000000..562d2a535 --- /dev/null +++ b/pr-preview/pr-921/assets/images/gdrive-roles-ac60dede6567bd76e873d1a81d642532.svg @@ -0,0 +1,2419 @@ + + + + diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-01-55e7a873e7fdd4aa810922af9606ad0c.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-01-55e7a873e7fdd4aa810922af9606ad0c.svg new file mode 100644 index 000000000..f997a207c --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-01-55e7a873e7fdd4aa810922af9606ad0c.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-02-46c38ef0a05b5eac7e8a85c3ca02e20f.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-02-46c38ef0a05b5eac7e8a85c3ca02e20f.svg new file mode 100644 index 000000000..03620eae6 --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-02-46c38ef0a05b5eac7e8a85c3ca02e20f.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-03-3734cdad8827d03f6a76db672f13be46.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-03-3734cdad8827d03f6a76db672f13be46.svg new file mode 100644 index 000000000..2a4001f84 --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-03-3734cdad8827d03f6a76db672f13be46.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-04-e8b2110197173b6308a3f797e76aa471.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-04-e8b2110197173b6308a3f797e76aa471.svg new file mode 100644 index 000000000..151679729 --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-04-e8b2110197173b6308a3f797e76aa471.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-05-ffffd65d9b3eb843353c35f2f663a0c5.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-05-ffffd65d9b3eb843353c35f2f663a0c5.svg new file mode 100644 index 000000000..b967bb279 --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-05-ffffd65d9b3eb843353c35f2f663a0c5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-06-8eb4b8f4a925670b0ff05fa86c4b890e.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-06-8eb4b8f4a925670b0ff05fa86c4b890e.svg new file mode 100644 index 000000000..b26f30237 --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-06-8eb4b8f4a925670b0ff05fa86c4b890e.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/getting-started-diagram-07-110858004c2892e28df4c404a50abce2.svg b/pr-preview/pr-921/assets/images/getting-started-diagram-07-110858004c2892e28df4c404a50abce2.svg new file mode 100644 index 000000000..875635f58 --- /dev/null +++ b/pr-preview/pr-921/assets/images/getting-started-diagram-07-110858004c2892e28df4c404a50abce2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/github-01-14b7cc249174f7311e651e9541c4527b.svg b/pr-preview/pr-921/assets/images/github-01-14b7cc249174f7311e651e9541c4527b.svg new file mode 100644 index 000000000..50836f1a9 --- /dev/null +++ b/pr-preview/pr-921/assets/images/github-01-14b7cc249174f7311e651e9541c4527b.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + repo:contoso/tooling + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/github-02-2eaa2dc691d0378f661d8ce52dfab5d4.svg b/pr-preview/pr-921/assets/images/github-02-2eaa2dc691d0378f661d8ce52dfab5d4.svg new file mode 100644 index 000000000..fdee9812e --- /dev/null +++ b/pr-preview/pr-921/assets/images/github-02-2eaa2dc691d0378f661d8ce52dfab5d4.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + team:contoso/engineering + repo:contoso/tooling + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/github-03-7afa9c606e43a97e744eda1e1f201b02.svg b/pr-preview/pr-921/assets/images/github-03-7afa9c606e43a97e744eda1e1f201b02.svg new file mode 100644 index 000000000..36643acc8 --- /dev/null +++ b/pr-preview/pr-921/assets/images/github-03-7afa9c606e43a97e744eda1e1f201b02.svg @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + repo:contoso/tooling + team:contoso/engineering + + team:contoso/protocols + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/github-04-6a9b8175f0c09f9ce3b843911c620693.svg b/pr-preview/pr-921/assets/images/github-04-6a9b8175f0c09f9ce3b843911c620693.svg new file mode 100644 index 000000000..4900e39f4 --- /dev/null +++ b/pr-preview/pr-921/assets/images/github-04-6a9b8175f0c09f9ce3b843911c620693.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + team:contoso/protocols + + team:contoso/engineering + + repo:contoso/tooling + + org:contoso + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/github-org-base-permissions-drop-down-2952b06603835375e74da4bf2f8278f4.png b/pr-preview/pr-921/assets/images/github-org-base-permissions-drop-down-2952b06603835375e74da4bf2f8278f4.png new file mode 100644 index 000000000..e739407ad Binary files /dev/null and b/pr-preview/pr-921/assets/images/github-org-base-permissions-drop-down-2952b06603835375e74da4bf2f8278f4.png differ diff --git a/pr-preview/pr-921/assets/images/github-permission-level-1059e9392f2d7126e8376f141d5bad84.svg b/pr-preview/pr-921/assets/images/github-permission-level-1059e9392f2d7126e8376f141d5bad84.svg new file mode 100644 index 000000000..d8e2a93ea --- /dev/null +++ b/pr-preview/pr-921/assets/images/github-permission-level-1059e9392f2d7126e8376f141d5bad84.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/github-repo-access-level-6c53de1088cef314d5d1de14a8634727.svg b/pr-preview/pr-921/assets/images/github-repo-access-level-6c53de1088cef314d5d1de14a8634727.svg new file mode 100644 index 000000000..6c024dec8 --- /dev/null +++ b/pr-preview/pr-921/assets/images/github-repo-access-level-6c53de1088cef314d5d1de14a8634727.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/iot-01-01e62d5f3e91ef20a4f763fb2079c1fa.svg b/pr-preview/pr-921/assets/images/iot-01-01e62d5f3e91ef20a4f763fb2079c1fa.svg new file mode 100644 index 000000000..3d1541246 --- /dev/null +++ b/pr-preview/pr-921/assets/images/iot-01-01e62d5f3e91ef20a4f763fb2079c1fa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/pattern-5de3eb8b397a4a785603c49c6e70e860.png b/pr-preview/pr-921/assets/images/pattern-5de3eb8b397a4a785603c49c6e70e860.png new file mode 100644 index 000000000..73c435099 Binary files /dev/null and b/pr-preview/pr-921/assets/images/pattern-5de3eb8b397a4a785603c49c6e70e860.png differ diff --git a/pr-preview/pr-921/assets/images/slack-01-b6e717f5e865abef206372fda13e528e.svg b/pr-preview/pr-921/assets/images/slack-01-b6e717f5e865abef206372fda13e528e.svg new file mode 100644 index 000000000..2d74a57b7 --- /dev/null +++ b/pr-preview/pr-921/assets/images/slack-01-b6e717f5e865abef206372fda13e528e.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/assets/images/terminal-beeca3a53258f5076350c9fe9924d782.png b/pr-preview/pr-921/assets/images/terminal-beeca3a53258f5076350c9fe9924d782.png new file mode 100644 index 000000000..c659d4a19 Binary files /dev/null and b/pr-preview/pr-921/assets/images/terminal-beeca3a53258f5076350c9fe9924d782.png differ diff --git a/pr-preview/pr-921/assets/images/usersets-check-tree-68f05e3f382b35ea6be97c5115223351.png b/pr-preview/pr-921/assets/images/usersets-check-tree-68f05e3f382b35ea6be97c5115223351.png new file mode 100644 index 000000000..20686afaf Binary files /dev/null and b/pr-preview/pr-921/assets/images/usersets-check-tree-68f05e3f382b35ea6be97c5115223351.png differ diff --git a/pr-preview/pr-921/assets/js/01a85c17.7c09761d.js b/pr-preview/pr-921/assets/js/01a85c17.7c09761d.js new file mode 100644 index 000000000..b02060cb7 --- /dev/null +++ b/pr-preview/pr-921/assets/js/01a85c17.7c09761d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[8209],{44096:(e,t,a)=>{a.d(t,{in:()=>c,OU:()=>P,Ki:()=>A,kJ:()=>f,x:()=>l,e7:()=>m,J_:()=>b,Gx:()=>y});var s=a(96540),n=a(89532),i=a(36803),r=a(74848);function l(){const e=(0,i.A)(),t=e?.data?.blogMetadata;if(!t)throw new Error("useBlogMetadata() can't be called on the current route because the blog metadata could not be found in route context");return t}const o=s.createContext(null);function c(e){let{children:t,content:a,isBlogPostPage:n=!1}=e;const i=function(e){let{content:t,isBlogPostPage:a}=e;return(0,s.useMemo)((()=>({metadata:t.metadata,frontMatter:t.frontMatter,assets:t.assets,toc:t.toc,isBlogPostPage:a})),[t,a])}({content:a,isBlogPostPage:n});return(0,r.jsx)(o.Provider,{value:i,children:t})}function m(){const e=(0,s.useContext)(o);if(null===e)throw new n.dV("BlogPostProvider");return e}var d=a(86025),u=a(44586);const g=e=>new Date(e).toISOString();function p(e){const t=e.map(x);return{author:1===t.length?t[0]:t}}function h(e,t,a){return e?{image:j({imageUrl:t(e,{absolute:!0}),caption:`title image for the blog post: ${a}`})}:{}}function f(e){const{siteConfig:t}=(0,u.A)(),{withBaseUrl:a}=(0,d.hH)(),{metadata:{blogDescription:s,blogTitle:n,permalink:i}}=e,r=`${t.url}${i}`;return{"@context":"https://schema.org","@type":"Blog","@id":r,mainEntityOfPage:r,headline:n,description:s,blogPost:e.items.map((e=>function(e,t,a){const{assets:s,frontMatter:n,metadata:i}=e,{date:r,title:l,description:o,lastUpdatedAt:c}=i,m=s.image??n.image,d=n.keywords??[],u=`${t.url}${i.permalink}`,f=c?g(c):void 0;return{"@type":"BlogPosting","@id":u,mainEntityOfPage:u,url:u,headline:l,name:l,description:o,datePublished:r,...f?{dateModified:f}:{},...p(i.authors),...h(m,a,l),...d?{keywords:d}:{}}}(e.content,t,a)))}}function b(){const e=l(),{assets:t,metadata:a}=m(),{siteConfig:s}=(0,u.A)(),{withBaseUrl:n}=(0,d.hH)(),{date:i,title:r,description:o,frontMatter:c,lastUpdatedAt:f}=a,b=t.image??c.image,x=c.keywords??[],j=f?g(f):void 0,v=`${s.url}${a.permalink}`;return{"@context":"https://schema.org","@type":"BlogPosting","@id":v,mainEntityOfPage:v,url:v,headline:r,name:r,description:o,datePublished:i,...j?{dateModified:j}:{},...p(a.authors),...h(b,n,r),...x?{keywords:x}:{},isPartOf:{"@type":"Blog","@id":`${s.url}${e.blogBasePath}`,name:e.blogTitle}}}function x(e){return{"@type":"Person",...e.name?{name:e.name}:{},...e.title?{description:e.title}:{},...e.url?{url:e.url}:{},...e.email?{email:e.email}:{},...e.imageURL?{image:e.imageURL}:{}}}function j(e){let{imageUrl:t,caption:a}=e;return{"@type":"ImageObject","@id":t,url:t,contentUrl:t,caption:a}}var v=a(56347),N=a(28774),C=a(31682),k=a(99169);function y(e){const{pathname:t}=(0,v.zy)();return(0,s.useMemo)((()=>e.filter((e=>function(e,t){return!(e.unlisted&&!(0,k.ys)(e.permalink,t))}(e,t)))),[e,t])}function A(e){const t=(0,C.$z)(e,(e=>`${new Date(e.date).getFullYear()}`)),a=Object.entries(t);return a.reverse(),a}function P(e){let{items:t,ulClassName:a,liClassName:s,linkClassName:n,linkActiveClassName:i}=e;return(0,r.jsx)("ul",{className:a,children:t.map((e=>(0,r.jsx)("li",{className:s,children:(0,r.jsx)(N.A,{isNavLink:!0,to:e.permalink,className:n,activeClassName:i,children:e.title})},e.permalink)))})}},28027:(e,t,a)=>{a.d(t,{A:()=>O});var s=a(96540),n=a(34164),i=a(12161),r=a(24581),l=a(21312),o=a(44096),c=a(6342),m=a(51107),d=a(74848);function u(e){let{year:t,yearGroupHeadingClassName:a,children:s}=e;return(0,d.jsxs)("div",{role:"group",children:[(0,d.jsx)(m.A,{as:"h3",className:a,children:t}),s]})}function g(e){let{items:t,yearGroupHeadingClassName:a,ListComponent:s}=e;if((0,c.p)().blog.sidebar.groupByYear){const e=(0,o.Ki)(t);return(0,d.jsx)(d.Fragment,{children:e.map((e=>{let[t,n]=e;return(0,d.jsx)(u,{year:t,yearGroupHeadingClassName:a,children:(0,d.jsx)(s,{items:n})},t)}))})}return(0,d.jsx)(s,{items:t})}const p=(0,s.memo)(g),h="sidebar_re4s",f="sidebarItemTitle_pO2u",b="sidebarItemList_Yudw",x="sidebarItem__DBe",j="sidebarItemLink_mo7H",v="sidebarItemLinkActive_I1ZP",N="yearGroupHeading_rMGB",C=e=>{let{items:t}=e;return(0,d.jsx)(o.OU,{items:t,ulClassName:(0,n.A)(b,"clean-list"),liClassName:x,linkClassName:j,linkActiveClassName:v})};function k(e){let{sidebar:t}=e;const a=(0,o.Gx)(t.items);return(0,d.jsx)("aside",{className:"col col--3",children:(0,d.jsxs)("nav",{className:(0,n.A)(h,"thin-scrollbar"),"aria-label":(0,l.T)({id:"theme.blog.sidebar.navAriaLabel",message:"Blog recent posts navigation",description:"The ARIA label for recent posts in the blog sidebar"}),children:[(0,d.jsx)("div",{className:(0,n.A)(f,"margin-bottom--md"),children:t.title}),(0,d.jsx)(p,{items:a,ListComponent:C,yearGroupHeadingClassName:N})]})})}const y=(0,s.memo)(k);var A=a(75600);const P={yearGroupHeading:"yearGroupHeading_QT03"},_=e=>{let{items:t}=e;return(0,d.jsx)(o.OU,{items:t,ulClassName:"menu__list",liClassName:"menu__list-item",linkClassName:"menu__link",linkActiveClassName:"menu__link--active"})};function w(e){let{sidebar:t}=e;const a=(0,o.Gx)(t.items);return(0,d.jsx)(p,{items:a,ListComponent:_,yearGroupHeadingClassName:P.yearGroupHeading})}function B(e){return(0,d.jsx)(A.GX,{component:w,props:e})}const G=(0,s.memo)(B);function H(e){let{sidebar:t}=e;const a=(0,r.l)();return t?.items.length?"mobile"===a?(0,d.jsx)(G,{sidebar:t}):(0,d.jsx)(y,{sidebar:t}):null}function O(e){const{sidebar:t,toc:a,children:s,...r}=e,l=t&&t.items.length>0;return(0,d.jsx)(i.A,{...r,children:(0,d.jsx)("div",{className:"container margin-vert--lg",children:(0,d.jsxs)("div",{className:"row",children:[(0,d.jsx)(H,{sidebar:t}),(0,d.jsx)("main",{className:(0,n.A)("col",{"col--7":l,"col--9 col--offset-1":!l}),children:s}),a&&(0,d.jsx)("div",{className:"col col--2",children:a})]})})})}},69158:(e,t,a)=>{a.r(t),a.d(t,{default:()=>f});a(96540);var s=a(34164),n=a(21312);const i=()=>(0,n.T)({id:"theme.tags.tagsPageTitle",message:"Tags",description:"The title of the tag list page"});var r=a(61213),l=a(17559),o=a(28027),c=a(56133),m=a(51107);const d={tag:"tag_Nnez"};var u=a(74848);function g(e){let{letterEntry:t}=e;return(0,u.jsxs)("article",{children:[(0,u.jsx)(m.A,{as:"h2",id:t.letter,children:t.letter}),(0,u.jsx)("ul",{className:"padding--none",children:t.tags.map((e=>(0,u.jsx)("li",{className:d.tag,children:(0,u.jsx)(c.A,{...e})},e.permalink)))}),(0,u.jsx)("hr",{})]})}function p(e){let{tags:t}=e;const a=function(e){const t={};return Object.values(e).forEach((e=>{const a=function(e){return e[0].toUpperCase()}(e.label);t[a]??=[],t[a].push(e)})),Object.entries(t).sort(((e,t)=>{let[a]=e,[s]=t;return a.localeCompare(s)})).map((e=>{let[t,a]=e;return{letter:t,tags:a.sort(((e,t)=>e.label.localeCompare(t.label)))}}))}(t);return(0,u.jsx)("section",{className:"margin-vert--lg",children:a.map((e=>(0,u.jsx)(g,{letterEntry:e},e.letter)))})}var h=a(41463);function f(e){let{tags:t,sidebar:a}=e;const n=i();return(0,u.jsxs)(r.e3,{className:(0,s.A)(l.G.wrapper.blogPages,l.G.page.blogTagsListPage),children:[(0,u.jsx)(r.be,{title:n}),(0,u.jsx)(h.A,{tag:"blog_tags_list"}),(0,u.jsxs)(o.A,{sidebar:a,children:[(0,u.jsx)(m.A,{as:"h1",children:n}),(0,u.jsx)(p,{tags:t})]})]})}},56133:(e,t,a)=>{a.d(t,{A:()=>l});a(96540);var s=a(34164),n=a(28774);const i={tag:"tag_zVej",tagRegular:"tagRegular_sFm0",tagWithCount:"tagWithCount_h2kH"};var r=a(74848);function l(e){let{permalink:t,label:a,count:l,description:o}=e;return(0,r.jsxs)(n.A,{href:t,title:o,className:(0,s.A)(i.tag,l?i.tagWithCount:i.tagRegular),children:[a,l&&(0,r.jsx)("span",{children:l})]})}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/028b1cc5.e4a4cf6d.js b/pr-preview/pr-921/assets/js/028b1cc5.e4a4cf6d.js new file mode 100644 index 000000000..d2d9e480e --- /dev/null +++ b/pr-preview/pr-921/assets/js/028b1cc5.e4a4cf6d.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[6767],{38860:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>h,default:()=>g,frontMatter:()=>d,metadata:()=>i,toc:()=>p});const i=JSON.parse('{"id":"content/interacting/read-tuple-changes","title":"How to get tuple changes","description":"Getting tuple changes","source":"@site/docs/content/interacting/read-tuple-changes.mdx","sourceDirName":"content/interacting","slug":"/interacting/read-tuple-changes","permalink":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/interacting/read-tuple-changes.mdx","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"title":"How to get tuple changes","sidebar_position":1,"slug":"/interacting/read-tuple-changes","description":"Getting tuple changes"},"sidebar":"docs","previous":{"title":"Relationship Queries","permalink":"/pr-preview/pr-921/docs/interacting/relationship-queries"},"next":{"title":"Search with Permissions","permalink":"/pr-preview/pr-921/docs/interacting/search-with-permissions"}}');var s=t(74848),l=t(28453),a=t(89987),r=t(11470),o=t(19365);const d={title:"How to get tuple changes",sidebar_position:1,slug:"/interacting/read-tuple-changes",description:"Getting tuple changes"},h="How to get tuple changes",c={},p=[{value:"Before you start",id:"before-you-start",level:2},{value:"Step by step",id:"step-by-step",level:2},{value:"01. Configure The API Client",id:"01-configure-the--api-client",level:3},{value:"02. Get changes for all object types",id:"02-get-changes-for-all-object-types",level:3},{value:"03. Get changes for a specific object type",id:"03-get-changes-for-a-specific-object-type",level:3}];function u(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",ul:"ul",...(0,l.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"how-to-get-tuple-changes",children:"How to get tuple changes"})}),"\n",(0,s.jsx)(a.ZE,{}),"\n",(0,s.jsx)(n.p,{children:"This section illustrates how to call the Read Changes API to get the list of relationship tuple changes that happened in your store, in the exact order that they happened. The API response includes tuples that have been added or removed in your store. It does not include other changes, like updates to your authorization model and adding new assertions."}),"\n",(0,s.jsx)(n.h2,{id:"before-you-start",children:"Before you start"}),"\n",(0,s.jsxs)(r.A,{groupId:"languages",children:[(0,s.jsx)(o.A,{value:a.NH.JS_SDK,label:a.px.get(a.NH.JS_SDK),children:(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(a.iz,{}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsx)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/install-sdk",children:"installed the SDK"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsxs)(n.a,{href:"../modeling",children:["configured the ",(0,s.jsx)(n.em,{children:"authorization model"})]})," and ",(0,s.jsxs)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/update-tuples#02-calling-write-api-to-add-new-relationship-tuples",children:["added some ",(0,s.jsx)(n.em,{children:"relationship tuples"})]}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have loaded ",(0,s.jsx)(n.code,{children:"FGA_STORE_ID"})," and ",(0,s.jsx)(n.code,{children:"FGA_API_URL"})," as environment variables."]}),"\n"]})}),(0,s.jsx)(o.A,{value:a.NH.GO_SDK,label:a.px.get(a.NH.GO_SDK),children:(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(a.iz,{}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsx)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/install-sdk",children:"installed the SDK"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsxs)(n.a,{href:"../modeling",children:["configured the ",(0,s.jsx)(n.em,{children:"authorization model"})]})," and ",(0,s.jsxs)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/update-tuples#02-calling-write-api-to-add-new-relationship-tuples",children:["added some ",(0,s.jsx)(n.em,{children:"relationship tuples"})]}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have loaded ",(0,s.jsx)(n.code,{children:"FGA_STORE_ID"})," and ",(0,s.jsx)(n.code,{children:"FGA_API_URL"})," as environment variables."]}),"\n"]})}),(0,s.jsx)(o.A,{value:a.NH.DOTNET_SDK,label:a.px.get(a.NH.DOTNET_SDK),children:(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(a.iz,{}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsx)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/install-sdk",children:"installed the SDK"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsxs)(n.a,{href:"../modeling",children:["configured the ",(0,s.jsx)(n.em,{children:"authorization model"})]}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have loaded ",(0,s.jsx)(n.code,{children:"FGA_STORE_ID"})," and ",(0,s.jsx)(n.code,{children:"FGA_API_URL"})," as environment variables."]}),"\n"]})}),(0,s.jsx)(o.A,{value:a.NH.PYTHON_SDK,label:a.px.get(a.NH.PYTHON_SDK),children:(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(a.iz,{}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsx)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/install-sdk",children:"installed the SDK"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsxs)(n.a,{href:"../modeling",children:["configured the ",(0,s.jsx)(n.em,{children:"authorization model"})]}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have loaded ",(0,s.jsx)(n.code,{children:"FGA_STORE_ID"})," and ",(0,s.jsx)(n.code,{children:"FGA_API_URL"})," as environment variables."]}),"\n"]})}),(0,s.jsx)(o.A,{value:a.NH.JAVA_SDK,label:a.px.get(a.NH.JAVA_SDK),children:(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(a.iz,{}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsx)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/install-sdk",children:"installed the SDK"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsxs)(n.a,{href:"../modeling",children:["configured the ",(0,s.jsx)(n.em,{children:"authorization model"})]}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have loaded ",(0,s.jsx)(n.code,{children:"FGA_STORE_ID"})," and ",(0,s.jsx)(n.code,{children:"FGA_API_URL"})," as environment variables."]}),"\n"]})}),(0,s.jsx)(o.A,{value:a.NH.CURL,label:a.px.get(a.NH.CURL),children:(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsx)(a.iz,{}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["You have ",(0,s.jsxs)(n.a,{href:"../modeling",children:["configured the ",(0,s.jsx)(n.em,{children:"authorization model"})]})," and ",(0,s.jsxs)(n.a,{href:"/pr-preview/pr-921/docs/getting-started/update-tuples#02-calling-write-api-to-add-new-relationship-tuples",children:["added some ",(0,s.jsx)(n.em,{children:"relationship tuples"})]}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["You have loaded ",(0,s.jsx)(n.code,{children:"FGA_STORE_ID"})," and ",(0,s.jsx)(n.code,{children:"FGA_API_URL"})," as environment variables."]}),"\n"]})})]}),"\n",(0,s.jsx)(n.h2,{id:"step-by-step",children:"Step by step"}),"\n",(0,s.jsx)(n.p,{children:"To get a chronologically ordered list of tuples that have been written or deleted in your store, you can do so by calling the Read Changes API."}),"\n",(0,s.jsxs)(n.h3,{id:"01-configure-the--api-client",children:["01. Configure The ",(0,s.jsx)(a.bU,{format:a.Ed.ShortForm})," API Client"]}),"\n",(0,s.jsx)(n.p,{children:"First you will need to configure the API client."}),"\n",(0,s.jsxs)(r.A,{groupId:"languages",children:[(0,s.jsx)(o.A,{value:a.NH.JS_SDK,label:a.px.get(a.NH.JS_SDK),children:(0,s.jsx)(a.nD,{lang:"js-sdk"})}),(0,s.jsx)(o.A,{value:a.NH.GO_SDK,label:a.px.get(a.NH.GO_SDK),children:(0,s.jsx)(a.nD,{lang:"go-sdk"})}),(0,s.jsx)(o.A,{value:a.NH.DOTNET_SDK,label:a.px.get(a.NH.DOTNET_SDK),children:(0,s.jsx)(a.nD,{lang:"dotnet-sdk"})}),(0,s.jsx)(o.A,{value:a.NH.PYTHON_SDK,label:a.px.get(a.NH.PYTHON_SDK),children:(0,s.jsx)(a.nD,{lang:"python-sdk"})}),(0,s.jsx)(o.A,{value:a.NH.JAVA_SDK,label:a.px.get(a.NH.JAVA_SDK),children:(0,s.jsx)(a.nD,{lang:"java-sdk"})}),(0,s.jsxs)(o.A,{value:a.NH.CURL,label:a.px.get(a.NH.CURL),children:[(0,s.jsxs)(n.p,{children:["To obtain the ",(0,s.jsx)(n.a,{href:"https://auth0.com/docs/authorization/flows/call-your-api-using-the-client-credentials-flow",children:"access token"}),":"]}),(0,s.jsx)(a.nD,{lang:"curl"})]})]}),"\n",(0,s.jsx)(n.h3,{id:"02-get-changes-for-all-object-types",children:"02. Get changes for all object types"}),"\n",(0,s.jsx)(n.p,{children:"To get a paginated list of changes that happened in your store:"}),"\n",(0,s.jsx)(a.JQ,{pageSize:25,skipSetup:!0,allowedLanguages:[a.NH.JS_SDK,a.NH.GO_SDK,a.NH.DOTNET_SDK,a.NH.PYTHON_SDK,a.NH.JAVA_SDK,a.NH.CLI,a.NH.CURL]}),"\n",(0,s.jsxs)(n.p,{children:["The result will contain an array of up to 25 tuples, with the operation (",(0,s.jsx)(n.code,{children:"write"})," or ",(0,s.jsx)(n.code,{children:"delete"}),"), and the timestamp in which that operation took place. The result will also contain a continuation token. Save the continuation token in persistent storage between calls so that it is not lost and you do not have to restart from scratch on system restart or on error."]}),"\n",(0,s.jsx)(n.p,{children:"You can then use this token to get the next set of changes:"}),"\n",(0,s.jsx)(a.JQ,{pageSize:25,continuationToken:"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==",skipSetup:!0,allowedLanguages:[a.NH.JS_SDK,a.NH.GO_SDK,a.NH.DOTNET_SDK,a.NH.PYTHON_SDK,a.NH.JAVA_SDK,a.NH.CLI,a.NH.CURL]}),"\n",(0,s.jsx)(n.p,{children:"Once there are no more changes to retrieve, the API will return the same token as the one you sent. Save the token in persistent storage to use at a later time."}),"\n",(0,s.jsx)(n.admonition,{type:"note",children:(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"The default page size is 50. The maximum page size allowed is 100."}),"\n",(0,s.jsxs)(n.li,{children:["The API response does not expand the tuples. If you wrote a tuple that includes a userset, like ",(0,s.jsx)(n.code,{children:'{"user": "group:abc#member", "relation": "owner": "doc:budget"}'}),", the Read Changes API will return that exact tuple."]}),"\n"]})}),"\n",(0,s.jsx)(n.h3,{id:"03-get-changes-for-a-specific-object-type",children:"03. Get changes for a specific object type"}),"\n",(0,s.jsx)(n.p,{children:"Imagine you have the following authorization model:"}),"\n",(0,s.jsx)(a.pB,{configuration:{schema_version:"1.1",type_definitions:[{type:"user"},{type:"group",relations:{member:{this:{}}},metadata:{relations:{member:{directly_related_user_types:[{type:"user"}]}}}},{type:"folder",relations:{owner:{this:{}}},metadata:{relations:{owner:{directly_related_user_types:[{type:"group",relation:"member"},{type:"user"}]}}}},{type:"doc",relations:{owner:{this:{}}},metadata:{relations:{owner:{directly_related_user_types:[{type:"group",relation:"member"},{type:"user"}]}}}}]}}),"\n",(0,s.jsxs)(n.p,{children:["It is possible to get a list of changes that happened in your store that relate only to one specific object type, like ",(0,s.jsx)(n.code,{children:"folder"}),", by issuing a call like this:"]}),"\n",(0,s.jsx)(a.JQ,{pageSize:25,type:"folder",skipSetup:!0,allowedLanguages:[a.NH.JS_SDK,a.NH.GO_SDK,a.NH.DOTNET_SDK,a.NH.PYTHON_SDK,a.NH.JAVA_SDK,a.NH.CLI,a.NH.CURL]}),"\n",(0,s.jsxs)(n.p,{children:["The response will include a continuation token. In subsequent calls, you have to include the token and the ",(0,s.jsx)(n.code,{children:"type"}),". (If you send this continuation token without the ",(0,s.jsx)(n.code,{children:"type"})," parameter set, you will get an error)."]}),"\n",(0,s.jsx)(a.JQ,{pageSize:25,type:"folder",continuationToken:"eyJwayI6IkxBVEVTVF9OU0NPTkZJR19hdXRoMHN0b3JlIiwic2siOiIxem1qbXF3MWZLZExTcUoyN01MdTdqTjh0cWgifQ==",skipSetup:!0,allowedLanguages:[a.NH.JS_SDK,a.NH.GO_SDK,a.NH.DOTNET_SDK,a.NH.PYTHON_SDK,a.NH.JAVA_SDK,a.NH.CLI,a.NH.CURL]})]})}function g(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(u,{...e})}):u(e)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/03f1273c.c989ebbc.js b/pr-preview/pr-921/assets/js/03f1273c.c989ebbc.js new file mode 100644 index 000000000..a1e9e5644 --- /dev/null +++ b/pr-preview/pr-921/assets/js/03f1273c.c989ebbc.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[9884],{74575:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>h,frontMatter:()=>r,metadata:()=>a,toc:()=>p});var a=t(76523),i=t(74848),o=t(28453);const r={title:"Join the OpenFGA team at KubeCon NA 2023",description:"OpenFGA at KubeCon",slug:"kubecon-na-2023",date:new Date("2023-10-12T00:00:00.000Z"),authors:"aaguiar",tags:["conferences","kubecon"],image:"https://openfga.dev/img/openfga_logo.svg",hide_table_of_contents:!1},s="Join the OpenFGA team at KubeCon NA 2023!",l={authorsImageUrls:[void 0]},p=[];function c(e){const n={a:"a",li:"li",p:"p",ul:"ul",...(0,o.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:"As you'd expect, the OpenFGA team will be at KubeCon NA 2023 in Chicago, IL!"}),"\n",(0,i.jsx)(n.p,{children:"We'll have a packed agenda for the week:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://www.linkedin.com/in/jonathan-whitaker-5a8b2484/",children:"Jonathan Whitaker"})," and ",(0,i.jsx)(n.a,{href:"https://www.linkedin.com/in/luxas/",children:"Lucas K\xe4ldstr\xf6m"})," will be presenting in ",(0,i.jsx)(n.a,{href:"https://cloud-native.rejekts.io/",children:"Could_Native Rejects"})," on how to use OpenFGA to manage and extend authorization in Kubernetes. Learn more ",(0,i.jsx)(n.a,{href:"https://cfp.cloud-native.rejekts.io/cloud-native-rejekts-na-chicago-2023/speaker/XB7EUR/",children:"here"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://www.linkedin.com/in/miparnisari/",children:"Maria Ines Parnisari"})," and ",(0,i.jsx)(n.a,{href:"https://www.linkedin.com/in/aaguiar/",children:"Andres Aguiar"})," will be presenting in ",(0,i.jsx)(n.a,{href:"https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/co-located-events/appdevelopercon/",children:"AppDeveloperCon"})," about modernizing authorization for cloud native applications using OpenFGA. Learn more ",(0,i.jsx)(n.a,{href:"https://colocatedeventsna2023.sched.com/event/1Rj2j/modernizing-authorization-for-cloud-native-applications-using-openfga-andres-aguiar-maria-ines-parnisari-okta",children:"here"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["We'll host a Project Meeting on Monday 9.30 AM in the Hudson room at the ",(0,i.jsx)(n.a,{href:"https://maps.app.goo.gl/77FwgGdpsWK5jWHd6",children:"Hilton Garden Inn"}),". We'll share how the product is being used, demo the latests features like our new CLI, the VS Code Extension, Conditional Relationships, the Java SDK... and more!"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsx)(n.p,{children:"We'll be in the CNCF Project Pavilion during the afternoons."}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["We'll host our ",(0,i.jsx)(n.a,{href:"https://github.com/openfga/community/blob/main/community-meetings.md",children:"OpenFGA community meeting"})," directly from KubeCon on Thursday 9th at 3PM UTC (8AM PST/11AM EST)."]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["If you want to meet with the team outside of these events, please pick any spot that works for you in our ",(0,i.jsx)(n.a,{href:"https://calendar.app.google/GonEwLboKvPkG8pL6",children:"calendar"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"See you in Chicago!"})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(c,{...e})}):c(e)}},76523:e=>{e.exports=JSON.parse('{"permalink":"/pr-preview/pr-921/blog/kubecon-na-2023","source":"@site/blog/kubecon-na-2023.md","title":"Join the OpenFGA team at KubeCon NA 2023","description":"OpenFGA at KubeCon","date":"2023-10-12T00:00:00.000Z","tags":[{"inline":true,"label":"conferences","permalink":"/pr-preview/pr-921/blog/tags/conferences"},{"inline":true,"label":"kubecon","permalink":"/pr-preview/pr-921/blog/tags/kubecon"}],"readingTime":0.885,"hasTruncateMarker":false,"authors":[{"name":"Andres Aguiar","title":"Product Manager","url":"https://github.com/aaguiarz","imageURL":"/pr-preview/pr-921/img/blog/authors/andres.jpg","key":"aaguiar","page":null}],"frontMatter":{"title":"Join the OpenFGA team at KubeCon NA 2023","description":"OpenFGA at KubeCon","slug":"kubecon-na-2023","date":"2023-10-12T00:00:00.000Z","authors":"aaguiar","tags":["conferences","kubecon"],"image":"https://openfga.dev/img/openfga_logo.svg","hide_table_of_contents":false},"unlisted":false,"prevItem":{"title":"Conditional Relationship Tuples for OpenFGA","permalink":"/pr-preview/pr-921/blog/conditional-tuples-announcement"}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/0682978e.73133772.js b/pr-preview/pr-921/assets/js/0682978e.73133772.js new file mode 100644 index 000000000..45f0eb4e2 --- /dev/null +++ b/pr-preview/pr-921/assets/js/0682978e.73133772.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[7962],{11321:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>r,default:()=>m,frontMatter:()=>d,metadata:()=>o,toc:()=>c});const o=JSON.parse('{"id":"content/modeling/modular-models","title":"Modular Models","description":"Modular Models","source":"@site/docs/content/modeling/modular-models.mdx","sourceDirName":"content/modeling","slug":"/modeling/modular-models","permalink":"/pr-preview/pr-921/docs/modeling/modular-models","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/modeling/modular-models.mdx","tags":[],"version":"current","sidebarPosition":6,"frontMatter":{"sidebar_position":6,"slug":"/modeling/modular-models","description":"Modular Models"},"sidebar":"docs","previous":{"title":"Testing Models","permalink":"/pr-preview/pr-921/docs/modeling/testing"},"next":{"title":"Building Blocks","permalink":"/pr-preview/pr-921/docs/modeling/building-blocks"}}');var t=i(74848),a=i(28453),s=i(89987);const d={sidebar_position:6,slug:"/modeling/modular-models",description:"Modular Models"},r="Modular Models",l={},c=[{value:"Key Concepts",id:"key-concepts",level:2},{value:"fga.mod",id:"fgamod",level:3},{value:"Modules",id:"modules",level:3},{value:"Type Extensions",id:"type-extensions",level:3},{value:"Example",id:"example",level:2},{value:"Core",id:"core",level:3},{value:"Issue tracking",id:"issue-tracking",level:3},{value:"Wiki",id:"wiki",level:3},{value:"fga.mod",id:"fgamod-1",level:3},{value:"Putting it all together",id:"putting-it-all-together",level:3},{value:"Viewing the model",id:"viewing-the-model",level:3}];function h(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,a.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"modular-models",children:"Modular Models"})}),"\n",(0,t.jsx)(s.ZE,{}),"\n",(0,t.jsx)(n.p,{children:"Authorization is application-specific. In an organization with multiple teams building different applications or modules, each team should be able to define and evolve their authorization policies independently."}),"\n",(0,t.jsx)(n.p,{children:"Modular models allows splitting your authorization model across multiple files and modules, improving upon some of the challenges that may be faced when maintaining an authorization model within a company, such as:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"A model can grow large and difficult to understand."}),"\n",(0,t.jsx)(n.li,{children:"As more teams begin to contribute to a model, the ownership boundaries may not be clear and code review processes might not scale."}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["With modular models, a single model can be split across multiple files in a project and organized in a way that makes sense for the project or teams collaborating on it. For example, modular models allows ownership for reviews to be expressed using a feature like ",(0,t.jsx)(n.a,{href:"https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners",children:"GitHub's"}),", ",(0,t.jsx)(n.a,{href:"https://docs.gitlab.com/ee/user/project/codeowners/",children:"GitLab's"})," or ",(0,t.jsx)(n.a,{href:"https://docs.gitea.com/usage/code-owners",children:"Gitea's"})," code owners."]}),"\n",(0,t.jsx)(n.h2,{id:"key-concepts",children:"Key Concepts"}),"\n",(0,t.jsx)(n.h3,{id:"fgamod",children:(0,t.jsx)(n.code,{children:"fga.mod"})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.code,{children:"fga.mod"})," file is the project file for modular models. It specifies the schema version for the final combined model and lists the individual files that make up the modular model."]}),"\n",(0,t.jsxs)(n.table,{children:[(0,t.jsx)(n.thead,{children:(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.th,{children:"Property"}),(0,t.jsx)(n.th,{children:"Description"})]})}),(0,t.jsxs)(n.tbody,{children:[(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"schema"})}),(0,t.jsx)(n.td,{children:"The schema version to be used for the combined model"})]}),(0,t.jsxs)(n.tr,{children:[(0,t.jsx)(n.td,{children:(0,t.jsx)(n.code,{children:"contents"})}),(0,t.jsx)(n.td,{children:"The individual files that make up the modular model"})]})]})]}),"\n",(0,t.jsx)(n.h3,{id:"modules",children:"Modules"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(s.bU,{format:s.Ed.ShortForm})," modules define the types and relations for a specific application module or service."]}),"\n",(0,t.jsxs)(n.p,{children:["Modules are declared using the ",(0,t.jsx)(n.code,{children:"module"})," keyword in the DSL, and a module can be written across multiple files. A single file cannot have more than one module."]}),"\n",(0,t.jsx)(n.h3,{id:"type-extensions",children:"Type Extensions"}),"\n",(0,t.jsx)(n.p,{children:"As teams implement features, they might find that core types they are dependent upon might not contain all the relations they need. However, it might not make sense for these relations to be owned by the owner of that type if they aren't needed across the system."}),"\n",(0,t.jsx)(n.p,{children:"Modular models solves that problem by allowing individual types to be extended within other modules to to share those relations."}),"\n",(0,t.jsx)(n.p,{children:"The following are requirements for type extension:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"The extended type must exist"}),"\n",(0,t.jsx)(n.li,{children:"A single type can only be extended once per file"}),"\n",(0,t.jsx)(n.li,{children:"The relations added must not already exist, or be part of another type extension"}),"\n"]}),"\n",(0,t.jsx)(n.h2,{id:"example",children:"Example"}),"\n",(0,t.jsx)(n.p,{children:"The following example shows how an authorization model for a SaaS compny with a issue tracking and wiki software can implement modular models."}),"\n",(0,t.jsx)(n.h3,{id:"core",children:"Core"}),"\n",(0,t.jsx)(n.p,{children:"If there is a core set of types owned by a team that manages the overall identity for the company, the following provides the basics: users, organizations and groups that can be used by each product area."}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-dsl.openfga",children:"module core\n\ntype user\n\ntype organization\n relations\n define member: [user]\n define admin: [user]\n\ntype group\n relations\n define member: [user]\n"})}),"\n",(0,t.jsx)(n.h3,{id:"issue-tracking",children:"Issue tracking"}),"\n",(0,t.jsxs)(n.p,{children:["The issue tracking software separates out the project- and issue-related types into separate files. Below, we also extend the ",(0,t.jsx)(n.code,{children:"organization"})," type to add a relation specific to the issue tracking feature: the ability to authorize who can create a project."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-dsl.openfga",children:"module issue-tracker\n\nextend type organization\n relations\n define can_create_project: admin\n\ntype project\n relations\n define organization: [organization]\n define viewer: member from organization\n"})}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-dsl.openfga",children:"module issue-tracker\n\ntype ticket\n relations\n define project: [project]\n define owner: [user]\n"})}),"\n",(0,t.jsx)(n.h3,{id:"wiki",children:"Wiki"}),"\n",(0,t.jsxs)(n.p,{children:["The wiki model is managed in one file until it grows. We can also extend the ",(0,t.jsx)(n.code,{children:"organization"})," type again to add a relation tracking who can create a space."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-dsl.openfga",children:"module wiki\n\nextend type organization\n relations\n define can_create_space: admin\n\n\ntype space\n relations\n define organization: [organization]\n define can_view_pages: member from organization\n\ntype page\n relations\n define space: [space]\n define owner: [user]\n"})}),"\n",(0,t.jsx)(n.h3,{id:"fgamod-1",children:(0,t.jsx)(n.code,{children:"fga.mod"})}),"\n",(0,t.jsxs)(n.p,{children:["To deploy this model, create the ",(0,t.jsx)(n.code,{children:"fga.mod"})," manifest file, set a schema version, and list the individual module files that comprise the model."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-yaml",children:"schema: '1.2'\ncontents:\n - core.fga\n - issue-tracker/projects.fga\n - issue-tracker/tickets.fga\n - wiki.fga\n"})}),"\n",(0,t.jsx)(n.h3,{id:"putting-it-all-together",children:"Putting it all together"}),"\n",(0,t.jsxs)(n.p,{children:["With individual parts of the modular model in place, write the model to ",(0,t.jsx)(s.bU,{format:s.Ed.ShortForm})," and run tests against it. Below is an example of what to run in the CLI:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-shell",children:"fga model write --store-id=$FGA_STORE_ID --file fga.mod\n"})}),"\n",(0,t.jsx)(n.p,{children:"This model can now be queried and have tuples written to it, just like a singular file authorization model."}),"\n",(0,t.jsx)(s.dp,{relationshipTuples:[{user:"user:anne",relation:"admin",object:"organization:acme"},{user:"organization:acme",relation:"organization",object:"space:acme"},{user:"organization:acme",relation:"organization",object:"project:acme"}],skipSetup:!0,allowedLanguages:[s.NH.JS_SDK,s.NH.GO_SDK,s.NH.DOTNET_SDK,s.NH.PYTHON_SDK,s.NH.JAVA_SDK,s.NH.CLI,s.NH.CURL]}),"\n",(0,t.jsx)(s.ou,{user:"user:anne",relation:"can_create_space",object:"organization:acme",allowed:!0}),"\n",(0,t.jsx)(n.h3,{id:"viewing-the-model",children:"Viewing the model"}),"\n",(0,t.jsxs)(n.p,{children:["When using the CLI to view the combined model DSL with ",(0,t.jsx)(n.code,{children:"fga model get --store-id=$FGA_STORE_ID"}),", the DSL is annotated with comments defining the source module and file for types, relations and conditions."]}),"\n",(0,t.jsxs)(n.p,{children:["For example, the ",(0,t.jsx)(n.code,{children:"organization"})," type shows that the type is defined in the ",(0,t.jsx)(n.code,{children:"core.fga"})," file as part of the ",(0,t.jsx)(n.code,{children:"core"})," module, the ",(0,t.jsx)(n.code,{children:"can_create_project"})," relation is defined in ",(0,t.jsx)(n.code,{children:"issue-tracker/projects.fga"})," as part of the ",(0,t.jsx)(n.code,{children:"issuer-tracker"})," module, and the ",(0,t.jsx)(n.code,{children:"can_create_space"})," relation is defined in the ",(0,t.jsx)(n.code,{children:"wiki.fga"})," file as part of the ",(0,t.jsx)(n.code,{children:"wiki"})," module."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-dsl.openfga",children:"type organization # module: core, file: core.fga\n relations\n define admin: [user]\n define member: [user] or admin\n define can_create_project: admin # extended by: module: issue-tracker, file: issue-tracker/projects.fga\n define can_create_space: admin # extended by: module: wiki, file: wiki.fga\n"})})]})}function m(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(h,{...e})}):h(e)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/07d77440.d56e1548.js b/pr-preview/pr-921/assets/js/07d77440.d56e1548.js new file mode 100644 index 000000000..0d38dbf14 --- /dev/null +++ b/pr-preview/pr-921/assets/js/07d77440.d56e1548.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[362],{41010:e=>{e.exports=JSON.parse('{"tag":{"label":"conferences","permalink":"/pr-preview/pr-921/blog/tags/conferences","allTagsPath":"/pr-preview/pr-921/blog/tags","count":1,"unlisted":false},"listMetadata":{"permalink":"/pr-preview/pr-921/blog/tags/conferences","page":1,"postsPerPage":10,"totalPages":1,"totalCount":1,"blogDescription":"Blog","blogTitle":"Blog"}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/0938166f.52c5476b.js b/pr-preview/pr-921/assets/js/0938166f.52c5476b.js new file mode 100644 index 000000000..383e59ad6 --- /dev/null +++ b/pr-preview/pr-921/assets/js/0938166f.52c5476b.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[1786],{1600:(e,i,t)=>{t.r(i),t.d(i,{assets:()=>g,contentTitle:()=>d,default:()=>c,frontMatter:()=>a,metadata:()=>n,toc:()=>l});const n=JSON.parse('{"id":"content/modeling/migrating/overview","title":"Model Migrations","description":"This section has guides that focus on migrating models and relations.","source":"@site/docs/content/modeling/migrating/overview.mdx","sourceDirName":"content/modeling/migrating","slug":"/modeling/migrating","permalink":"/pr-preview/pr-921/docs/modeling/migrating","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/modeling/migrating/overview.mdx","tags":[],"version":"current","sidebarPosition":0,"frontMatter":{"id":"overview","title":"Model Migrations","slug":"/modeling/migrating","sidebar_position":0},"sidebar":"docs","previous":{"title":"Entitlements","permalink":"/pr-preview/pr-921/docs/modeling/advanced/entitlements"},"next":{"title":"Migrating Relations","permalink":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations"}}');var o=t(74848),r=t(28453),s=t(89987);const a={id:"overview",title:"Model Migrations",slug:"/modeling/migrating",sidebar_position:0},d="Content",g={},l=[];function m(e){const i={h1:"h1",header:"header",p:"p",...(0,r.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(s.ZE,{}),"\n",(0,o.jsx)(i.p,{children:"This section has guides that focus on migrating models and relations."}),"\n",(0,o.jsx)(s.rS,{title:"When to use",description:"The content in this section is useful:",listItems:["If you want to introduce changes to your existing authorization model or upgrade it to a new schema version."]}),"\n",(0,o.jsx)(i.header,{children:(0,o.jsx)(i.h1,{id:"content",children:"Content"})}),"\n",(0,o.jsx)(s.pV,{middle:[{title:"Migrating Relations",description:"A end-to-end example on renaming a relation.",to:"migrating/migrating-relations"},{title:"Migrating Models",description:"Learn how to safely update your model.",to:"migrating/migrating-models"}]})]})}function c(e={}){const{wrapper:i}={...(0,r.R)(),...e.components};return i?(0,o.jsx)(i,{...e,children:(0,o.jsx)(m,{...e})}):m(e)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/0bf6a463.ced4ddbd.js b/pr-preview/pr-921/assets/js/0bf6a463.ced4ddbd.js new file mode 100644 index 000000000..86b7f65a2 --- /dev/null +++ b/pr-preview/pr-921/assets/js/0bf6a463.ced4ddbd.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[9775],{28705:(e,t,s)=>{s.r(t),s.d(t,{assets:()=>d,contentTitle:()=>c,default:()=>p,frontMatter:()=>r,metadata:()=>i,toc:()=>l});const i=JSON.parse('{"id":"content/authorization-concepts","title":"Authorization Concepts","description":"Introduction to Authorization","source":"@site/docs/content/authorization-concepts.mdx","sourceDirName":"content","slug":"/authorization-concepts","permalink":"/pr-preview/pr-921/docs/authorization-concepts","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/authorization-concepts.mdx","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"title":"Authorization Concepts","description":"Introduction to Authorization","sidebar_position":1,"slug":"/authorization-concepts"},"sidebar":"docs","previous":{"title":"What is OpenFGA","permalink":"/pr-preview/pr-921/docs/fga"},"next":{"title":"OpenFGA Concepts","permalink":"/pr-preview/pr-921/docs/concepts"}}');var a=s(74848),o=s(28453),n=s(89987);const r={title:"Authorization Concepts",description:"Introduction to Authorization",sidebar_position:1,slug:"/authorization-concepts"},c="Authorization Concepts",d={},l=[{value:"Authentication and Authorization",id:"authentication-and-authorization",level:2},{value:"What is Fine-Grained Authorization?",id:"what-is-fine-grained-authorization",level:2},{value:"What is Role-Based Access Control?",id:"what-is-role-based-access-control",level:2},{value:"What is Attribute-Based Access Control?",id:"what-is-attribute-based-access-control",level:2},{value:"What is Policy-Based Access Control?",id:"what-is-policy-based-access-control",level:2},{value:"What is Relationship-Based Access Control?",id:"what-is-relationship-based-access-control",level:2},{value:"What is Zanzibar?",id:"what-is-zanzibar",level:2}];function h(e){const t={a:"a",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(t.header,{children:(0,a.jsx)(t.h1,{id:"authorization-concepts",children:"Authorization Concepts"})}),"\n",(0,a.jsx)(t.h2,{id:"authentication-and-authorization",children:"Authentication and Authorization"}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Authentication",children:"Authentication"})," ensures a user's identity. ",(0,a.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Authorization",children:"Authorization"})," determines if a user can perform a certain action on a particular resource."]}),"\n",(0,a.jsx)(t.p,{children:"For example, when you log in to Google, Authentication is the process of verifying that your username and password are correct. Authorization is the process of ensuring that you can access a given Google service or feature."}),"\n",(0,a.jsx)(t.h2,{id:"what-is-fine-grained-authorization",children:"What is Fine-Grained Authorization?"}),"\n",(0,a.jsx)(t.p,{children:"Fine-Grained Authorization (FGA) implies the ability to grant specific users permission to perform certain actions in specific resources."}),"\n",(0,a.jsx)(t.p,{children:"Well-designed FGA systems allow you to manage permissions for millions of objects and users. These permissions can change rapidly as a system continually adds objects and updates access permissions for its users."}),"\n",(0,a.jsx)(t.p,{children:"A notable example of FGA is Google Drive: access can be granted either to documents or to folders, as well as to individual users or users as a group, and access rights regularly change as new documents are created and shared with specific users or groups."}),"\n",(0,a.jsx)(t.h2,{id:"what-is-role-based-access-control",children:"What is Role-Based Access Control?"}),"\n",(0,a.jsxs)(t.p,{children:["In ",(0,a.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Role-based_access_control",children:"Role-Based Access Control"})," (RBAC), permissions are assigned to users based on their role in a system. For example, a user needs the ",(0,a.jsx)(t.code,{children:"editor"})," role to edit content."]}),"\n",(0,a.jsx)(t.p,{children:"RBAC systems enable you to define users, groups, roles, and permissions, then store them in a centralized location. Applications access that information to make authorization decisions."}),"\n",(0,a.jsx)(t.h2,{id:"what-is-attribute-based-access-control",children:"What is Attribute-Based Access Control?"}),"\n",(0,a.jsxs)(t.p,{children:["In ",(0,a.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Attribute-based_access_control",children:"Attribute-Based Access Control"})," (ABAC), permissions are granted based on a set of attributes that a user or resource possesses. For example, a user assigned both ",(0,a.jsx)(t.code,{children:"marketing"})," and ",(0,a.jsx)(t.code,{children:"manager"})," attributes is entitled to publish and delete posts that have a ",(0,a.jsx)(t.code,{children:"marketing"})," attribute."]}),"\n",(0,a.jsx)(t.p,{children:"Applications implementing ABAC need to retrieve information stored in multiple data sources - like RBAC services, user directories, and application-specific data sources - to make authorization decisions."}),"\n",(0,a.jsx)(t.h2,{id:"what-is-policy-based-access-control",children:"What is Policy-Based Access Control?"}),"\n",(0,a.jsx)(t.p,{children:"Policy-Based Access Control (PBAC) is the ability to manage authorization policies in a centralized way that\u2019s external to the application code. Most implementations of ABAC are also PBAC."}),"\n",(0,a.jsx)(t.h2,{id:"what-is-relationship-based-access-control",children:"What is Relationship-Based Access Control?"}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/Relationship-based_access_control",children:"Relationship-Based Access Control"})," (ReBAC) enables user access rules to be conditional on relations that a given user has with a given object ",(0,a.jsx)(t.em,{children:"and"})," that object's relationship with other objects. For example, a given user can view a given document if the user has access to the document's parent folder."]}),"\n",(0,a.jsx)(t.p,{children:"ReBAC is a superset of RBAC: you can fully implement RBAC with ReBAC.\nReBAC also lets you natively solve for ABAC when attributes can be expressed in the form of relationships. For example \u2018a user\u2019s manager\u2019, \u2018the parent folder\u2019, \u2018the owner of a document\u2019, \u2018the user\u2019s department\u2019 can be defined as relationships."}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(n.bU,{format:n.Ed.ShortForm})," extends ReBAC by making it simpler to express additional ABAC scenarios using ",(0,a.jsx)(t.a,{href:"/pr-preview/pr-921/docs/modeling/conditions",children:"Conditions"})," or ",(0,a.jsx)(t.a,{href:"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples",children:"Contextual Tuples"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"ReBAC can also be considered PBAC, as authorization policies are centralized."}),"\n",(0,a.jsx)(t.h2,{id:"what-is-zanzibar",children:"What is Zanzibar?"}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(t.a,{href:"https://research.google/pubs/pub48190/",children:"Zanzibar"})," is Google's global authorization system across Google's product suite. It\u2019s based on ReBAC and uses object-relation-user tuples to store relationship data, then checks those relations for a match between a user and an object. For more information, see ",(0,a.jsx)(t.a,{href:"https://zanzibar.academy",children:"Zanzibar Academy"}),"."]}),"\n",(0,a.jsx)(t.p,{children:"ReBAC systems based on Zanzibar store the data necessary to make authorization decisions in a centralized database. Applications only need to call an API to make authorization decisions."}),"\n",(0,a.jsxs)(t.p,{children:[(0,a.jsx)(n.bU,{format:n.Ed.ShortForm})," is an example of a Zanzibar-based authorization system."]}),"\n",(0,a.jsx)(n.XQ,{description:"Learn about {ProductName}.",relatedLinks:[{title:"{ProductName} Concepts",description:"Learn about the {ProductName} Concepts",link:"./concepts",id:"./concepts"},{title:"Modeling: Getting Started",description:"Learn about how to get started with modeling your permission system in {ProductName}.",link:"./getting-started",id:"./getting-started"}]})]})}function p(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,a.jsx)(t,{...e,children:(0,a.jsx)(h,{...e})}):h(e)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/116d061d.5b65e8d9.js b/pr-preview/pr-921/assets/js/116d061d.5b65e8d9.js new file mode 100644 index 000000000..bc2265b31 --- /dev/null +++ b/pr-preview/pr-921/assets/js/116d061d.5b65e8d9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[7178],{59622:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>a,default:()=>g,frontMatter:()=>p,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"content/getting-started/setup-openfga/overview","title":"Setup OpenFGA","description":"Setting up an OpenFGA server","source":"@site/docs/content/getting-started/setup-openfga/overview.mdx","sourceDirName":"content/getting-started/setup-openfga","slug":"/getting-started/setup-openfga/overview","permalink":"/pr-preview/pr-921/docs/getting-started/setup-openfga/overview","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/getting-started/setup-openfga/overview.mdx","tags":[],"version":"current","sidebarPosition":1,"frontMatter":{"title":"Setup OpenFGA","description":"Setting up an OpenFGA server","sidebar_position":1,"slug":"/getting-started/setup-openfga/overview"},"sidebar":"docs","previous":{"title":"Getting Started","permalink":"/pr-preview/pr-921/docs/getting-started"},"next":{"title":"Configure OpenFGA","permalink":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga"}}');var s=n(74848),o=n(28453),i=n(89987);const p={title:"Setup OpenFGA",description:"Setting up an OpenFGA server",sidebar_position:1,slug:"/getting-started/setup-openfga/overview"},a="Setup OpenFGA",d={},u=[];function c(e){const t={h1:"h1",header:"header",p:"p",...(0,o.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(t.header,{children:(0,s.jsx)(t.h1,{id:"setup-openfga",children:"Setup OpenFGA"})}),"\n",(0,s.jsx)(t.p,{children:"Follow the guides below to set up an OpenFGA server."}),"\n",(0,s.jsx)(i.ZE,{}),"\n",(0,s.jsx)(i.pV,{middle:[{title:"Configure an OpenFGA Server",description:"How to setup an OpenFGA server.",to:"configure-openfga"},{title:"Docker Setup Guide",description:"How to setup an OpenFGA server with Docker.",to:"docker"},{title:"Kubernetes Setup Guide",description:"How to setup an OpenFGA server with Kubernetes.",to:"kubernetes"},{title:"Setup Access Control",description:"How to enable and setup the built-in access control OpenFGA server (experimental).",to:"access-control"}]})]})}function g(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,s.jsx)(t,{...e,children:(0,s.jsx)(c,{...e})}):c(e)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/11a254f1.bffa6c09.js b/pr-preview/pr-921/assets/js/11a254f1.bffa6c09.js new file mode 100644 index 000000000..9326b6ed5 --- /dev/null +++ b/pr-preview/pr-921/assets/js/11a254f1.bffa6c09.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[3908],{35068:(e,n,i)=>{i.r(n),i.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>t,toc:()=>h});var t=i(92528),s=i(74848),a=i(28453);const r={title:"Fine Grained News - March 2024",description:"Fine Grained News",slug:"fine-grained-news-2024-03",date:new Date("2024-03-28T00:00:00.000Z"),authors:"aaguiar",tags:["newsletter"],image:"https://openfga.dev/img/og-rich-embed.png",hide_table_of_contents:!1},o="Fine Grained News",l={authorsImageUrls:[void 0]},h=[{value:"KubeCon Europe 2024 was super-busy!",id:"kubecon-europe-2024-was-super-busy",level:2},{value:"CNCF incubation",id:"cncf-incubation",level:2},{value:"New Adopters",id:"new-adopters",level:2},{value:"Community News",id:"community-news",level:2},{value:"New Releases",id:"new-releases",level:2},{value:"Transitioning from Discord to CNCF's Slack",id:"transitioning-from-discord-to-cncfs-slack",level:2},{value:"See you next month!",id:"see-you-next-month",level:2}];function d(e){const n={a:"a",h2:"h2",li:"li",p:"p",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.p,{children:"Welcome to Fine Grained News, KubeCon Edition!"}),"\n",(0,s.jsx)(n.h2,{id:"kubecon-europe-2024-was-super-busy",children:"KubeCon Europe 2024 was super-busy!"}),"\n",(0,s.jsx)(n.p,{children:"You can now watch online:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:["An AppDeveloperCon session about ",(0,s.jsx)(n.a,{href:"https://www.youtube.com/watch?v=5NkJHeToEwo",children:"Implementing Modern Cloud Native Authorization Using OpenFGA"})," where ",(0,s.jsx)(n.a,{href:"https://github.com/paulinejamin",children:"Pauline Jamin"})," and ",(0,s.jsx)(n.a,{href:"https://github.com/aaguiarz",children:"Andres Aguiar"})," go over how OpenFGA is helping Agicap to implement fine-grained authorization."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:["A 7-min Lightning Talk about ",(0,s.jsx)(n.a,{href:"https://www.youtube.com/watch?v=K7Me3OjFxJ0",children:"OpenFGA: The Cloud Native way to implement Fine Grained Authorization"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://www.linkedin.com/in/jonathan-whitaker-5a8b2484/",children:"Jonathan Whitaker"}),"'s talk about ",(0,s.jsx)(n.a,{href:"https://www.youtube.com/watch?v=UaK1EnRgrng",children:"Federated IAM for Kubernetes with OpenFGA"}),", demoing how to use OpenFGA and KeyCloak to implement fine-grained authorization in a Kubernetes cluster, in ways it's not possible today, like giving access to a user for 90 seconds."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:["We also participated in ",(0,s.jsx)(n.a,{href:"https://app.myonvent.com/event/operator-day",children:"Canonical's Operator Day"})," sharing how Canonical is using OpenFGA, but the presentation is not online yet."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Also, thanks to everyone who stopped by the OpenFGA Kiosk in the Project Pavilion to share their feedback about the project or learn more about it!"}),"\n",(0,s.jsx)(n.h2,{id:"cncf-incubation",children:"CNCF incubation"}),"\n",(0,s.jsx)(n.p,{children:"As you may know, the CNCF has three stages for projects: Sandbox, Incubation, and Graduation. OpenFGA is currently a Sandbox project."}),"\n",(0,s.jsxs)(n.p,{children:["We are very happy to announce that we just ",(0,s.jsx)(n.a,{href:"https://github.com/cncf/toc/pull/1276",children:"applied for Incubation"}),"! We are excited about this step and will keep you posted on the progress."]}),"\n",(0,s.jsx)(n.h2,{id:"new-adopters",children:"New Adopters"}),"\n",(0,s.jsxs)(n.p,{children:["The OpenFGA community ",(0,s.jsx)(n.a,{href:"https://github.com/openfga/community/blob/main/ADOPTERS.md",children:"maintains a list"})," of products/projects/companies that are using OpenFGA in production. We'd like to thank thank the following adopters for adding themselves to the list in the last month:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://www.instill.tech/",children:"Instill AI"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://zuplo.com",children:"Zuplo"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://openobserve.ai/",children:"OpenObserve"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://datum.net/",children:"Datum"})}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"If you are using OpenFGA in production, please consider adding your company/project to the list."}),"\n",(0,s.jsx)(n.h2,{id:"community-news",children:"Community News"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/rhamzeh/",children:"Raghd Hamzeh"})," represented OpenFGA in an ",(0,s.jsx)(n.a,{href:"https://www.youtube.com/watch?v=VyHbFwfrf04",children:"episode on Authorizing Access"}),' within a series called "You Choose - Choose Your Own Adventure: The Treacherous Trek to Security\u201d. This episode was comparing OpenFGA with Hexa and Paralus. OpenFGA was the project viewers voted for as most interested in being featured in a demo.']}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/Sambego",children:"Sam Bellen"})," published a ",(0,s.jsx)(n.a,{href:"https://github.com/Sambego/fga-drive-example/",children:"Google Drive example"})," using OpenFGA. It's a Next.js project, written in TypeScript and ready to deploy on Vercel."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/bytefish",children:"Philipp Wagner"})," is working on a ",(0,s.jsx)(n.a,{href:"https://github.com/bytefish/gitclub-dotnet",children:".NET example"})," inspired by the Github model."]}),"\n"]}),"\n",(0,s.jsxs)(n.li,{children:["\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.a,{href:"https://github.com/paulinejamin",children:"Pauline Jamin"})," and ",(0,s.jsx)(n.a,{href:"https://github.com/geoffroybraun",children:"Geoffroy Braun"})," will present about ",(0,s.jsx)(n.a,{href:"https://www.devoxx.fr/schedule/talk/?id=42356",children:"Infuser du m\xe9tier dans les autorisations avec ReBAC"})," at ",(0,s.jsx)(n.a,{href:"https://www.devoxx.fr/",children:"Devoxx France 2024"})," in April 17th."]}),"\n"]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"new-releases",children:"New Releases"}),"\n",(0,s.jsxs)(n.p,{children:["We just shipped a ",(0,s.jsx)(n.a,{href:"https://openfga.dev/blog/modular-models-announcement",children:"release candidate of Modular Models"}),", that makes it easy for multiple teams to collaborate in a single OpenFGA model. It requires the following components:"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/openfga/js-sdk/releases/tag/v0.3.5",children:"OpenFGA v.1.5.1"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/openfga/cli/releases/tag/v0.3.0",children:"CLI v0.3.0"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/openfga/vscode-ext/releases/tag/v0.2.20",children:"Visual Studio Code Extension v0.2.20"})}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"We also shipped new version of our SDKs with several fixes:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"https://github.com/openfga/js-sdk/releases/tag/v0.3.5",children:"Javascript SDK 0.3.5"}),"."]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/openfga/go-sdk/releases/tag/v0.3.5",children:"Go SDK v0.3.5"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"https://github.com/openfga/java-sdk/releases/tag/v0.4.0",children:"Java SDK v0.4.0"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"transitioning-from-discord-to-cncfs-slack",children:"Transitioning from Discord to CNCF's Slack"}),"\n",(0,s.jsxs)(n.p,{children:["As we mentioned in the last edition, we transitioned out from Discord for OpenFGA and are now using the CNCF ",(0,s.jsx)(n.a,{href:"https://cloud-native.slack.com/archives/C06G1NNH47N",children:"#openfga Slack channel"}),". If you are not part of the CNCF Slack workspace, you need to join the ",(0,s.jsx)(n.a,{href:"https://slack.cncf.io",children:"CNCF Slack"})," first."]}),"\n",(0,s.jsx)(n.h2,{id:"see-you-next-month",children:"See you next month!"}),"\n",(0,s.jsx)(n.p,{children:"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!"})]})}function c(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(d,{...e})}):d(e)}},92528:e=>{e.exports=JSON.parse('{"permalink":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","source":"@site/blog/fine-grained-news-2024-03.md","title":"Fine Grained News - March 2024","description":"Fine Grained News","date":"2024-03-28T00:00:00.000Z","tags":[{"inline":true,"label":"newsletter","permalink":"/pr-preview/pr-921/blog/tags/newsletter"}],"readingTime":2.64,"hasTruncateMarker":false,"authors":[{"name":"Andres Aguiar","title":"Product Manager","url":"https://github.com/aaguiarz","imageURL":"/pr-preview/pr-921/img/blog/authors/andres.jpg","key":"aaguiar","page":null}],"frontMatter":{"title":"Fine Grained News - March 2024","description":"Fine Grained News","slug":"fine-grained-news-2024-03","date":"2024-03-28T00:00:00.000Z","authors":"aaguiar","tags":["newsletter"],"image":"https://openfga.dev/img/og-rich-embed.png","hide_table_of_contents":false},"unlisted":false,"prevItem":{"title":"Modular Models","permalink":"/pr-preview/pr-921/blog/modular-models-announcement"},"nextItem":{"title":"Fine Grained News - February 2024","permalink":"/pr-preview/pr-921/blog/fine-grained-news-2024-02"}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/11d41818.e1b8ab33.js b/pr-preview/pr-921/assets/js/11d41818.e1b8ab33.js new file mode 100644 index 000000000..40db7746d --- /dev/null +++ b/pr-preview/pr-921/assets/js/11d41818.e1b8ab33.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[3277],{95757:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>o,default:()=>c,frontMatter:()=>r,metadata:()=>s,toc:()=>h});var s=t(44592),i=t(74848),a=t(28453);const r={title:"Fine Grained News - April 2024",description:"Fine Grained News",slug:"fine-grained-news-2024-04",date:new Date("2024-04-30T00:00:00.000Z"),authors:"aaguiar",tags:["newsletter"],image:"https://openfga.dev/img/og-rich-embed.png",hide_table_of_contents:!1},o="Fine Grained News",l={authorsImageUrls:[void 0]},h=[{value:"New Releases!",id:"new-releases",level:2},{value:"OpenFGA Hackathon",id:"openfga-hackathon",level:2},{value:"OpenFGA Security Assessment",id:"openfga-security-assessment",level:2},{value:"What's Next",id:"whats-next",level:2},{value:"Transitioning from Discord to CNCF's Slack",id:"transitioning-from-discord-to-cncfs-slack",level:2},{value:"See you next month!",id:"see-you-next-month",level:2}];function d(e){const n={a:"a",h2:"h2",li:"li",p:"p",ul:"ul",...(0,a.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.p,{children:"Welcome to Fine Grained News, April edition!"}),"\n",(0,i.jsx)(n.h2,{id:"new-releases",children:"New Releases!"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.a,{href:"https://openfga.dev/blog/modular-models-announcement",children:"Modular Models"})," is now part of the OpenFGA core, making it easy for multiple teams to collaborate on a single OpenFGA model. Check it out, we love the feature! :)"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["Thanks to the help provided by the ",(0,i.jsx)(n.a,{href:"https://github.com/spring-projects/spring-security/issues/14121",children:"Spring Security team"})," there's now a ",(0,i.jsx)(n.a,{href:"https://github.com/openfga/spring-boot-starter",children:"Spring Boot Starter for OpenFGA"}),"!"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["We shipped an OpenFGA Release Candidate with ",(0,i.jsx)(n.a,{href:"https://openfga.dev/blog/list-users-announcement",children:"a new ListUsers API"}),", that can be enabled with an experimental flag. ListUsers allows you to retrieve all the users that have a specific relation with a resource, for example, all users that can view a document."]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"openfga-hackathon",children:"OpenFGA Hackathon"}),"\n",(0,i.jsxs)(n.p,{children:["A few weeks ago we hosted a Hackathon where multiple team members experimented new ideas around OpenFGA. You'll need to wait until the next ",(0,i.jsx)(n.a,{href:"https://github.com/openfga/community/blob/main/community-meetings.md",children:"community meeting"})," to learn more :)."]}),"\n",(0,i.jsx)(n.h2,{id:"openfga-security-assessment",children:"OpenFGA Security Assessment"}),"\n",(0,i.jsxs)(n.p,{children:["We are working with the CNCF Tag-Security team on a ",(0,i.jsx)(n.a,{href:"https://github.com/cncf/tag-security/issues/1236",children:"joint security assessment"}),", which is a step required to get accepted as a CNCF Incubation project."]}),"\n",(0,i.jsx)(n.h2,{id:"whats-next",children:"What's Next"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["In collaboration with ",(0,i.jsx)(n.a,{href:"https://github.com/le-yams",children:"Yann D'Isanto"})," we are building a ",(0,i.jsx)(n.a,{href:"https://github.com/le-yams/openfga4intellij",children:"plugin for JetBrain's IDEs"})," to allow syntax coloring and validation of OpenFGA models. Together with the ",(0,i.jsx)(n.a,{href:"https://marketplace.visualstudio.com/items?itemName=openfga.openfga-vscode",children:"Visual Studio Code integration"})," and the ",(0,i.jsx)(n.a,{href:"https://github.com/matoous/tree-sitter-fga",children:"Tree sitter grammar"})," from ",(0,i.jsx)(n.a,{href:"https://github.com/matoous/",children:"Matou\u0161 Dzivjak"})," OpenFGA will get great coverage for major IDEs and editors."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["We'll be ",(0,i.jsx)(n.a,{href:"https://github.com/openfga/roadmap/issues/41",children:"instrumenting our SDKs"})," to provide metrics / tracing and logging through OpenTelemetry APIs."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["We'll be adding ",(0,i.jsx)(n.a,{href:"https://github.com/openfga/roadmap/issues/54",children:"additional consistency options"})," for OpenFGA query APIs."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["We'll be working on adding ",(0,i.jsx)(n.a,{href:"https://github.com/openfga/roadmap/issues/30",children:"authorization for OpenFGA APIs"}),"."]}),"\n"]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Please check the items above and let us know if you have any feedback or idea."}),"\n",(0,i.jsx)(n.h2,{id:"transitioning-from-discord-to-cncfs-slack",children:"Transitioning from Discord to CNCF's Slack"}),"\n",(0,i.jsxs)(n.p,{children:["As we mentioned in the last edition, we transitioned out from Discord for OpenFGA and are now using the CNCF ",(0,i.jsx)(n.a,{href:"https://cloud-native.slack.com/archives/C06G1NNH47N",children:"#openfga Slack channel"}),". If you are not part of the CNCF Slack workspace, you need to join the ",(0,i.jsx)(n.a,{href:"https://slack.cncf.io",children:"CNCF Slack"})," first."]}),"\n",(0,i.jsx)(n.h2,{id:"see-you-next-month",children:"See you next month!"}),"\n",(0,i.jsx)(n.p,{children:"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!"})]})}function c(e={}){const{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},44592:e=>{e.exports=JSON.parse('{"permalink":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","source":"@site/blog/fine-grained-news-2024-04.md","title":"Fine Grained News - April 2024","description":"Fine Grained News","date":"2024-04-30T00:00:00.000Z","tags":[{"inline":true,"label":"newsletter","permalink":"/pr-preview/pr-921/blog/tags/newsletter"}],"readingTime":1.785,"hasTruncateMarker":false,"authors":[{"name":"Andres Aguiar","title":"Product Manager","url":"https://github.com/aaguiarz","imageURL":"/pr-preview/pr-921/img/blog/authors/andres.jpg","key":"aaguiar","page":null}],"frontMatter":{"title":"Fine Grained News - April 2024","description":"Fine Grained News","slug":"fine-grained-news-2024-04","date":"2024-04-30T00:00:00.000Z","authors":"aaguiar","tags":["newsletter"],"image":"https://openfga.dev/img/og-rich-embed.png","hide_table_of_contents":false},"unlisted":false,"prevItem":{"title":"List Users API","permalink":"/pr-preview/pr-921/blog/list-users-announcement"},"nextItem":{"title":"Modular Models","permalink":"/pr-preview/pr-921/blog/modular-models-announcement"}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/12365047.2479b3e0.js b/pr-preview/pr-921/assets/js/12365047.2479b3e0.js new file mode 100644 index 000000000..51c4bc3b4 --- /dev/null +++ b/pr-preview/pr-921/assets/js/12365047.2479b3e0.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[7005],{66706:e=>{e.exports=JSON.parse('{"metadata":{"permalink":"/pr-preview/pr-921/blog/page/2","page":2,"postsPerPage":10,"totalPages":2,"totalCount":17,"previousPage":"/pr-preview/pr-921/blog","blogDescription":"Blog","blogTitle":"Blog"}}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/138e0e15.c4b4c28c.js b/pr-preview/pr-921/assets/js/138e0e15.c4b4c28c.js new file mode 100644 index 000000000..1a0f3e66d --- /dev/null +++ b/pr-preview/pr-921/assets/js/138e0e15.c4b4c28c.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[4921],{41597:e=>{e.exports=JSON.parse('{"name":"@easyops-cn/docusaurus-search-local","id":"default"}')}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/15369573.e1089af9.js b/pr-preview/pr-921/assets/js/15369573.e1089af9.js new file mode 100644 index 000000000..b06fe0c81 --- /dev/null +++ b/pr-preview/pr-921/assets/js/15369573.e1089af9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[4266],{10270:(e,t,i)=>{i.r(t),i.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>r,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"content/modeling/building-blocks/object-to-object-relationships","title":"Object to Object Relationships","description":"Modeling relationships between objects (e.g. folder parent of a document)","source":"@site/docs/content/modeling/building-blocks/object-to-object-relationships.mdx","sourceDirName":"content/modeling/building-blocks","slug":"/modeling/building-blocks/object-to-object-relationships","permalink":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/modeling/building-blocks/object-to-object-relationships.mdx","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2,"slug":"/modeling/building-blocks/object-to-object-relationships","description":"Modeling relationships between objects (e.g. folder parent of a document)"},"sidebar":"docs","previous":{"title":"Concentric Relationships","permalink":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships"},"next":{"title":"Usersets","permalink":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets"}}');var n=i(74848),o=i(28453),a=i(89987);const r={sidebar_position:2,slug:"/modeling/building-blocks/object-to-object-relationships",description:"Modeling relationships between objects (e.g. folder parent of a document)"},l="Object to Object Relationships",d={},c=[{value:"Before you start",id:"before-you-start",level:2},{value:"Modeling user groups",id:"modeling-user-groups",level:3},{value:" concepts",id:"-concepts",level:3},{value:"Step by step",id:"step-by-step",level:2},{value:"01. Create parent relations in document",id:"01-create-parent-relations-in-document",level:3},{value:"02. Add Parent Relationship Tuples",id:"02-add-parent-relationship-tuples",level:3},{value:"03. Check that parent folders have permissions",id:"03-check-that-parent-folders-have-permissions",level:3},{value:"Advanced object to object relationships",id:"advanced-object-to-object-relationships",level:2},{value:"01. Create authorization model with object to object relationships",id:"01-create-authorization-model-with-object-to-object-relationships",level:3},{value:"02. Adding relationship tuples",id:"02-adding-relationship-tuples",level:3},{value:"03. Check to see if access is allowed without direct relationship",id:"03-check-to-see-if-access-is-allowed-without-direct-relationship",level:3},{value:"04. Disassociating plan from feature",id:"04-disassociating-plan-from-feature",level:3},{value:"Related Sections",id:"related-sections",level:2}];function h(e){const t={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",strong:"strong",ul:"ul",...(0,o.R)(),...e.components},{Details:i}=t;return i||function(e,t){throw new Error("Expected "+(t?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"object-to-object-relationships",children:"Object to Object Relationships"})}),"\n",(0,n.jsx)(a.ZE,{}),"\n",(0,n.jsxs)(t.p,{children:["In this guide you'll learn how to model your application with ",(0,n.jsx)(a.OK,{section:"what-is-an-object",linkName:"objects"})," that are not specifically tied to a user. For example, a ",(0,n.jsx)(t.code,{children:"folder"})," is a ",(0,n.jsx)(t.code,{children:"parent"})," of a ",(0,n.jsx)(t.code,{children:"document"}),"."]}),"\n",(0,n.jsxs)(a.u6,{title:"When to use",appearance:"filled",children:[(0,n.jsxs)(t.p,{children:["This design pattern is helpful in the case where there are relationships between different objects. With ",(0,n.jsx)(a.bU,{format:a.Ed.LongForm}),", so long as both objects are in a type defined in the ",(0,n.jsx)(a.OK,{section:"what-is-an-authorization-model",linkName:"authorization model"}),", relationship tuples can be added to indicate a relationship between them."]}),(0,n.jsx)(t.p,{children:"For example:"}),(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"communities"})," can contain ",(0,n.jsx)(t.code,{children:"channels"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"channels"})," can contain ",(0,n.jsx)(t.code,{children:"posts"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"channels"})," can contain ",(0,n.jsx)(t.code,{children:"threads"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"threads"})," can contain ",(0,n.jsx)(t.code,{children:"posts"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"bookshelf"})," can have ",(0,n.jsx)(t.code,{children:"books"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"trips"})," can have ",(0,n.jsx)(t.code,{children:"bookings"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"account"})," can contain ",(0,n.jsx)(t.code,{children:"transactions"})]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.code,{children:"buildings"})," can have ",(0,n.jsx)(t.code,{children:"doors"})]}),"\n"]})]}),"\n",(0,n.jsx)(t.h2,{id:"before-you-start",children:"Before you start"}),"\n",(0,n.jsxs)(t.p,{children:["To better follow this guide, make sure you're familiar with some ",(0,n.jsx)(a.OK,{})," and know how to develop the things listed below."]}),"\n",(0,n.jsxs)(i,{children:[(0,n.jsx)("summary",{children:(0,n.jsxs)(t.p,{children:["You will start with the ",(0,n.jsx)(t.em,{children:(0,n.jsx)(a.OK,{section:"what-is-an-authorization-model",linkName:"authorization model"})})," below, it represents a ",(0,n.jsx)(t.code,{children:"document"})," ",(0,n.jsx)(t.em,{children:(0,n.jsx)(a.OK,{section:"what-is-a-type",linkName:"type"})})," that can have users ",(0,n.jsx)(t.strong,{children:(0,n.jsx)(a.OK,{section:"what-is-a-relation",linkName:"related"})})," as ",(0,n.jsx)(t.code,{children:"editor"}),", and ",(0,n.jsx)(t.code,{children:"folder"})," type that can have users related as ",(0,n.jsx)(t.code,{children:"viewer"}),"."]})}),(0,n.jsx)(a.pB,{configuration:{schema_version:"1.1",type_definitions:[{type:"user"},{type:"document",relations:{editor:{this:{}}},metadata:{relations:{editor:{directly_related_user_types:[{type:"user"}]}}}},{type:"folder",relations:{viewer:{this:{}}},metadata:{relations:{viewer:{directly_related_user_types:[{type:"user"}]}}}}]}}),(0,n.jsx)("hr",{}),(0,n.jsx)(t.p,{children:"In addition, you will need to know the following:"}),(0,n.jsx)(t.h3,{id:"modeling-user-groups",children:"Modeling user groups"}),(0,n.jsxs)(t.p,{children:["You need to know how to add users to groups and grant groups access to resources. ",(0,n.jsx)(t.a,{href:"/pr-preview/pr-921/docs/modeling/user-groups",children:"Learn more \u2192"})]}),(0,n.jsxs)(t.h3,{id:"-concepts",children:[(0,n.jsx)(a.bU,{format:a.Ed.ShortForm})," concepts"]}),(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:["A ",(0,n.jsx)(a.OK,{section:"what-is-a-type",linkName:"Type"}),": a class of objects that have similar characteristics"]}),"\n",(0,n.jsxs)(t.li,{children:["A ",(0,n.jsx)(a.OK,{section:"what-is-a-user",linkName:"User"}),": an entity in the system that can be related to an object"]}),"\n",(0,n.jsxs)(t.li,{children:["A ",(0,n.jsx)(a.OK,{section:"what-is-a-relation",linkName:"Relation"}),": is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system"]}),"\n",(0,n.jsxs)(t.li,{children:["An ",(0,n.jsx)(a.OK,{section:"what-is-an-object",linkName:"Object"}),": represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model"]}),"\n",(0,n.jsxs)(t.li,{children:["A ",(0,n.jsx)(a.OK,{section:"what-is-a-relationship-tuple",linkName:"Relationship Tuple"}),": a grouping consisting of a user, a relation and an object stored in ",(0,n.jsx)(a.bU,{format:a.Ed.ShortForm})]}),"\n"]})]}),"\n",(0,n.jsx)(a.QF,{}),"\n",(0,n.jsx)(t.h2,{id:"step-by-step",children:"Step by step"}),"\n",(0,n.jsx)(t.h3,{id:"01-create-parent-relations-in-document",children:"01. Create parent relations in document"}),"\n",(0,n.jsxs)(t.p,{children:["To represent that a ",(0,n.jsx)(t.code,{children:"folder"})," can be a ",(0,n.jsx)(t.code,{children:"parent"})," of a ",(0,n.jsx)(t.code,{children:"document"}),", we first need to modify our ",(0,n.jsx)(t.code,{children:"document"})," ",(0,n.jsx)(a.OK,{section:"what-is-a-type-definition",linkName:"type definition"})," to allow a ",(0,n.jsx)(t.code,{children:"parent"})," ",(0,n.jsx)(a.OK,{section:"what-is-a-relation",linkName:"relation"}),"."]}),"\n",(0,n.jsx)(a.pB,{configuration:{schema_version:"1.1",type_definitions:[{type:"user"},{type:"document",relations:{parent:{this:{}},editor:{this:{}}},metadata:{relations:{parent:{directly_related_user_types:[{type:"folder"}]},editor:{directly_related_user_types:[{type:"user"}]}}}},{type:"folder",relations:{viewer:{this:{}}},metadata:{relations:{viewer:{directly_related_user_types:[{type:"user"}]}}}}]}}),"\n",(0,n.jsx)(t.h3,{id:"02-add-parent-relationship-tuples",children:"02. Add Parent Relationship Tuples"}),"\n",(0,n.jsxs)(t.p,{children:["Once the type definition is updated, we can now create the ",(0,n.jsx)(a.OK,{section:"what-is-a-relationship",linkName:"relationship"})," between a ",(0,n.jsx)(t.code,{children:"folder"})," as a ",(0,n.jsx)(t.code,{children:"parent"})," of a ",(0,n.jsx)(t.code,{children:"document"}),". To do this, we will create a new ",(0,n.jsx)(t.strong,{children:(0,n.jsx)(a.OK,{section:"what-is-a-relationship-tuple",linkName:"relationship tuple"})})," that describes: ",(0,n.jsxs)(t.strong,{children:["folder",":budgets"]})," is a ",(0,n.jsx)(t.code,{children:"parent"})," of ",(0,n.jsxs)(t.strong,{children:["document",":may_budget",".doc"]}),". In ",(0,n.jsx)(a.bU,{format:a.Ed.LongForm}),", ",(0,n.jsx)(a.OK,{section:"what-is-a-user",linkName:"users"})," in the relationship tuples can not only be IDs, but also other objects in the form of ",(0,n.jsx)(t.code,{children:"type:object_id"}),"."]}),"\n",(0,n.jsx)(a.dp,{relationshipTuples:[{_description:"The user in this case is another object where the type is `folder` and the object_id is `budgets`",user:"folder:budgets",relation:"parent",object:"document:may_budget.doc"}]}),"\n",(0,n.jsx)(t.h3,{id:"03-check-that-parent-folders-have-permissions",children:"03. Check that parent folders have permissions"}),"\n",(0,n.jsxs)(t.p,{children:["Once that relationship tuple is added to ",(0,n.jsx)(a.bU,{format:a.Ed.ShortForm}),", we can ",(0,n.jsx)(a.OK,{section:"what-is-a-check-request",linkName:"check"})," if the relationship is valid by asking the following: ",(0,n.jsxs)(t.strong,{children:['"is folder',":budgets"," a parent of document",":may_budget",'.doc?"']})]}),"\n",(0,n.jsx)(a.ou,{user:"folder:budgets",relation:"parent",object:"document:may_budget.doc",allowed:!0}),"\n",(0,n.jsxs)(t.p,{children:["It is important to note that the current authorization model does not imply inheritance of permissions. Even though ",(0,n.jsxs)(t.strong,{children:["folder",":budgets"]})," is a ",(0,n.jsx)(t.code,{children:"parent"})," of ",(0,n.jsxs)(t.strong,{children:["document",":may_budget",".doc"]}),", ",(0,n.jsxs)(t.strong,{children:["it does not inherit the ",(0,n.jsx)(t.code,{children:"editor"})," relation from ",(0,n.jsx)(t.code,{children:"parent"})," to ",(0,n.jsx)(t.code,{children:"document"}),"."]})," Meaning ",(0,n.jsx)(t.code,{children:"editors"})," on ",(0,n.jsxs)(t.strong,{children:["folder",":budgets"]})," are not ",(0,n.jsx)(t.code,{children:"editors"})," on ",(0,n.jsxs)(t.strong,{children:["document",":may_budget",".doc"]}),". Further configuration changes are needed to indicate that and will be tackled in a later guide."]}),"\n",(0,n.jsx)(t.admonition,{type:"caution",children:(0,n.jsxs)(t.p,{children:["When creating relationship tuples for ",(0,n.jsx)(a.bU,{format:a.Ed.ShortForm})," make sure to use unique ids for each object and user within your application domain. We are using first names and simple ids to just illustrate an easy-to-follow example."]})}),"\n",(0,n.jsx)(t.h2,{id:"advanced-object-to-object-relationships",children:"Advanced object to object relationships"}),"\n",(0,n.jsxs)(t.p,{children:["Object to object can be used for more advanced use case, such as ",(0,n.jsx)(t.a,{href:"/pr-preview/pr-921/docs/modeling/advanced/entitlements",children:"entitlements"}),". An example use case is to allow subscribers to be entitled to different plans."]}),"\n",(0,n.jsx)(t.h3,{id:"01-create-authorization-model-with-object-to-object-relationships",children:"01. Create authorization model with object to object relationships"}),"\n",(0,n.jsxs)(t.p,{children:["To do this, the authorization model will have two ",(0,n.jsx)(a.OK,{section:"what-is-a-type",linkName:"types"})," - feature and plan."]}),"\n",(0,n.jsx)(a.pB,{configuration:{schema_version:"1.1",type_definitions:[{type:"user"},{type:"feature",relations:{associated_plan:{this:{}},access:{union:{child:[{this:{}},{tupleToUserset:{tupleset:{relation:"associated_plan"},computedUserset:{relation:"subscriber_member"}}}]}}},metadata:{relations:{associated_plan:{directly_related_user_types:[{type:"plan"}]},access:{directly_related_user_types:[{type:"user"}]}}}},{type:"plan",relations:{subscriber_member:{this:{}}},metadata:{relations:{subscriber_member:{directly_related_user_types:[{type:"user"}]}}}}]}}),"\n",(0,n.jsxs)(t.p,{children:["Type ",(0,n.jsx)(t.code,{children:"feature"})," has two relations, associated_plan and access. Relation ",(0,n.jsx)(t.code,{children:"associated_plan"})," allows associating plans with features while ",(0,n.jsx)(t.code,{children:"access"})," defines who can access the feature. In our case, the access can be achieved either from"]}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(a.OK,{section:"what-are-direct-and-implied-relationships",linkName:"direct relationship"})," via ",(0,n.jsx)(t.a,{href:"/pr-preview/pr-921/docs/configuration-language#direct-relationship-type-restrictions",children:"direct relationship type restrictions"}),".\nor ",(0,n.jsx)(t.code,{children:"this"})]}),"\n",(0,n.jsx)(t.li,{children:"object to object relationship where a user can access because it is a subscriber_member of a particular plan AND that plan is associated with the feature."}),"\n"]}),"\n",(0,n.jsxs)(t.p,{children:["Here, we define ",(0,n.jsx)(t.code,{children:"plan"})," as the user of object ",(0,n.jsx)(t.code,{children:"feature"})," with relationship ",(0,n.jsx)(t.code,{children:"associated_plan"})," rather than defining ",(0,n.jsx)(t.code,{children:"feature"})," as the user of object ",(0,n.jsx)(t.code,{children:"plan"})," with relationship ",(0,n.jsx)(t.code,{children:"feature"}),". The reason we choose the former is that we want to describe our system in the following ",(0,n.jsx)(t.a,{href:"/pr-preview/pr-921/docs/modeling/getting-started#write-it-in-plain-language",children:"plain language"}),":"]}),"\n",(0,n.jsx)(a.u6,{monoFontChildren:!0,appearance:"filled",children:(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsx)(t.li,{children:"A user can access a feature in a plan if they are a subscriber member of a plan that is the associated plan of a feature."}),"\n"]})}),"\n",(0,n.jsx)(t.p,{children:"This will give us a flow of user->organization->plan->feature and allows us to answer the question of whether user can access a feature rather than whether user is subscriber of a plan."}),"\n",(0,n.jsx)(t.h3,{id:"02-adding-relationship-tuples",children:"02. Adding relationship tuples"}),"\n",(0,n.jsx)(t.p,{children:"To realize the relationship, we will need to add the following relationship tuples."}),"\n",(0,n.jsx)(a.dp,{relationshipTuples:[{_description:"make anne as subscriber_member for plan:advanced",user:"user:anne",relation:"subscriber_member",object:"plan:advanced"},{_description:"The advanced plan is associated with the data preview feature",user:"plan:advanced",relation:"associated_plan",object:"feature:data_preview"}]}),"\n",(0,n.jsx)(t.h3,{id:"03-check-to-see-if-access-is-allowed-without-direct-relationship",children:"03. Check to see if access is allowed without direct relationship"}),"\n",(0,n.jsx)(t.p,{children:"To validate that the authorization model and relationship tuples are correct, we can ask the question:"}),"\n",(0,n.jsx)(a.ou,{user:"user:anne",relation:"access",object:"feature:data_preview",allowed:!0}),"\n",(0,n.jsxs)(t.p,{children:["We see that ",(0,n.jsx)(t.code,{children:"anne"})," is allowed to ",(0,n.jsx)(t.code,{children:"access"})," ",(0,n.jsx)(t.code,{children:"feature:data_preview"})," without requiring direct relationship."]}),"\n",(0,n.jsx)(t.h3,{id:"04-disassociating-plan-from-feature",children:"04. Disassociating plan from feature"}),"\n",(0,n.jsxs)(t.p,{children:["At any point in time, ",(0,n.jsx)(t.code,{children:"plan:advanced"})," may be disassociated from ",(0,n.jsx)(t.code,{children:"feature:data_preview"}),"."]}),"\n",(0,n.jsx)(a.dp,{deleteRelationshipTuples:[{_description:"Remove advanced plan from data preview feature",user:"plan:advanced",relation:"associated_plan",object:"feature:data_preview"}]}),"\n",(0,n.jsxs)(t.p,{children:["When this is the case, ",(0,n.jsx)(t.code,{children:"anne"})," will no longer have ",(0,n.jsx)(t.code,{children:"access"})," to ",(0,n.jsx)(t.code,{children:"feature:data_preview"})," even though she is still a ",(0,n.jsx)(t.code,{children:"subscriber_member"})," of ",(0,n.jsx)(t.code,{children:"plan:advanced"}),"."]}),"\n",(0,n.jsx)(a.ou,{user:"user:anne",relation:"access",object:"feature:data_preview",allowed:!1}),"\n",(0,n.jsx)(a.ou,{user:"user:anne",relation:"subscriber_member",object:"plan:advanced",allowed:!0}),"\n",(0,n.jsx)(t.h2,{id:"related-sections",children:"Related Sections"}),"\n",(0,n.jsx)(a.XQ,{description:"Check the following sections for more on how object-to-object relationships can be used.",relatedLinks:[{title:"Advanced Modeling Patterns: Entitlements",description:"Learn how to model entitlement access patterns.",link:"../advanced/entitlements",id:"../advanced/entitlements.mdx"},{title:"Modeling Parent-Child Relationships",description:"Learn how to model parent and child relationships.",link:"../parent-child",id:"../parent-child.mdx"},{title:"Modeling User Groups",description:"Learn how to model user groups.",link:"../user-groups",id:"../user-groups.mdx"}]})]})}function p(e={}){const{wrapper:t}={...(0,o.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(h,{...e})}):h(e)}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/17896441.8d54381f.js b/pr-preview/pr-921/assets/js/17896441.8d54381f.js new file mode 100644 index 000000000..f248a2776 --- /dev/null +++ b/pr-preview/pr-921/assets/js/17896441.8d54381f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[8401],{92047:(e,r,t)=>{t.d(r,{A:()=>i});var a=t(96540),n=t(41622),s=t(74848);function i(e){const r=a.Children.toArray(e.children),t=r.find((e=>a.isValidElement(e)&&"summary"===e.type)),i=(0,s.jsx)(s.Fragment,{children:r.filter((e=>e!==t))});return(0,s.jsx)(n.A,{...e,onClickCapture:e=>{"A"===e.target.tagName&&e.target.closest("summary")&&e.stopPropagation()},summary:t,children:i})}}}]); \ No newline at end of file diff --git a/pr-preview/pr-921/assets/js/18e2b0e6.891a9ad9.js b/pr-preview/pr-921/assets/js/18e2b0e6.891a9ad9.js new file mode 100644 index 000000000..808a1d385 --- /dev/null +++ b/pr-preview/pr-921/assets/js/18e2b0e6.891a9ad9.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkopenfga_dev=self.webpackChunkopenfga_dev||[]).push([[394],{36239:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>s,default:()=>g,frontMatter:()=>r,metadata:()=>i,toc:()=>d});const i=JSON.parse('{"id":"content/getting-started/setup-openfga/playground","title":"Using the OpenFGA Playground","description":"Setting up an OpenFGA server","source":"@site/docs/content/getting-started/setup-openfga/playground.mdx","sourceDirName":"content/getting-started/setup-openfga","slug":"/getting-started/setup-openfga/playground","permalink":"/pr-preview/pr-921/docs/getting-started/setup-openfga/playground","draft":false,"unlisted":false,"editUrl":"https://github.com/openfga/openfga.dev/edit/main/docs/content/getting-started/setup-openfga/playground.mdx","tags":[],"version":"current","sidebarPosition":4,"frontMatter":{"title":"Using the OpenFGA Playground","description":"Setting up an OpenFGA server","sidebar_position":4,"slug":"/getting-started/setup-openfga/playground"},"sidebar":"docs","previous":{"title":"\ud83d\udee1\ufe0fAccess Control","permalink":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control"},"next":{"title":"Install SDK Client","permalink":"/pr-preview/pr-921/docs/getting-started/install-sdk"}}');var o=t(74848),a=t(28453);const r={title:"Using the OpenFGA Playground",description:"Setting up an OpenFGA server",sidebar_position:4,slug:"/getting-started/setup-openfga/playground"},s="Using the OpenFGA Playground",l={},d=[{value:"Running the Playground in a different port",id:"running-the-playground-in-a-different-port",level:2},{value:"Disabling the Playground",id:"disabling-the-playground",level:2}];function p(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,a.R)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.header,{children:(0,o.jsx)(n.h1,{id:"using-the-openfga-playground",children:"Using the OpenFGA Playground"})}),"\n",(0,o.jsx)(n.p,{children:"The Playground facilitates rapid development by allowing you to visualize and model your application's authorization models and manage relationship tuples with a locally running OpenFGA instance."}),"\n",(0,o.jsxs)(n.p,{children:["It is enabled on port 3000 by default and accessible at ",(0,o.jsx)(n.a,{href:"http://localhost:3000/playground",children:"http://localhost:3000/playground"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"The Playground is designed for early prototyping and learning. It has several limitations:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["It works by embedding the public ",(0,o.jsx)(n.a,{href:"https://play.fga.dev",children:"Playground website"})," in an ",(0,o.jsx)(n.code,{children:" +

Exercises for you

+
+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/advanced/slack.html.html b/pr-preview/pr-921/docs/modeling/advanced/slack.html.html new file mode 100644 index 000000000..ea9dcf0dc --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/advanced/slack.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/blocklists.html b/pr-preview/pr-921/docs/modeling/blocklists.html new file mode 100644 index 000000000..8e04a3844 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/blocklists.html @@ -0,0 +1,80 @@ + + + + + +Blocklists | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Blocklists

+ +

In this guide you'll see how to model preventing users from accessing objects using OpenFGA. For example, blocking users from accessing a document, even if it has been already shared with them.

+
When to use

Exclusion is useful while building applications. You may need to support access patterns like granting access to some users, but excluding specific people or groups, similar to how users can block others from following them on social media, or prevent them from sharing documents on Google Drive.

This is useful when:

    +
  • Implementing the "blocking" feature, such as the profile blocking commonly present on social media platforms (e.g. Instagram and Twitter).
  • +
  • Reduce a user's access if they are part of a particular group (e.g. restricting access to members who are also guests, or restricting access to users in a certain locality).
  • +
+

Before you start

+

Before you start this guide, make sure you're familiar with some OpenFGA Concepts and know how to develop the things listed below.

+

You will start with the authorization model below, it represents a document type that can have users related as editor, and team type that can have users related as member.

Let us also assume that we have a document called "planning", shared for editing within the product team (comprised of becky and carl).

model
schema 1.1

type user

type document
relations
define editor: [user, team#member]

type team
relations
define member: [user]

The current state of the system is represented by the following relationship tuples being in the system already:

[// Members of the product team can edit the planning document
{
"_description": "Members of the product team can edit the planning document",
"user": "team:product#member",
"relation": "editor",
"object": "document:planning"
}// Becky is a member of the product team
{
"_description": "Becky is a member of the product team",
"user": "user:becky",
"relation": "member",
"object": "team:product"
}// Carl is a member of the product team
{
"_description": "Carl is a member of the product team",
"user": "user:carl",
"relation": "member",
"object": "team:product"
}]

In addition, you will need to know the following:

Modeling user groups

You need to know how to add users to groups and grant groups access to resources. Learn more →

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • Exclusion Operator: the exclusion operator can be used to exclude certain usersets from being related to an object
  • +
+ +

Step by step

+

With the above authorization model and relationship tuples, OpenFGA will correctly respond with {"allowed":true} when check is called to see if Carl and Becky can edit this document.

+

We can verify that by issuing two check requests:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:becky',
relation: 'editor',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:carl',
relation: 'editor',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

We want to share a document with the product team and also have the ability to deny certain users access, even if they have the document shared with them already. We can verify this by blocking Carl (who we have seen already has edit access) from editing the document.

+

In order to do that, we need to:

+
    +
  1. Modify our model to allow indicating that users can be blocked from accessing a document
  2. +
  3. Modify our model to indicate that users who are blocked can no longer edit the document
  4. +
  5. Verify that our solution works:
  6. +
+

a. Indicate that Carl is blocked from the planning document

+

b. Carl (now blocked) can no longer edit the document

+

c. Becky still has edit access

+

01. Modify our model so users can be blocked from accessing a document

+

To allow users to be "blocked" from accessing a document, we first need to allow this relation. We'll update our store model to add a blocked relation to the document type.

+

The authorization model becomes this:

+
model
schema 1.1

type user

type document
relations
define blocked: [user]
define editor: [user, team#member]

type team
relations
define member: [user]
+

Now we can add relationship tuples indicating that a certain user is blocked from editing a document.

+

02. Modify our model so users who are blocked can no longer edit the document

+

Now that we can mark users as blocked from editing documents, we need to support denying the editor relationship when a user is blocked. We do that by modifying the relation definition of editor, and making use of the exclusion operator to exclude the set of blocked users, as we can see here:

+
model
schema 1.1

type user

type document
relations
define blocked: [user]
define editor: [user, team#member] but not blocked

type team
relations
define member: [user]
+

03. Verify our solution works

+

To check if our new model works, we'll add a relationship tuple with Carl as blocked from document:planning and then verify that Carl no longer has editor access to that document.

+

a. Indicate that Carl is blocked from the planning document

+

With our modified authorization model, we can indicate that Carl is blocked by adding this relationship tuple.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Carl is blocked from editing the planning document
{"_description":"Carl is blocked from editing the planning document","user":"user:carl","relation":"blocked","object":"document:planning"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

b. Carl (now blocked) can no longer edit the document

+

We have modified the authorization model and added relationship tuples to indicate that Carl is blocked. Now let's make sure our solution works as expected.

+

To check if Carl still has access to the document, we can issue a check request with Carl as the user.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:carl',
relation: 'editor',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

The response is false, so our solution is working as expected.

+

c. Becky still has edit access

+

To check if Becky still has access to the document, we'll issue another check request with Becky as the user.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:becky',
relation: 'editor',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

The response is true, indicating our model change did not inadvertently deny access for users who have access but are not blocked.

+
caution

When creating tuples for OpenFGA make sure to use unique ids for each object and user within your application domain. We are using first names and human-readable identifiers to make this task easier to read.

+ +
Modeling: Getting Started

Learn about how to get started with modeling.

Configuration Language

Learn about OpenFGA Configuration Language.

Public Access

Learn about model public access.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/blocklists.html.html b/pr-preview/pr-921/docs/modeling/blocklists.html.html new file mode 100644 index 000000000..23d5e87c4 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/blocklists.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks.html b/pr-preview/pr-921/docs/modeling/building-blocks.html new file mode 100644 index 000000000..cee30849c --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks.html @@ -0,0 +1,27 @@ + + + + + +Building Blocks | OpenFGA + + + + + + + + + + + + + + +
Skip to main content
+

This section has guides that on the building blocks of authorization model.

+
When to use

The content in this section is useful:

  • If you are starting with OpenFGA and want to learn the building blocks that can be used to build any model.
+

Content

+
Direct Relationships

Learn to model relationships that may or may not be assigned directly to individual users.

Concentric Relationships

Learn to model nested relationships in your application.

Object to Object Relationships

Learn to model your application with objects that are not specifically tied to a user.

Usersets

Learn to model your application by assigning relationships to groups of users.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks.html.html b/pr-preview/pr-921/docs/modeling/building-blocks.html.html new file mode 100644 index 000000000..9f5ee000b --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships.html b/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships.html new file mode 100644 index 000000000..1648ae082 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships.html @@ -0,0 +1,59 @@ + + + + + +Concentric Relationships | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Concentric Relationships

+ +

In this short guide, you'll learn how to represent a concentric relationships.

+

For example, if you want to have all editors of a document also be viewers of said document.

+
When to use

Concentric relations make the most sense when your domain logic has nested relations, where one having relation implies having another relation.

For example:

    +
  • all editors are viewers
  • +
  • all managers are members
  • +
  • all device_managers are device_renamers
  • +

This allows you to only create a single relationship tuple rather than creating n relationship tuples for each relation.

+

Before You Start

+

To better understand this guide, you should be familiar with some OpenFGA Concepts and know how to develop the things listed below.

+

You will start with the authorization model below, it represents a document type that can have users related as editor and viewer.

Let us also assume that we have a document called "meeting_notes.doc" and bob is assigned as editor to this document.

model
schema 1.1

type user

type document
relations
define viewer: [user]
define editor: [user]

The current state of the system is represented by the following relationship tuples being in the system already:

[{
"user": "user:bob",
"relation": "editor",
"object": "document:meeting_notes.doc"
}]

In addition, you will need to know the following:

Modeling User Groups

You need to know how to add users to groups and grant groups access to resources. Learn more →

OpenFGA concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
+ +

Step by step

+

With the current type definition, there isn't a way to indicate that all editors of a certain document are also automatically viewers of that document. So for a certain user, in order to indicate that they can both edit and view a certain document, two relationship tuples need to be created (one for editor, and another for viewer).

+

01. Modify our model to imply editor as viewer

+

Instead of creating two relationship tuples, we can leverage concentric relationships by defining editors are viewers.

+

Our authorization model becomes the following:

+
model
schema 1.1

type user

type document
relations
define viewer: [user] or editor
define editor: [user]
+
info

viewer of a document are any of:

    +
  1. users that are directly assigned as viewer
  2. +
  3. users that have editor of the document
  4. +
+

With this authorization model change, having an editor relationship with a certain document implies having a viewer relationship with that same document.

+

02. Check that editors are viewers

+

Since we had a relationship tuple that indicates that bob is an editor of document:meeting_notes.doc, this means bob is now implicitly a viewer of document:meeting_notes.doc. +If we now check: is bob a viewer of document:meeting_notes.doc? we would get the following:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'viewer',
object: 'document:meeting_notes.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+
Note

When creating relationship tuples for OpenFGA make sure to use unique ids for each object and user within your application domain. We're using first names and simple ids to just illustrate an easy-to-follow example.

+ +
Modeling Google Drive

See how to indicate that editors are commenters and viewers in Google Drive.

Modeling GitHub

See how to indicate that repository admins are writers and readers in GitHub.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships.html.html b/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships.html.html new file mode 100644 index 000000000..794e2e215 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships.html b/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships.html new file mode 100644 index 000000000..ab1eb387e --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships.html @@ -0,0 +1,109 @@ + + + + + +Direct Relationships | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Direct Relationships

+ +

In this guide you'll learn how to model relationships that may or may not be assigned directly to individual users.

+
When to use

Disabling direct relationships for a certain relation on an objects are useful especially in cases where you are trying to model some permissions that are not usually granted individually to a user.

This is useful when:

    +
  • For security reason, not permitting permissions assigned directly to individuals without associating roles
  • +
+

Before you start

+

To better understand this guide, you should be familiar with some OpenFGA Concepts and know how to develop the things listed below.

+

You will need to know the following:

    +
  • Direct Access
  • +
  • OpenFGA Concepts
  • +

Direct access

You need to know how to create an authorization model and create a relationship tuple to grant a user access to an object. Learn more →

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • Direct Relationship Type Restrictions: used in the context of the relation definition can be used to allow direct relationships to the objects of this type
  • +
+ +

What are direct relationships?

+

Direct relationships are relationships where a user has a relationship to an object that is not dependent on any other relationship they have with that object.

+

When checking for a relationship, a direct relationship exists if a relationship tuple is present in the system with the exact same object and relation that were in the query and where the user is one of:

+
    +
  • the same user ID as that in the query
  • +
  • type bound public access (<type>:*)
  • +
  • a set of users that contains the user ID present in the query
  • +
+

Enable or disable direct relationships

+

Direct relationships can be enabled for a specific relation on an object type by adding direct relationship type restrictions from that relation's definition. Likewise, they can be disabled by removing the direct relationship type restrictions.

+
model
schema 1.1

type user

type document
relations
define viewer: [user, user:*, team#member] or editor
define editor: [user, team#member]

type team
relations
define member: [user]
+
info

The authorization model describes two object types: document and team.

The document type definition has two relations, editor and viewer. Both relations allow a direct relationship; viewer also allows an indirect relationship through editor.

In the team type definition, there is a single member relation that only allows direct relationships.

+

How it affects your system

+

To illustrate the effect enabling or disabling direct relationships on a specific relation has, we'll investigate several situations.

+

1. With direct relationships enabled

+

Let us start with the authorization model we had above:

+
model
schema 1.1

type user

type document
relations
define viewer: [user, user:*, team#member] or editor
define editor: [user, team#member]

type team
relations
define member: [user]
+

Now choose the type of relation to see how it affects your system:

+

Assume you have a tuple that states that Anne is a viewer of document:planning

[{
"user": "user:anne",
"relation": "viewer",
"object": "document:planning"
}]

Now if we do a check request to see if Anne can view the planning document, we will get a response of {"allowed": true}.

Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'viewer',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true

This is because:

    +
  • There is a relationship tuple specifying that Anne has a viewer relationship with document:planning.
  • +
  • Direct relationships are allowed in the viewer relation definition in the document type definition.
  • +
+

2. With direct relationships disabled

+

In this section, we will investigate the effect of disabling direct relationships on the document's viewer relation.

+
model
schema 1.1

type user

type document
relations
define viewer: editor
define editor: [user, team#member]

type team
relations
define member: [user]
+
info

Notice that in this updated authorization model, the direct relationship keyword has been removed from the document's viewer relation definition.

+

Now choose the type of relation to see how it affects your system:

+

Assume you have a tuple that states that Fred is a viewer of document:planning

[{
"user": "user:fred",
"relation": "viewer",
"object": "document:planning"
}]

Now if we do a check request to see if Fred can view the planning document, we will get a response of {"allowed": false}.

Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:fred',
relation: 'viewer',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false

This is because:

    +
  • Even though there is a relationship tuple specifying that Fred has a viewer relationship with document:planning.
  • +
  • Direct relationships are NOT allowed in the viewer relation definition in the document type definition.
  • +
+ +
Modeling Roles and Permissions

Learn how to remove the direct relationship to indicate nonassignable permissions.

Modeling for IoT

See how Roles and Permissions can be used in an IoT use-case.

Modeling Entitlements

Take a look at the access relation in the feature type for an example of removing the direct relationship

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships.html.html b/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships.html.html new file mode 100644 index 000000000..00b666e21 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships.html b/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships.html new file mode 100644 index 000000000..0a5b1c659 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships.html @@ -0,0 +1,88 @@ + + + + + +Object to Object Relationships | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Object to Object Relationships

+ +

In this guide you'll learn how to model your application with objects that are not specifically tied to a user. For example, a folder is a parent of a document.

+
When to use

This design pattern is helpful in the case where there are relationships between different objects. With OpenFGA, so long as both objects are in a type defined in the authorization model, relationship tuples can be added to indicate a relationship between them.

For example:

    +
  • communities can contain channels
  • +
  • channels can contain posts
  • +
  • channels can contain threads
  • +
  • threads can contain posts
  • +
  • bookshelf can have books
  • +
  • trips can have bookings
  • +
  • account can contain transactions
  • +
  • buildings can have doors
  • +
+

Before you start

+

To better follow this guide, make sure you're familiar with some OpenFGA Concepts and know how to develop the things listed below.

+

You will start with the authorization model below, it represents a document type that can have users related as editor, and folder type that can have users related as viewer.

model
schema 1.1

type user

type document
relations
define editor: [user]

type folder
relations
define viewer: [user]

In addition, you will need to know the following:

Modeling user groups

You need to know how to add users to groups and grant groups access to resources. Learn more →

OpenFGA concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
+ +

Step by step

+

01. Create parent relations in document

+

To represent that a folder can be a parent of a document, we first need to modify our document type definition to allow a parent relation.

+
model
schema 1.1

type user

type document
relations
define parent: [folder]
define editor: [user]

type folder
relations
define viewer: [user]
+

02. Add Parent Relationship Tuples

+

Once the type definition is updated, we can now create the relationship between a folder as a parent of a document. To do this, we will create a new relationship tuple that describes: folder:budgets is a parent of document:may_budget.doc. In OpenFGA, users in the relationship tuples can not only be IDs, but also other objects in the form of type:object_id.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// The user in this case is another object where the type is `folder` and the object_id is `budgets`
{"_description":"The user in this case is another object where the type is `folder` and the object_id is `budgets`","user":"folder:budgets","relation":"parent","object":"document:may_budget.doc"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

03. Check that parent folders have permissions

+

Once that relationship tuple is added to OpenFGA, we can check if the relationship is valid by asking the following: "is folder:budgets a parent of document:may_budget.doc?"

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'folder:budgets',
relation: 'parent',
object: 'document:may_budget.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

It is important to note that the current authorization model does not imply inheritance of permissions. Even though folder:budgets is a parent of document:may_budget.doc, it does not inherit the editor relation from parent to document. Meaning editors on folder:budgets are not editors on document:may_budget.doc. Further configuration changes are needed to indicate that and will be tackled in a later guide.

+
caution

When creating relationship tuples for OpenFGA make sure to use unique ids for each object and user within your application domain. We are using first names and simple ids to just illustrate an easy-to-follow example.

+

Advanced object to object relationships

+

Object to object can be used for more advanced use case, such as entitlements. An example use case is to allow subscribers to be entitled to different plans.

+

01. Create authorization model with object to object relationships

+

To do this, the authorization model will have two types - feature and plan.

+
model
schema 1.1

type user

type feature
relations
define associated_plan: [plan]
define access: [user] or subscriber_member from associated_plan

type plan
relations
define subscriber_member: [user]
+

Type feature has two relations, associated_plan and access. Relation associated_plan allows associating plans with features while access defines who can access the feature. In our case, the access can be achieved either from

+ +

Here, we define plan as the user of object feature with relationship associated_plan rather than defining feature as the user of object plan with relationship feature. The reason we choose the former is that we want to describe our system in the following plain language:

+
    +
  • A user can access a feature in a plan if they are a subscriber member of a plan that is the associated plan of a feature.
  • +
+

This will give us a flow of user->organization->plan->feature and allows us to answer the question of whether user can access a feature rather than whether user is subscriber of a plan.

+

02. Adding relationship tuples

+

To realize the relationship, we will need to add the following relationship tuples.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// make anne as subscriber_member for plan:advanced
{"_description":"make anne as subscriber_member for plan:advanced","user":"user:anne","relation":"subscriber_member","object":"plan:advanced"},
// The advanced plan is associated with the data preview feature
{"_description":"The advanced plan is associated with the data preview feature","user":"plan:advanced","relation":"associated_plan","object":"feature:data_preview"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

03. Check to see if access is allowed without direct relationship

+

To validate that the authorization model and relationship tuples are correct, we can ask the question:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'access',
object: 'feature:data_preview',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

We see that anne is allowed to access feature:data_preview without requiring direct relationship.

+

04. Disassociating plan from feature

+

At any point in time, plan:advanced may be disassociated from feature:data_preview.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
deletes: [
// Remove advanced plan from data preview feature
{ user: 'plan:advanced', relation: 'associated_plan', object: 'feature:data_preview'}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

When this is the case, anne will no longer have access to feature:data_preview even though she is still a subscriber_member of plan:advanced.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'access',
object: 'feature:data_preview',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'subscriber_member',
object: 'plan:advanced',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+ +
Advanced Modeling Patterns: Entitlements

Learn how to model entitlement access patterns.

Modeling Parent-Child Relationships

Learn how to model parent and child relationships.

Modeling User Groups

Learn how to model user groups.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships.html.html b/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships.html.html new file mode 100644 index 000000000..4c89cf7a0 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/usersets.html b/pr-preview/pr-921/docs/modeling/building-blocks/usersets.html new file mode 100644 index 000000000..eb75ead7c --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/usersets.html @@ -0,0 +1,62 @@ + + + + + +Usersets | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Usersets

+ +

What is a userset?

+

A userset represents a set or collection of users.

+

Usersets can be used to indicate that a group of users in the system have a certain relation with an object. This can be used to assign permissions to groups of users rather than specific ones, allowing us to represent the permissions in our system using less tuples and granting us flexibility in granting or denying access in bulk.

+

In OpenFGA, usersets are represented via this notation: object#relation, where object is made up of a type and an object identifier. For example:

+
    +
  • company:xyz#employee represents all users that are related to company:xyz as employee
  • +
  • tweet:12345#viewer represents all users that are related to tweet:12345 as viewer
  • +
+

How do check requests work with usersets?

+

Imagine the following authorization model:

+
model
schema 1.1

type user

type org
relations
define member: [user]

type document
relations
define reader: [user, org#member]
+

Now let us assume that the store has the following tuples:

+
[// Userset "Members of the xyz org" can read the budget document
{
"_description": "Userset \"Members of the xyz org\" can read the budget document",
"user": "org:xyz#member",
"relation": "reader",
"object": "document:budget"
}// Anne is part of the userset "Members of the xyz org"
{
"_description": "Anne is part of the userset \"Members of the xyz org\"",
"user": "user:anne",
"relation": "member",
"object": "org:xyz"
}]
+

If we call the check API to see if user anne has a reader relationship with document:budget, OpenFGA will check whether anne is part of the userset that does have a reader relationship. Because she is part of that userset, the request will return true:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'reader',
object: 'document:budget',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

How do expand requests work with usersets?

+

Imagine the following authorization model:

+
model
schema 1.1

type user

type document
relations
define writer: [user, org#member]
define reader: [user, org#member] or writer
+

If we wanted to see which users and usersets have a reader relationship with document:budget, we can call the Expand API. The response will contain a userset tree where the leaf nodes are specific user IDs and usersets. For example:

+
{
"tree": {
"root": {
"type": "document:budget#reader",
"union": {
"nodes": [
{
"type": "document:budget#reader",
"leaf": {
"users": {
"users": ["user:bob"]
}
}
},
{
"type": "document:budget#reader",
"leaf": {
"computed": {
"userset": "document:budget#writer"
}
}
}
]
}
}
}
}
+

As you can see from the response above, with usersets we can express unions of user groups. We can also express intersections and exclusions.

+

Internals

+

Using the type definitions in the authorization model, some of the situations we can represent are:

+
    +
  • that a user is not in a set of users having a certain relation to an object, even if a relationship tuple exists in the system. See Disabling Direct Relationships
  • +
  • that a user has a certain relationship with an object if they are in the union, intersection or exclusion of usersets.
  • +
  • that a user being in a set of users having a certain relation to an object can result in them having another relation to the object. See Concentric Relationships
  • +
  • that the user being in a set of users having a certain relation to an object and that object is in a set of users having a certain relation to another object, can imply that the original user has a certain relationship to the final object. See Object-to-Object Relationships
  • +
+

When executing the Check API of the form check(user, relation, object), OpenFGA will perform the following steps:

+
    +
  1. In the authorization model, look up type and its relation. Start building a tree where the root node will be the definition of that relation, which can be a union, exclusion, or intersection of usersets, or it can be direct users.
  2. +
  3. Expand all the usersets involved into new nodes in the tree. This means recursively finding all the users that are members of the usersets. If there are direct relationships with users, create leaf nodes.
  4. +
  5. Check whether user is a leaf node in the tree. If the API finds one match, it will return immediately and will not expand the remaining nodes.
  6. +
+

Image showing the path  traverses to find if a user is in the userset related to an object

+ +
Managing Group Membership

How to add users to a userset

Managing Group Access

How to add permissions to a userset

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/building-blocks/usersets.html.html b/pr-preview/pr-921/docs/modeling/building-blocks/usersets.html.html new file mode 100644 index 000000000..bf75a3baa --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/building-blocks/usersets.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/conditions.html b/pr-preview/pr-921/docs/modeling/conditions.html new file mode 100644 index 000000000..8cbdfac7a --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/conditions.html @@ -0,0 +1,71 @@ + + + + + +Conditions | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Conditions

+

Overview

+

Conditions allow you to model more complex authorization modeling scenarios involving attributes and can be used to represent some Attribute-based Access Control (ABAC) policies. Take a look at the Conditions and Conditional Relationship Tuples concepts for a quick overview.

+

There are various use cases where Conditions can be helpful. These include, but are not limited to:

+ +

For more information and background context on why we added this feature, please see our blog post on Conditional Relationship Tuples for OpenFGA.

+

Defining conditions in models

+

For this example we'll use the following authorization model to demonstrate a temporal based access policy. Namely, a user can view a document if and only if they have been granted the viewer relationship AND their non-expired grant policy is met.

+
model
schema 1.1

type user

type document
relations
define viewer: [user with non_expired_grant]

condition non_expired_grant(current_time: timestamp, grant_time: timestamp, grant_duration: duration) {
current_time < grant_time + grant_duration
}
+
note

The type restriction for document#viewer requires that any user of type user that is written in the relationship tuple must be accompanied by the non_expired_grant condition. This is denoted by the user with non_expired_grant specification.

+

Write the model to the FGA store:

+

const { authorization_model_id: id } = await fgaClient.writeAuthorizationModel({
"schema_version": "1.1",
"type_definitions": [
{
"type": "user"
},
{
"type": "document",
"relations": {
"viewer": {
"this": {}
}
},
"metadata": {
"relations": {
"viewer": {
"directly_related_user_types": [
{
"type": "user",
"condition": "non_expired_grant"
}
]
}
}
}
}
],
"conditions": {
"non_expired_grant": {
"name": "non_expired_grant",
"expression": "current_time < grant_time + grant_duration",
"parameters": {
"current_time": {
"type_name": "TYPE_NAME_TIMESTAMP"
},
"grant_duration": {
"type_name": "TYPE_NAME_DURATION"
},
"grant_time": {
"type_name": "TYPE_NAME_TIMESTAMP"
}
}
}
}
});
// id = "01HVMMBCMGZNT3SED4Z17ECXCA"
+

Writing conditional relationship tuples

+

Using the model above, when we Write relationship tuples to the OpenFGA store, then any document#viewer relationship with user objects must be accompanied by the condition non_expired_grant because the type restriction requires it.

+

For example, we can give user:anne viewer access to document:1 for 10 minutes by writing the following relationship tuple:

+

await fgaClient.write({
writes: [
{"user":"user:anne","relation":"viewer","object":"document:1","condition":{"name":"non_expired_grant","context":{"grant_time":"2023-01-01T00:00:00Z","grant_duration":"10m"}}}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Queries with condition context

+

Now that we have written a Conditional Relationship Tuple, we can query OpenFGA using the Check API to see if user:anne has viewer access to document:1 under certain conditions/context. That is, user:anne should only have access if the current timestamp is less than the grant timestamp (e.g. the time which the tuple was written) plus the duration of the grant (10 minutes). If the current timestamp is less than, then you'll get a permissive decision. For example,

+

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'viewer',
object: 'document:1',
context: {"current_time":"2023-01-01T00:09:50Z"}
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

but if the current time is outside the grant window then you get a deny decision. For example,

+

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'viewer',
object: 'document:1',
context: {"current_time":"2023-01-01T00:10:01Z"}
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

Similarly, we can use the ListObjects API to return all of the documents that user:anne has viewer access given the current time. For example,

+
const response = await fgaClient.listObjects({
user: "user:anne",
relation: "viewer",
type: "document",
context:{"current_time":"2023-01-01T00:09:50Z"},
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA",
});
// response.objects = ["document:1"]
+

but if the current time is outside the grant window then we don't get the object in the response. For example,

+
const response = await fgaClient.listObjects({
user: "user:anne",
relation: "viewer",
type: "document",
context:{"current_time":"2023-01-01T00:10:01Z"},
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA",
});
// response.objects = []
+
note

When evaluating a condition at request time, the context written/persisted in the relationship tuple and the context provided at request time are merged together into a single evaluation context.

If you provide a context value in the request context that is also written/persisted in the relationship tuple, then the context values written in the relationship tuple take precedence. That is, the merge strategy is such that persisted context has higher precedence than request context.

+

Examples

+

For more examples take a look at our Sample Stores repository. There are various examples with ABAC models in that repository.

+

Supported parameter types

+

The following table enumerates the list of supported parameter types. The more formal list is defined in https://github.com/openfga/openfga/tree/main/internal/condition/types.

+

Note that some of the types support generics, these types are indicated with <T>.

+
Friendly Type NameType Name (Protobuf Enum)DescriptionExamples
intTYPE_NAME_INTA 64-bit signed integer value.-1
"-1"
uintTYPE_NAME_UINTA 64-bit unsigned integer value.1
"1"
doubleTYPE_NAME_DOUBLEA double-width floating point value, represented equivalently as a Go float64 value.

If the value is provided as a string we parse it with strconv.ParseFloat(s, 64). See strconv.ParseFloat for more info.
3.14159
-0.75
"1"
"-2.5"
boolTYPE_NAME_BOOLA boolean value.true
false

"true"
"false"
bytesTYPE_NAME_BYTESAn array of byte values specified as a byte string."bytestring"
stringTYPE_NAME_STRINGA string value."hello, world"
durationTYPE_NAME_DURATIONA value representing a duration of time specified using Go duration string format.

See time.Duration#ParseDuration
"120s"
"2m"
timestampTYPE_NAME_TIMESTAMPA timestamp value that follows the RFC3339 specification."2023-01-01T00:00:00Z"
anyTYPE_NAME_ANYA variant type which permits any value to be provided.{"x": 1}
"hello"
["a", "b"]
list<T>TYPE_NAME_LISTA list of values of generic type T.list<string> - ["a", "b", "c"]
list<int> - [-1, 1]
list<duration> - ["60s", "1m"]
map<T>TYPE_NAME_MAPA map whose keys are strings and whose values are values of generic type T.

Any map value must have string keys, only the value types can vary.
map<int> - {"x": -1, "y": 1}
map<string> - {"key": "value"}
ipaddressTYPE_NAME_IPADDRESSA custom value type specified as a string representation of an IP Address."192.168.0.1"
+

Limitations

+
    +
  • +

    The size of the condition context parameter that can be written alongside a relationship tuple is limited to 32KB in size.

    +
  • +
  • +

    The size of the condition context parameter for query requests (e.g. Check, ListObjects, etc.) is not explicitly limited, but the OpenFGA server has an overall request size limit of 512KB at this time.

    +
  • +
  • +

    We enforce a maximum Google CEL expression evaluation cost of 100 (by default) to protect the server from malicious conditions. The evaluation cost of a CEL expression is a function of the size the input that is being compared and the composition of the expression. For more general information please see the official Language Definition for Google CEL. If you hit these limits with practical use-cases, please reach out to the maintainer team and we can discuss.

    +
  • +
+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/conditions.html.html b/pr-preview/pr-921/docs/modeling/conditions.html.html new file mode 100644 index 000000000..ab48459f6 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/conditions.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization.html b/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization.html new file mode 100644 index 000000000..d1446f1f1 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization.html @@ -0,0 +1,171 @@ + + + + + +Contextual and Time-Based Authorization | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Contextual and Time-Based Authorization

+ +

This section explores some methods available to you to tackle some use-cases where the expected authorization check may depend on certain dynamic or contextual data (such as time, location, ip address, weather) that have not been written to the OpenFGA store.

+
When to use

Contextual Tuples should be used when modeling cases where a user's access to an object depends on the context of their request. For example:

    +
  • An employee’s ability to access a document when they are connected to the company VPN or the api call is originating from an internal IP address.
  • +
  • A support engineer is only able to access a user's account during office hours.
  • +
  • If a user belongs to multiple organizations, they are only able to access a resource if they set a specific organization in their current context.
  • +
+

Before you start

+

To follow this guide, you should be familiar with some OpenFGA Concepts.

+

OpenFGA concepts

+
    +
  • A Relation: Defined in the type definition of an authorization model, a relation is a string that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system.
  • +
  • A Check Request: is a call to the OpenFGA check endpoint that returns whether the user has a certain relationship with an object.
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • A Contextual Tuple: a tuple that can be added to a Check request, and only exists within the context of that particular request.
  • +
+

You also need to be familiar with:

+
    +
  • Modeling Object-to-Object Relationships: You need to know how to create relationships between objects and how that might affect a user's relationships to those objects. Learn more →
  • +
  • Modeling Multiple Restrictions: You need to know how to model requiring multiple authorizations before allowing users to perform certain actions. Learn more →
  • +
+ +

Scenario

+

For the scope of this guide, we are going to consider the following scenario.

+

Consider you are building the authorization model for WeBank Inc.

+

In order for an Account Manager at WeBank Inc. to be able to access a customer's account and its transactions, they would need to be:

+
    +
  • An account manager at the same branch as the customer's account
  • +
  • Connected via the branch's internal network or through the branch's VPN
  • +
  • Connected during this particular branch's office hours
  • +
+

We will start with the following Authorization Model

+
model
schema 1.1

type user

type branch
relations
define account_manager: [user]

type account
relations
define branch: [branch]
define account_manager: account_manager from branch
define customer: [user]
define viewer: customer or account_manager
define can_view: viewer

type transaction
relations
define account: [account]
define can_view: viewer from account
+

We are considering the case that:

    +
  • Anne is the Account Manager at the West-Side branch
  • +
  • Caroline is the customer for checking account number 526
  • +
  • The West-Side branch is the branch that the checking account number 526 has been created at
  • +
  • Checking account number 526 has a transaction, we'll call it transaction A
  • +
  • The West-Side branch’s office hours is from 8am-3pm UTC
  • +

The above state translates to the following relationship tuples:

Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Anne is the Account Manager at the West-Side branch
{"_description":"Anne is the Account Manager at the West-Side branch","user":"user:anne","relation":"account_manager","object":"branch:west-side"},
// Caroline is the customer for checking account number 526
{"_description":"Caroline is the customer for checking account number 526","user":"user:caroline","relation":"customer","object":"account:checking-526"},
// The West-Side branch is the branch that the Checking account number 526 has been created at
{"_description":"The West-Side branch is the branch that the Checking account number 526 has been created at","user":"branch:west-side","relation":"branch","object":"account:checking-526"},
// Checking account number 526 is the account for transaction A
{"_description":"Checking account number 526 is the account for transaction A","user":"account:checking-526","relation":"account","object":"transaction:A"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Requirements

+

By the end of this guide we would like to validate that:

+
    +
  • If Anne is at the branch, and it is 12pm UTC, Anne should be able to view transaction A
  • +
  • If Anne is connecting remotely at 12pm UTC but is not connected to the VPN, Anne should not be able to view transaction A
  • +
  • If Anne is connecting remotely and is connected to the VPN +
      +
    • at 12pm UTC, should be able to view transaction A
    • +
    • at 6pm UTC, should not be able to view transaction A
    • +
    +
  • +
+

Step by step

+

In order to solve for the requirements above, we will break the problem down to three steps:

+
    +
  1. Understand relationships without contextual tuples. We will want to ensure that
  2. +
+
    +
  • the customer can view a transaction tied to their account
  • +
  • the account manager can view a transaction whose account is at the same branch
  • +
+
    +
  1. Extend the Authorization Model to take time and ip address into consideration
  2. +
  3. Use contextual tuples for context related checks.
  4. +
+

Understand relationships without contextual data

+

With the Authorization Model and relationship tuples shown above, OpenFGA has all the information needed to

+
    +
  • Ensure that the customer can view a transaction tied to their account
  • +
  • Ensure that the account manager can view a transaction whose account is at the same branch
  • +
+

We can verify that using the following checks

+

Anne can view transaction:A because she is an account manager of an account that is at the same branch.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'transaction:A',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

Caroline can view transaction:A because she is a customer and the transaction is tied to her account.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:caroline',
relation: 'can_view',
object: 'transaction:A',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

Additionally, we will check that Mary, an account manager at a different branch cannot view transaction A.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Mary is an account manager at the East-Side branch
{"_description":"Mary is an account manager at the East-Side branch","user":"user:mary","relation":"account_manager","object":"branch:east-side"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:mary',
relation: 'can_view',
object: 'transaction:A',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

Note that so far, we have not prevented Anne from viewing the transaction outside office hours, let's see if we can do better.

+

Take time and IP address into consideration

+
Extend the authorization model
+

In order to add time and ip address to our authorization model, we will add appropriate types for them. We will have a "timeslot" and an "ip-address-range" as types, and each can have users related to it as a user.

+

type timeslot
relations
define user: [user]
+

type ip-address-range
relations
define user: [user]
+

We'll also need to introduce some new relations, and modify some others.

+
    +
  1. On the "branch" type:
  2. +
+
    +
  • Add "approved_timeslot" relation to mark than a certain timeslot is approved to view transactions for accounts in this branch
  • +
  • Add "approved_ip_address_range" relation to mark than an ip address range is approved to view transactions for accounts in this branch
  • +
  • Add "approved_context" relation to combine the two authorizations above (user from approved_timeslot and user from approved_ip_address_range), and indicate that the user is in an approved context
  • +
+

The branch type definition then becomes:

+

type branch
relations
define account_manager: [user]
define approved_ip_address_range: [ip-address-range]
define approved_timeslot: [timeslot]
define approved_context: user from approved_timeslot and user from approved_ip_address_range
+
    +
  1. On the "account" type:
  2. +
+
    +
  • Add "account_manager_viewer" relation to combine the "account_manager" relationship and the new "approved_context" relation from the branch
  • +
  • Update the "viewer" relation definition to customer or account_manager_viewer where "customer" can view without being subjected to contextual authorization, while "account_manager_viewer" needs to be within the branch allowed context to view
  • +
+

The account type definition then becomes:

+

type account
relations
define branch: [branch]
define account_manager: account_manager from branch
define customer: [user]
define account_manager_viewer: account_manager and approved_context from branch
define viewer: customer or account_manager_viewer
define can_view: viewer
+
note

On the "transaction" type:

    +
  • Nothing will need to be done, as it will inherit the updated "viewer" relation definition from "account"
  • +
+
Add the required tuples to mark that Anne is in an approved context
+

Now that we have updated our authorization model to take time and ip address into consideration, you will notice that Anne has lost access because nothing indicates that Anne is connecting from an approved ip address and time. You can verify that by issuing the following check:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'transaction:A',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

We need to add relationship tuples to mark some approved timeslots and ip address ranges:

+
note
    +
  • Here we added the time slots in increments of 1 hour periods, but this is not a requirement.
  • +
  • We did not add all the office hours to keep this guide shorter.
  • +
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// 11am to 12pm is within the office hours of the West-Side branch
{"_description":"11am to 12pm is within the office hours of the West-Side branch","user":"timeslot:11_12","relation":"approved_timeslot","object":"branch:west-side"},
// 12pm to 1pm is within the office hours of the West-Side branch
{"_description":"12pm to 1pm is within the office hours of the West-Side branch","user":"timeslot:12_13","relation":"approved_timeslot","object":"branch:west-side"},
// The office VPN w/ the 10.0.0.0/16 address range is approved for the West-Side branch
{"_description":"The office VPN w/ the 10.0.0.0/16 address range is approved for the West-Side branch","user":"ip-address-range:10.0.0.0/16","relation":"approved_ip_address_range","object":"branch:west-side"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Now that we have added the allowed timeslots and ip address ranges we need to add the following relationship tuples to give Anne access.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Anne is connecting from within the 10.0.0.0/16 ip address range
{"_description":"Anne is connecting from within the 10.0.0.0/16 ip address range","user":"user:anne","relation":"user","object":"ip-address-range:10.0.0.0/16"},
// Anne is connecting between 12pm and 1pm
{"_description":"Anne is connecting between 12pm and 1pm","user":"user:anne","relation":"user","object":"timeslot:12_13"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

If we have the above two tuples in the system, when checking whether Anne can view transaction A we should get a response stating that Anne can view it.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'transaction:A',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+ +

Now that we know we can authorize based on present state, we have a different problem to solve. We are storing the tuples in the state in order for OpenFGA to evaluate them, which means that:

+
    +
  • For the case of the IP Address, we are not able to truly authorize based on the context of the request. E.g. if Anne was trying to connect from the phone and from the PC at the same time, and only the PC was connected to the VPN, how would OpenFGA know to deny one and allow the other if the data is stored in the state?
  • +
  • On every check call we have to first write the correct tuples, then call the Check api, then clean up those tuples. This causes a substantial increase in latency as well as incorrect answers for requests happening in parallel (they could write/delete each other's tuples).
  • +
+

How do we solve this? How do we tie the above two tuples to the context of the request instead of the system state?

+

First, we will need to undo adding the stored relationship tuples where Anne is connecting from within the 10.0.0.0/16 ip address range and Anne connecting between 12pm and 1pm

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
deletes: [
// Remove stored tuples where Anne is connecting from within the 10.0.0.0/16 ip address range
{ user: 'user:anne', relation: 'user', object: 'ip-address-range:10.0.0.0/16'},
// Remove stored tuples where Anne is connecting between 12pm and 1pm
{ user: 'user:anne', relation: 'user', object: 'timeslot:12_13'}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

For Check calls, OpenFGA has a concept called "Contextual Tuples". Contextual Tuples are tuples that do not exist in the system state and are not written beforehand to OpenFGA. They are tuples that are sent alongside the Check request and will be treated as if they already exist in the state for the context of that particular Check call.

+

When Anne is connecting from an allowed ip address range and timeslot, OpenFGA will return {"allowed":true}:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'transaction:A',
contextualTuples: [
{"_description":"Anne is connecting from within the 10.0.0.0/16 ip address range","user":"user:anne","relation":"user","object":"ip-address-range:10.0.0.0/16"},{"_description":"Anne is connecting between 12pm and 1pm","user":"user:anne","relation":"user","object":"timeslot:12_13"}
],
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

When Anne is connecting from a denied ip address range or timeslot, OpenFGA will return {"allowed":false}:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'transaction:A',
contextualTuples: [
{"_description":"Anne is connecting from within the 10.0.0.0/16 ip address range","user":"user:anne","relation":"user","object":"ip-address-range:10.0.0.0/16"},{"_description":"Anne is connecting between 6pm and 7pm","user":"user:anne","relation":"user","object":"timeslot:18_19"}
],
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

Summary

+

Final version of the Authorization Model and Relationship tuples

model
schema 1.1

type user

type branch
relations
define account_manager: [user]
define approved_ip_address_range: [ip-address-range]
define approved_timeslot: [timeslot]
define approved_context: user from approved_timeslot and user from approved_ip_address_range

type account
relations
define branch: [branch]
define account_manager: account_manager from branch
define customer: [user]
define account_manager_viewer: account_manager and approved_context from branch
define viewer: customer or account_manager_viewer
define can_view: viewer

type transaction
relations
define account: [account]
define can_view: viewer from account

type timeslot
relations
define user: [user]

type ip-address-range
relations
define user: [user]
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Anne is the Account Manager at the West-Side branch
{"_description":"Anne is the Account Manager at the West-Side branch","user":"user:anne","relation":"account_manager","object":"branch:west-side"},
// Caroline is the customer for checking account number 526
{"_description":"Caroline is the customer for checking account number 526","user":"user:caroline","relation":"customer","object":"account:checking-526"},
// The West-Side branch is the branch that the Checking account number 526 has been created at
{"_description":"The West-Side branch is the branch that the Checking account number 526 has been created at","user":"branch:west-side","relation":"branch","object":"account:checking-526"},
// Checking account number 526 is the account for transaction A
{"_description":"Checking account number 526 is the account for transaction A","user":"account:checking-526","relation":"account","object":"transaction:A"},
// 8am to 9am is within the office hours of the West-Side branch
{"_description":"8am to 9am is within the office hours of the West-Side branch","user":"timeslot:8_9","relation":"approved_timeslot","object":"branch:west-side"},
// 9am to 10am is within the office hours of the West-Side branch
{"_description":"9am to 10am is within the office hours of the West-Side branch","user":"timeslot:9_10","relation":"approved_timeslot","object":"branch:west-side"},
// 10am to 11am is within the office hours of the West-Side branch
{"_description":"10am to 11am is within the office hours of the West-Side branch","user":"timeslot:10_11","relation":"approved_timeslot","object":"branch:west-side"},
// 11am to 12pm is within the office hours of the West-Side branch
{"_description":"11am to 12pm is within the office hours of the West-Side branch","user":"timeslot:11_12","relation":"approved_timeslot","object":"branch:west-side"},
// 12pm to 1pm is within the office hours of the West-Side branch
{"_description":"12pm to 1pm is within the office hours of the West-Side branch","user":"timeslot:12_13","relation":"approved_timeslot","object":"branch:west-side"},
// 1pm to 2pm is within the office hours of the West-Side branch
{"_description":"1pm to 2pm is within the office hours of the West-Side branch","user":"timeslot:13_14","relation":"approved_timeslot","object":"branch:west-side"},
// 2pm to 3pm is within the office hours of the West-Side branch
{"_description":"2pm to 3pm is within the office hours of the West-Side branch","user":"timeslot:14_15","relation":"approved_timeslot","object":"branch:west-side"},
// The office VPN w/ the 10.0.0.0/16 address range is approved for the West-Side branch
{"_description":"The office VPN w/ the 10.0.0.0/16 address range is approved for the West-Side branch","user":"ip-address-range:10.0.0.0/16","relation":"approved_ip_address_range","object":"branch:west-side"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
Warning

Contextual tuples:

+

Taking it a step further: Banks as a service authorization

+

In order to keep this guide concise, we assumed you were modeling for a single bank. What if you were offering a multi-tenant service where each bank is a single tenant?

+

In that case, we can extend the model like so:

+
model
schema 1.1

type user

type bank
relations
define admin: [user]

type branch
relations
define bank: [bank]
define account_manager: [user]
define approved_ip_address_range: [ip-address-range]
define approved_timeslot: [timeslot]
define approved_context: user from approved_timeslot and user from approved_ip_address_range

type account
relations
define branch: [branch]
define account_manager: account_manager from branch
define customer: [user]
define account_manager_viewer: account_manager and approved_context from branch
define viewer: customer or account_manager_viewer
define can_view: viewer

type transaction
relations
define account: [account]
define can_view: viewer from account

type timeslot
relations
define user: [user]

type ip-address-range
relations
define user: [user]
+ +
Object to Object Relationships

Learn how objects can relate to one another and how that can affect user's access.

Modeling with Multiple Restrictions

Learn how to model requiring multiple relationships before users are authorized to perform certain actions.

OpenFGA API

Details on the Check API in the OpenFGA reference guide.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization.html.html b/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization.html.html new file mode 100644 index 000000000..1e1436255 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/custom-roles.html b/pr-preview/pr-921/docs/modeling/custom-roles.html new file mode 100644 index 000000000..7d5360b6f --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/custom-roles.html @@ -0,0 +1,78 @@ + + + + + +Custom Roles | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Custom Roles

+ +

In this guide you'll learn how to model custom roles in your system using OpenFGA.

+

For example, a Business-to-Business (B2B) application could allow customers to create their own custom roles on the application to grant their users.

+
When to use

In many cases, roles would fit in well as relations on an object type, as seen in Modeling Roles and Permissions. In some cases, however, they may not be enough.

Custom roles are useful when:

    +
  • Users of the application are able to create arbitrary sets of roles with different permissions that govern the users' access to objects.
  • +
  • It is not known beforehand (at the time of Authorization Model creation) what the application roles are.
  • +
  • The team responsible for building the authorization model is different from the teams responsible for defining roles and access to the application.
  • +
+

Before you start

+

Before you start this guide, make sure you're familiar with some OpenFGA Concepts and know how to develop the things listed below.

+

Initial Model

To start, let's say there is an application with a type called asset-category. Users can have view and/or edit access to assets in that category. Any user who can edit can also view.

We'll start with the following authorization model showing a system with an asset-category type. This type allows users to have view and edit access to it.

model
schema 1.1

type user

type asset-category
relations
define viewer: [user] or editor
define editor: [user]

In addition, you'll need to know the following:

Modeling Roles and Permissions

You need to know how to add users to groups and grant groups access to resources. Learn more →

Modeling Object-to-Object Relationships

You need to know how to create relationships between objects and how that might affect a user's relationships to those objects. Learn more →

Concepts & Configuration Language

+ +

Step By Step

+

Starting with the authorization model mentioned above, we want to enable users to create their own custom roles, and tie permissions to those roles to our two users and to the permissions on the logo asset category.

+

For this guide, we'll model a scenario where a certain organization using our app has created an asset-category called "logos", and another called "text content".

+

The company administrator would like to create:

+
    +
  • a media-manager role that allows users to edit assets in the logos asset category
  • +
  • a media-viewer role that allows users to view all assets in the logos asset category
  • +
  • a blog-editor role that allows users to edit all assets in the text content asset category
  • +
  • a blog-viewer role that allows users to view all assets in the text content asset category
  • +
+

Imagine these are what the permissions the roles in one organization using our service are like:

+

Image showing custom roles and permissions

+

Finally, the administrator wants to assign Anne the media-manager role and Beth the media-viewer role.

+

At the end, we'll verify our model by ensuring the following access check requests return the expected result.

+

Image showing expected results

+

In order to do this, we need to:

+
  1. Update the Authorization Model to add a Role Type
  2. Use Relationship Tuples to tie the Users to the Roles
  3. Use Relationship Tuples to associate Permissions with the Roles
  4. Verify that the Authorization Model works
+

01. Update The Authorization Model To Add A Role Type

+

Because our roles are going to be dynamic and might change frequently, we represent them in a new type instead of as relations on that same type. We'll create new type called role, where users can be related as assignee to it.

+

The authorization model becomes this:

+
model
schema 1.1

type user

type asset-category
relations
define viewer: [user, role#assignee] or editor
define editor: [user, role#assignee]

type role
relations
define assignee: [user]
+

With this change we can add relationship tuples indicating that a certain user is assigned a certain role.

+

02.Use Relationship Tuples To Tie The Users To The Roles

+

Once we've added the role type, we can assign roles to Anne and Beth. Anne is assigned the "media-manager" role and Beth is assigned the "media-viewer" role. We can do that by adding relationship tuples as follows:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Anne is assigned the media-manager role
{"_description":"Anne is assigned the media-manager role","user":"user:anne","relation":"assignee","object":"role:media-manager"},
// Beth is assigned the media-viewer role
{"_description":"Beth is assigned the media-viewer role","user":"user:beth","relation":"assignee","object":"role:media-viewer"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

We can verify they are members of said roles by issuing the following check requests:

+

Image showing expected membership checks

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'assignee',
object: 'role:media-manager',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

03. Use Relationship Tuples To Associate Permissions With The Roles

+

With our users and roles set up, we still need to tie members of a certain role to it's corresponding permission(s).

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Users assigned the media-manager role can edit in the Logos assets category
{"_description":"Users assigned the media-manager role can edit in the Logos assets category","user":"role:media-manager#assignee","relation":"editor","object":"asset-category:logos"},
// Users assigned the media-viewer role can view from the Logos assets category
{"_description":"Users assigned the media-viewer role can view from the Logos assets category","user":"role:media-viewer#assignee","relation":"viewer","object":"asset-category:logos"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

04. Verify That The Authorization Model Works

+

To ensure our model works, it needs to match our expectations:

+

Image showing expected results

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'editor',
object: 'asset-category:logos',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

The checks come back as we expect, so our model is working correctly.

+ +
Modeling Roles and Permissions

Learn how to remove the direct relationship to indicate nonassignable permissions.

Modeling Concepts: Object to Object Relationships

Learn about how to model object to object relationships in OpenFGA.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/custom-roles.html.html b/pr-preview/pr-921/docs/modeling/custom-roles.html.html new file mode 100644 index 000000000..a56b1c7c6 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/custom-roles.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/direct-access.html b/pr-preview/pr-921/docs/modeling/direct-access.html new file mode 100644 index 000000000..83952d447 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/direct-access.html @@ -0,0 +1,54 @@ + + + + + +Direct Access | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Direct Access

+ +

This article describes how to grant a user access to an object in OpenFGA.

+
When to use

Granting access with relationship tuples is a core part of OpenFGA. Without relationship tuples, any checks_ will fail. You should use:

    +
  • authorization model to represent what relations are possible between the users and objects in the system
  • +
  • relationship tuples to represent the facts about the relationships between users and objects in your system.
  • +
+

Before you start

+

Familiarize yourself with OpenFGA Concepts to understand how to develop a relationship tuple and authorization model.

+

Assume that you have the following authorization model.
+You have a type called document that can have a viewer and/or an editor.

model
schema 1.1

type user

type document
relations
define viewer: [user]
define editor: [user]

In addition, you will need to know the following:

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
+ +

Step By Step

+

For an application to understand that user x has access to document y, it must provide OpenFGA that information with relationship tuples. +Each relationship tuple has three basic parameters: a user, a relation and an object.

+

01. Create A Relationship Tuple

+

Below, you'll add a relationship tuple to indicate that bob is an editor of document:meeting_notes.doc by adding the following:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
{"user":"user:bob","relation":"editor","object":"document:meeting_notes.doc"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

02. Check That The Relationship Exists

+

Once you add that relationship tuple to OpenFGA, you can check if the relationship is valid by asking if bob is an editor of document:meeting_notes.doc:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'editor',
object: 'document:meeting_notes.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

Checking whether bob is an viewer of document:meeting_notes.doc returns false because that relationship tuple does not exist in OpenFGA yet.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'viewer',
object: 'document:meeting_notes.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+
caution

When creating relationship tuples for OpenFGA, use unique ids for each object and user within your application domain. We're using first names and simple ids to as an easy-to-follow example.

+ +
OpenFGA Concepts

Learn about the OpenFGA Concepts.

Modeling: Getting Started

Learn about how to get started with modeling.

Configuration Language

Learn about OpenFGA Configuration Language.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/direct-access.html.html b/pr-preview/pr-921/docs/modeling/direct-access.html.html new file mode 100644 index 000000000..294bc5937 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/direct-access.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/getting-started.html b/pr-preview/pr-921/docs/modeling/getting-started.html new file mode 100644 index 000000000..5047a6b89 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/getting-started.html @@ -0,0 +1,412 @@ + + + + + +Get Started with Modeling | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Get Started with Modeling

+ +

Creating a Relationship Based Access Control (ReBAC) authorization model might feel odd at first. Most of us tend to think about authorization models in terms of roles and permissions. After all, most software works like that. Your existing systems are likely built on a model using roles and permissions.

+

This guide outlines a process for defining your authorization model with OpenFGA.

+

Introduction To Modeling

+

To define a ReBAC model in OpenFGA we recommend:

+
    +
  • If you have an existing system: forget about how your system works today and start thinking about how you want it to work in the future.
  • +
  • Thinking about authorization starting from the resources, or objects as OpenFGA calls them.
  • +
+

If that sounds hard, don't worry! We'll guide you through it.

+

OpenFGA is built to quickly and reliably make authorization checks +. This means providing an answer to a question: "Can user U perform action A on object O?"

+

ReBAC systems determine access from a user's relation to an object. Authorization decisions are then yes or no answers to the question: "Does user U have relation R with object O?".

+
General Authorization Check

"Can user U perform an action A on object O?"

OpenFGA (ReBAC) Authorization Check

"Does user U have relation R with object O?"

+

In the previous example, a relation R should be defined that implies permission to action A. For example:

+
General Authorization Check

"Can user Jane perform action view on object project sandcastle?"

OpenFGA (ReBAC) Authorization Check

"Can user Jane have relation view with object project sandcastle?"

+

We'll provide more detailed examples throughout this article.

+

When you are modeling, you need to answer a more general question:

+
Why could user U perform an action A on an object O?
+

If you can answer that question for all types of objects in your system, then you can codify that into an authorization model.

+

Let's get started!

+
+

A Process For Defining Authorization Models

+

Defining an authorization model requires codifying an answer to the question "why could user U perform an action A on an object O?" for all use cases or actions in your system. This is an iterative process. For the purpose of this guide, we'll go through one iteration of this process using a simplified Google Drive like system as an example.

+

Steps for defining your authorization model:

+
    +
  1. Pick the most important feature
  2. +
  3. List the object types
  4. +
  5. List relations for those types
  6. +
  7. Define relations
  8. +
  9. Test the model
  10. +
  11. Iterate
  12. +
+

The starting point

+

01. Pick The Most Important Feature

+

Pick the most important feature

+

A feature, in the context of this document, is an action or related set of actions your users can perform in your system. We'll introduce an example feature later in this section.

+

Start with the most important feature. It doesn't have to be the most complex one, but it should be the most important one. You're probably more familiar with the authorization requirements for this feature than other less important use cases.

+
Important
    +
  • Requirement clarity is fundamental when defining an authorization model.
  • +
  • The scope of the feature is not important at this point. You can always iterate later.
  • +
+

Write It In Plain Language

+

Once you've picked a feature, describe its authorization related scope using simple language. Avoid using the word "roles", as this ties you to an RBAC way of thinking.

+
info

Roles don't "disappear" in ReBAC systems like OpenFGA. Your users might have roles on a given object, rather than the entire system. But starting from the term "role" might lead you down the wrong path. Instead it is better to discover roles while you are modeling.

+

Your feature description should include the objects, users and groups of users participating in the system. Sentences should look like this:

+
A user {user} can perform action {action} to/on/in {object types} ... IF {conditions}
+

Let's look at an example of a simplified Google Drive like system. We'll focus on the feature allowing users to create, read, +update, delete, and share documents with other users.

+
+
+

This feature can be described with these sentences:

+
    +
  • A user can create a document in a drive if they are the owner of the drive.
  • +
  • A user can create a folder in a drive if they are the owner of the drive.
  • +
  • A user can create a document in a folder if they are the owner of the folder. The folder is the parent of the document.
  • +
  • A user can create a folder in a folder if they are the owner of the folder. The existing folder is the parent of the new folder.
  • +

    +
  • A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
  • +

    +
  • A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer or owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can change the owner of a document if they are an owner of the document.
  • +

    +
  • A user can change the owner of a folder if they are an owner of the folder.
  • +

    +
  • +

    A user can be a member of an organization.

    +

    How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.

    +
  • +

    +
  • A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
  • +
+

02. List The Object Types

+

List the object types

+

Next make a list of the types of objects in your system. You might be able to identify the objects in your system from your existing domain/database model.

+

Find all the objects in the previous step using this template:

+
A user {user} can perform action {action} to/on/in {object type} ... IF {conditions}
+

These are all the object types from the previous step (in order of appearance) based on that template:

+

Document

Folder

Organization

+

Let's highlight all object types in blue:

+
    +
  • A user can create a document in a drive if they are the owner of the drive.
  • +
  • A user can create a folder in a drive if they are the owner of the drive.
  • +
  • A user can create a document in a folder if they are the owner of the folder.
  • +
  • A user can create a folder in a folder if they are the owner of the folder.
  • +

    +
  • A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
  • +

    +
  • A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer, owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can change the owner of a document if they are an owner of the document.
  • +

    +
  • A user can change the owner of a folder if they are an owner of the folder.
  • +

    +
  • +

    A user can be a member of an organization.

    +

    How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.

    +
  • +

    +
  • A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
  • +
+

However, the list of object types is not finished. To complete the list of object types you must also add all the second nouns that appear in conditions as part of expressions of this format: "{first noun} of a/the {second noun}".

+
... IF {first noun} of a/the {second noun}
+

Let's highlight those expressions in green:

+
    +
  • A user can create a document in a drive if they are the owner of the drive.
  • +
  • A user can create a folder in a drive if they are the owner of the drive.
  • +
  • A user can create a document in a folder if they are the owner of the folder. The folder is the parent of the document.
  • +
  • A user can create a folder in a folder if they are the owner of the folder. The existing folder is the parent of the new folder .
  • +

    +
  • A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
  • +

    +
  • A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer or owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can change the owner of a document if they are an owner of the document.
  • +

    +
  • A user can change the owner of a folder if they are an owner of the folder.
  • +

    +
  • +

    A user can be a member of an organization.

    +

    How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.

    +
  • +

    +
  • A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
  • +
+

The only second noun we didn't have in our object type list is "Drive", so we'll add it to the list. +We will also need to add "User" to the list as it establishes the type of user who can establish relations.

+

User

Document

Folder

Organization

Drive

+

Now that we have a list of object types we can start defining them using the OpenFGA Configuration Language:

+
model
schema 1.1

type user

type document

type folder

type organization

type drive
+
Caution

You're now in the process of building a version you can use. The model above is not yet a valid authorization model accepted by OpenFGA.

+
Important

In a few cases other users can be part of determining whether an action can be performed on an action or not. Social media is an example of this "a user can comment on a picture if they are a friend of the user that published it".

In those cases User should also be an object type. Following the last recommendation, we would discover the User type because it is a second noun in an expression: "friend of the user".

+

03. List Relations For Those Types

+

List relations for those types

+

Each of the previously defined types has a set of relations. Relations are an important component in your model. After all, OpenFGA is a Relationship Based Access Control (ReBAC) system.

+

To identify relations for a type in the write-up we can perform an exercise similar to the one we did in list the type of objects in your system.

+

Relations for a type {type} will be all of these:

+
    +
  • any noun that is the {noun} of a "{noun} of a/an/the {type}" expression. These are typically the Foreign Keys in a database. We'll highlight these in green.
  • +
  • any verb or action that is the {action} of a "can {action} (in) a/an {type}" expression. These are typically the permissions for a type. We'll highlight these in yellow.
  • +
+
    +
  • A user can create a document in a drive if they are the owner of the drive.
  • +
  • A user can create a folder in a drive if they are the owner of the drive.
  • +
  • A user can create a document in a folder if they are the owner of the folder. The folder is the parent of the document.
  • +
  • A user can create a folder in a folder if they are the owner of the folder. The existing folder is the parent of the new folder.
  • +

    +
  • A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can share a folder with another user or an organization as a viewer if they are an owner of the folder.
  • +

    +
  • A user can view a document if they are an owner, viewer or editor of the document or if they are a viewer or owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can edit a document if they are an owner or editor of the document or if they are an owner of the folder/drive that is the parent of the document.
  • +

    +
  • A user can change the owner of a document if they are an owner of the document.
  • +

    +
  • A user can change the owner of a folder if they are an owner of the folder.
  • +

    +
  • +

    A user can be a member of an organization.

    +

    How a user is added as a member to an organization is beyond the scope of the feature we picked to write down.

    +
  • +

    +
  • A user can view a folder if they are the owner of the folder, or a viewer or owner of either the parent folder of the folder, or the parent drive of the folder.
  • +
+

The resulting list is:

+

Document

    +
  • parent
  • +
  • can_share
  • +
  • owner
  • +
  • editor
  • +
  • can_write
  • +
  • can_view
  • +
  • viewer
  • +
  • can_change_owner
  • +

Folder

    +
  • can_create_document
  • +
  • owner
  • +
  • can_create_folder
  • +
  • can_view
  • +
  • viewer
  • +
  • parent
  • +

Organization

    +
  • member
  • +

Drive

    +
  • can_create_document
  • +
  • owner
  • +
  • can_create_folder
  • +
+
info

In OpenFGA, relations can only have alphanumeric characters, underscores and hyphens. We recommend using underscore (_) to separate words and removing prepositions. E.g.: "can create a document" can become "can_create_document" or "create_document" if you are into brevity.

+

Using the OpenFGA Configuration Language we can enumerate the relations for each type:

+
model
schema 1.1
type user
type document
relations
define parent:
define owner:
define editor:
define viewer:
define can_share:
define can_view:
define can_write:
define can_change_owner:
type folder
relations
define owner:
define parent:
define viewer:
define can_create_folder:
define can_create_document:
define can_view:
type organization
relations
define member:
type drive
relations
define owner:
define can_create_document:
define can_create_folder:
+
Caution

You're now in the process of building a version you can use. The model above is not yet a valid authorization model accepted by OpenFGA.

+

04. Define Relations

+

Define relations

+

We will use the OpenFGA Configuration Language to create a relation definition for each of the relations we identified. At this stage we will encode the answers to the question we asked at the beginning of the document:.

+
Why could a user U, perform an action A on an object O?
+

We are going to go over each type and each of its relations and create a definition for it.

+

Type: Organization

+

We recommend starting from objects that represent groups/containers of users. For features in most systems these are easy to define and help reason about the other types. Examples of type names for these are "team", "group", "organization", etc.

+
Relation: Member
+

The member relation is used to tell OpenFGA about the members of an organization.

+
Important

Relation names in OpenFGA are arbitrary strings. There are no reserved relation names. You can use "member" or "part_of" or anything else to refer to a user that is part of a team/organization.

+

Remember "How a user is added as a member to an organization is beyond the scope of this feature." For the purposes of this model the relation definition should be:

+

type organization
relations
define member: [user, organization#member]
+

Why? This relation definition states:

+
    +
  • +

    That organizations have members

    +
  • +
  • +

    That the members of an organization with id {id} are all users described by tuples of the form:

    +

    { user: {user-id}, relation: "member", object: "organization:{id}" }

    +
  • +
+
Important

Relation definitions of the form "define {relation}: [user, organization#member]" are fairly common. They are used to express that relationships "to the object with that relation" (e.g. "users" of type user or "member of organization") can be assigned by your system and that only the users that have that relation are those with a direct relationship.

+

You can read more about group membership and types in Modeling User Groups.

+

For the direct relationships, we need to figure out the object types that makes sense for the relationship tuples' user. In our organization example, it makes sense for member relations to have user of type

+
    +
  • user
  • +
  • organization#member (i.e., other organization's member)
  • +
+

However, it will not make sense for organization member's user to be of type document, folder or drive.

+

We will specify this logic as part of directly related user type.

+
Side note

This also automatically supports nested organizational membership if you want such a feature in your system. You could use relationship tuples like the following one to express that "members of organization A are members of organization B":

{ user: "organization:A#member", relation: "member", object: "organization:B"}

If you want to learn more, you can read further about this in Modeling User Groups and Managing Relationships Between Objects.

+
Complete Type Definition
+

The complete type definition for the organization type is:

+

type organization
relations
define member: [user, organization#member]
+

Type: Document

+

After defining your "group" like types, continue with the most important type for the feature: the one that allows the main use case. In this case "document", since the main use case for users is to create, write, read and collaborate on documents.

+

Defining relations for the main type lets you focus on your core use case, and will likely make other type definitions easier.

+
Relation: Owner
+

The owner relation is used to tell OpenFGA which users are owners of the document.

+
Important

In the current version, there is no way to state that there is only one owner in the authorization model. The application must limit this set of users to just one owner if that is a requirement.

+

When a document is created, a relationship tuple will be stored in OpenFGA representing this relationship between owner and document. This is an example of a user to object relationship.

+

The relation definition then should be:

+

type document
relations
define owner: [user, organization#member]
+

Why? This relation definition states that:

+
    +
  • each document can have one or more owners
  • +
  • owners of a document are assignable by creating a tuple of the format +{ user: "{user_id}", relation: "owner", object: "document:{id}" } for individual users
  • +
+
Relation: Editor
+

The editor relation is used to tell OpenFGA which users are editors of the document.

+

When a user shares a document with another user or set of users as editor, a relationship tuple will be stored in OpenFGA representing this relationship between editor and document. This is an example of a users to object relationship.

+

The relation definition then should be:

+

type document
relations
define editor: [user, organization#member]
+

Why? This relation definition states that:

+
    +
  • each document can have editors
  • +
  • the editor(s) of a document are assignable by creating a tuple with shape +{ user: "{user_id}", relation: "editor", object: "document:{id}" } for individual users
  • +
+

This also supports making all members in an organization editors of the document, through a group to object relationship. A relationship tuple like the following one states that the members of organization A are editors of document 0001.

+
[{
"user": "organization:A#member",
"relation": "editor",
"object": "document:0001"
}]
+

You can learn more about this in Modeling User Groups.

+
Relation: Viewer
+

The viewer relation is similar to the document's editor relation. It will be defined like this:

+

type document
relations
define viewer: [user, organization#member]
+
Relation: Parent
+

The parent relation is used to tell OpenFGA which folder or drive is the parent of the document.

+
Important

Relation names in OpenFGA are arbitrary strings. There are no reserved relation names. You can use "parent", "container" or "ancestor" to refer to a "parent folder".

+

This relation is different from the others we have seen so far, as it is a relation between two objects (a folder and or drive that is the parent of the document). This is known as an object to object relationship, of which parent-child is a particular case.

+

When a document is created a relationship tuple will be stored in OpenFGA to represent this relationship between parent and document. The relation definition then should be:

+

type document
relations
define parent: [folder, drive]
+

Why? This relation definition states that:

+
    +
  • documents may have a parent
  • +
  • the parent(s) of a document with id {id} is either a folder or a drive, described by one of these relationship tuples: +
      +
    • { user: "folder:{id}", relation: "parent", object: "document:{id}" }
    • +
    • { user: "drive:{id}", relation: "parent", object: "document:{id}" }
    • +
    +
  • +
+

We can use direct type restriction to ensure a document's parent can only be an object of type either drive or folder.

+
Side note

You might have noticed that the "user" in the tuple is an object. This is a special syntax OpenFGA accepts in the "user" parameter to write object to object relationships. You can read more about writing data to manage object to object relationships in Managing Relationships Between Objects.

+
Relation: can_share
+

We need to express the following in the relation definition:

+

A user can share a document with another user or an organization as either editor or viewer if they are an owner or editor of a document or if they are an owner of the folder that is the parent of the document.

+

We can achieve that with the following definition using OpenFGA Configuration Language:

+

type document
relations
define can_share: owner or editor or owner from parent
+

There are a few key things here:

+
    +
  • We don't use a direct relationship type restriction as part of the definition. can_share is a common example of representing a permission that is defined in terms of other relations but is not directly assignable by the system.
  • +
  • The relation definition contains a union operator separating a list of relations that the user must have with the object in order to "be able to share the document". It is any of: +
      +
    • Being an owner of the document
    • +
    • Being an editor of the document
    • +
    • Being an owner of the parent of the document. Whether the parent is a drive or a folder is not important, as they both have an owner relation.
    • +
    +
  • +
+

You can read more about the aforementioned items in Modeling Roles and Permissions.

+
Relation: can_view
+

We need to express the following in the relation definition:

+

A user can view a document if they are an owner, viewer or editor of a document or if they are a viewer, owner of the folder/drive that is the parent of the document.

+

Similar to the can_share relation, we can achieve that with the following definition using OpenFGA Configuration Language:

+

type document
relations
define can_view: viewer or editor or owner or viewer from parent or owner from parent
+
Relation: can_write
+

We need to express the following in the relation definition:

+

A user can write a document if they are an owner or editor of a document or if they are an owner or editor of the folder/drive that is the parent of the document.

+

Similar to the can_share relation, we can achieve that with the following definition using OpenFGA Configuration Language:

+

type document
relations
define can_write: editor or owner or owner from parent
+
Relation: can_change_owner
+

We need to express the following in the relation definition:

+

A user can change the owner of a document if they are an owner of the document.

+

Similar to the can_share relation, we can achieve that with the following definition using OpenFGA Configuration Language:

+

type document
relations
define can_change_owner: owner
+
Complete Type Definition
+

The complete type definition for the document type is:

+
model
schema 1.1

type document
relations
define owner: [user, organization#member]
define editor: [user, organization#member]
define viewer: [user, organization#member]
define parent: [folder]
define can_share: owner or editor or owner from parent
define can_view: viewer or editor or owner or viewer from parent or editor from parent or owner from parent
define can_write: editor or owner or owner from parent
define can_change_owner: owner
+

Combining the type definitions for document and organization, we have

+
model
schema 1.1

type user

type organization
relations
define member: [user, organization#member]

type document
relations
define owner: [user, organization#member]
define editor: [user, organization#member]
define viewer: [user, organization#member]
define parent: [folder]
define can_share: owner or editor or owner from parent
define can_view: viewer or editor or owner or viewer from parent or editor from parent or owner from parent
define can_write: editor or owner or owner from parent
define can_change_owner: owner
+
note

The OpenFGA authorization model API and SDK only accepts JSON in its input. To convert from DSL to JSON, you may use the FGA CLI to run fga model transform.

+

05. Test The Model

+

Test the model

+

Once you have defined your group like types and the most important type for your feature you want to ensure everything is working as expected. This means testing the model.

+

How? Remember from the introduction that OpenFGA's main job is to answer the question:

+
Can user U, perform an action A on an object O?
+

The OpenFGA service does that by checking if a user has a particular relationship to an object, based on your authorization model and relationship tuples.

+
General Authorization Check

"Can user U perform action A on object O?"

OpenFGA (ReBAC) Authorization Check

"Can user U have relation R with object O?"

+

What we want is to ensure that given our current authorization model and some sample relationship tuples, we get the expected results for those questions.

+

So we'll write some relationship tuples and assertions. An OpenFGA assertion takes one of these forms:

+
    +
  1. user U has relation R with object O
  2. +
  3. user U does not have relation R with object O
  4. +
+

Much like automated tests and assertions work for programming languages, you can use assertions to prevent regressions while you change your tuples and authorization model. Essentially, assertions help you ensure things work like you expect them to work as you iterate.

+

Write Relationship Tuples

+

The relationship tuples should represent real examples from your system with fake data.

+

At this point you haven't defined the drive or folder types, so you can only test things based on users or organization members' relationships to documents. Let's imagine an example setup and write the relationship tuples for it:

+
System ActionRelationship Tuple
Anne is a member of the contoso organization{ user:"user:anne", relation: "member", object: "organization:contoso"}
Beth is a member of fabrikam organization{ user:"user:beth", relation: "member", object: "organization:fabrikam"}
Anne creates document:1, becomes its owner.{ user:"user:anne", relation: "owner", object: "document:1"}
Anne shares document:1 with all members of the fabrikam organization as editor.{ user:"organization:fabrikam#member", relation: "editor", object: "document:1"}
Beth creates document:2 and becomes its owner.{ user:"user:beth", relation: "owner", object: "document:2"}
Beth shares document:2 with all members of the contoso organization as viewer{ user:"organization:contoso#member", relation: "viewer", object: "document:2"}
+

Follow these steps to create relationship tuples.

+

Create Assertions

+

According to our written down model and the relationship tuples from the previous step, these assertions should be specified:

+

Because anne is the owner of document:1:

+
    +
  • user anne has relation can_share with document:1
  • +
  • user anne has relation can_write with document:1
  • +
  • user anne has relation can_view with document:1
  • +
  • user anne has relation can_change_owner with document:1
  • +
+

Because beth is a member of organization:fabrikam and members of organization:fabrikam are writer of document:1:

+
    +
  • user beth has relation can_share with document:1
  • +
  • user beth has relation can_write with document:1
  • +
  • user beth has relation can_view with document:1
  • +
  • user beth does not have relation can_change_owner with document:1
  • +
+

Because beth is the owner of document:2:

+
    +
  • user beth has relation can_share with document:2
  • +
  • user beth has relation can_write with document:2
  • +
  • user beth has relation can_view with document:2
  • +
  • user beth has relation can_change_owner with document:2
  • +
+

Because anne is a member of organization:contoso and members of organization:contoso are viewer of document:2:

+
    +
  • user anne does not have relation can_share with document:2
  • +
  • user anne does not have relation can_write with document:2
  • +
  • user anne has relation can_view with document:2
  • +
  • user anne does not have relation can_change_owner with document:2
  • +
+

Follow these steps to create assertions.

+

Run Assertions

+

Run the assertions. They should all pass. If they don't you can use the query view to understand what is causing them to fail, and then update your authorization model and relation tuples accordingly.

+

Once all the assertions are working, you should continue the iterative process of working on your model.

+

06. Iterate

+

Iterate

+

We'll leave the exercise of defining the drive and folder relations, then adding relationship tuples and assertions to you. Once you are finished, check out the complete example to see how you did.

+

When defining the authorization model for your own system, you would continue iterating on the authorization model with the next feature and so on.

+ +
OpenFGA Concepts

Learn about the OpenFGA Concepts.

Configuration Language

Learn about OpenFGA Configuration Language.

Direct Access

Learn about modeling user access to an object.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/getting-started.html.html b/pr-preview/pr-921/docs/modeling/getting-started.html.html new file mode 100644 index 000000000..f66deee93 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/getting-started.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/migrating.html b/pr-preview/pr-921/docs/modeling/migrating.html new file mode 100644 index 000000000..8092837a7 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/migrating.html @@ -0,0 +1,27 @@ + + + + + +Model Migrations | OpenFGA + + + + + + + + + + + + + + +
Skip to main content
+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/migrating.html.html b/pr-preview/pr-921/docs/modeling/migrating.html.html new file mode 100644 index 000000000..42074af60 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/migrating.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/migrating/migrating-models.html b/pr-preview/pr-921/docs/modeling/migrating/migrating-models.html new file mode 100644 index 000000000..6a4cfe494 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/migrating/migrating-models.html @@ -0,0 +1,48 @@ + + + + + +Model Migrations | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Model Migrations

+

You can think of model migrations for OpenFGA in the same way as you think about relational database migrations. You can perform migrations with or without downtime for both, and for some changes, doing them without downtime is harder.

+
OpenFGARelational Databases
Add a typeAdd a table
Remove a typeRemove a table
Rename a typeRename a table
Add a relationAdd a nullable column
Rename a relationRename a column
Delete a relationDelete a column
+

When thinking about migrations, keep in mind that:

+
    +
  • Models are immutable.
  • +
  • The tuples that are not valid according to the specified model, are ignored when evaluating queries.
  • +
+

To add a type or relation

+
    +
  1. Add the type or relation to the authorization model, and write the model to the store. This will generate a new model ID.
  2. +
  3. If you have tuples to write for the new types/relations, write them.
  4. +
  5. Update the application code to start using those new types/relations.
  6. +
  7. Configure the application to start using the new model ID.
  8. +
+

To delete a type or relation

+
    +
  1. Delete the type or relation to the authorization model, and write the model to the store. This will generate a new model ID.
  2. +
  3. Update the application code to stops using the deleted types/relations.
  4. +
  5. Configure the application to start using the new model ID.
  6. +
  7. Delete the tuples for the deleted type/relations. While not required, doing so can improve performance. Invalid tuples will be ignored during query evaluation, but their presence may slow down the process if they need to be retrieved.
  8. +
+

To rename a type or relation

+
    +
  • This document describes an end-to-end example for that use case.
  • +
+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/migrating/migrating-models.html.html b/pr-preview/pr-921/docs/modeling/migrating/migrating-models.html.html new file mode 100644 index 000000000..822e865ed --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/migrating/migrating-models.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/migrating/migrating-relations.html b/pr-preview/pr-921/docs/modeling/migrating/migrating-relations.html new file mode 100644 index 000000000..30eec0719 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/migrating/migrating-relations.html @@ -0,0 +1,76 @@ + + + + + +Migrating Relations | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Migrating Relations

+ +

In the lifecycle of software development, you will need to make updates or changes to the authorization model. In this guide, you will learn best practices for changing your existing authorization model. With these recommendations, you will minimize downtime and ensure your relationship models stay up to date.

+

Before you start

+

This guide assumes you are familiar with the following OpenFGA concepts:

+
    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be defined through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • Intersection Operator: the intersection operator can be used to indicate a relationship exists if the user is in all the sets of users
  • +
+

Step by step

+

The document below is an example of a relational authorization model. In this model, you can assign users to the editor relation. The editor relation has write privileges that regular users do not.

+

In this scenario, you will migrate the following model:

+
model
schema 1.1

type document
relations
define editor: [user]
define can_edit: editor

type user
+

There are existing relationship tuples associated with editor relation.

+
[{
"user": "user:anne",
"relation": "editor",
"object": "document:roadmap"
}{
"user": "user:charles",
"relation": "editor",
"object": "document:roadmap"
}]
+

This is the authorization model that you will want to migrate to:

+
model
schema 1.1

type document
relations
define writer: [user]
define can_write: writer

type user
+
+

01. Create a backwards compatible model

+

To avoid service disruption, you will create a backwards compatible model. The backwards compatible model ensures the existing relationship tuple will still work.

+

In the example below, user:Anne still has write privileges to the document:roadmap resource.

+
model
schema 1.1

type document
relations
define editor: [user]
define writer: [user] or editor
define can_write: writer
define can_edit: writer

type user
+

Test the can_edit definition. It should produce a value of true.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_write',
object: 'document:roadmap',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_edit',
object: 'document:roadmap',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

02. Create a new relationship tuple

+

Now that you have a backwards compatible model, you can create new relationship tuples with a new relation.

+

In this example, you will add Bethany to the writer relationship.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Bethany assigned writer instead of editor
{"_description":"Bethany assigned writer instead of editor","user":"user:bethany","relation":"writer","object":"document:roadmap"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Run a check in the API for Bethany to ensure correct access.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bethany',
relation: 'can_write',
object: 'document:roadmap',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

03. Migrate the existing relationship tuples

+

Next, migrate the existing relationship tuples. The new relation makes this definition obsolete.

+

Use the read API to look up all relationship tuples.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Execute a read
const { tuples } = await fgaClient.read({

});

// tuples = [{"key": {"user":"user:anne","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"},{"key": {"user":"user:charles","relation":"editor","object":"document:planning"}, "timestamp": "2021-10-06T15:32:11.128Z"}]
+

Then filter out the tuples that do not match the object type or relation (in this case, document and editor respectively), and update the new tuples with the write relationship.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
{"user":"user:anne","relation":"writer","object":"document:roadmap"},
{"user":"user:charles","relation":"writer","object":"document:roadmap"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Finally, remove the old relationship tuples.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
deletes: [
{ user: 'user:anne', relation: 'editor', object: 'document:roadmap'},
{ user: 'user:charles', relation: 'editor', object: 'document:roadmap'}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
info

Perform a write operation before a delete operation to ensure Anne still has access.

+

Confirm the tuples are correct by running a check on the user.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_write',
object: 'document:roadmap',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

The old relationship tuple no longer exists.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'editor',
object: 'document:roadmap',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

04. Remove obsolete relationship from the model

+

After you remove the previous relationship tuples, update your authorization model to remove the obsolete relation.

+
model
schema 1.1

type document
relations
define writer: [user]
define can_write: writer

type user
+

Now, the write API will only accept the new relation name.

+ +
Transactional Writes

Learn how to perform transactional write

Relationship Queries

Understand the differences between check, read, expand and list objects.

Production Best Practices

Learn the best practices of running OpenFGA in a production environment

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/migrating/migrating-relations.html.html b/pr-preview/pr-921/docs/modeling/migrating/migrating-relations.html.html new file mode 100644 index 000000000..5391f0d34 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/migrating/migrating-relations.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/modular-models.html b/pr-preview/pr-921/docs/modeling/modular-models.html new file mode 100644 index 000000000..fd14b887e --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/modular-models.html @@ -0,0 +1,72 @@ + + + + + +Modular Models | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Modular Models

+ +

Authorization is application-specific. In an organization with multiple teams building different applications or modules, each team should be able to define and evolve their authorization policies independently.

+

Modular models allows splitting your authorization model across multiple files and modules, improving upon some of the challenges that may be faced when maintaining an authorization model within a company, such as:

+
    +
  • A model can grow large and difficult to understand.
  • +
  • As more teams begin to contribute to a model, the ownership boundaries may not be clear and code review processes might not scale.
  • +
+

With modular models, a single model can be split across multiple files in a project and organized in a way that makes sense for the project or teams collaborating on it. For example, modular models allows ownership for reviews to be expressed using a feature like GitHub's, GitLab's or Gitea's code owners.

+

Key Concepts

+

fga.mod

+

The fga.mod file is the project file for modular models. It specifies the schema version for the final combined model and lists the individual files that make up the modular model.

+
PropertyDescription
schemaThe schema version to be used for the combined model
contentsThe individual files that make up the modular model
+

Modules

+

OpenFGA modules define the types and relations for a specific application module or service.

+

Modules are declared using the module keyword in the DSL, and a module can be written across multiple files. A single file cannot have more than one module.

+

Type Extensions

+

As teams implement features, they might find that core types they are dependent upon might not contain all the relations they need. However, it might not make sense for these relations to be owned by the owner of that type if they aren't needed across the system.

+

Modular models solves that problem by allowing individual types to be extended within other modules to to share those relations.

+

The following are requirements for type extension:

+
    +
  • The extended type must exist
  • +
  • A single type can only be extended once per file
  • +
  • The relations added must not already exist, or be part of another type extension
  • +
+

Example

+

The following example shows how an authorization model for a SaaS compny with a issue tracking and wiki software can implement modular models.

+

Core

+

If there is a core set of types owned by a team that manages the overall identity for the company, the following provides the basics: users, organizations and groups that can be used by each product area.

+
module core

type user

type organization
relations
define member: [user]
define admin: [user]

type group
relations
define member: [user]
+

Issue tracking

+

The issue tracking software separates out the project- and issue-related types into separate files. Below, we also extend the organization type to add a relation specific to the issue tracking feature: the ability to authorize who can create a project.

+
module issue-tracker

extend type organization
relations
define can_create_project: admin

type project
relations
define organization: [organization]
define viewer: member from organization
+
module issue-tracker

type ticket
relations
define project: [project]
define owner: [user]
+

Wiki

+

The wiki model is managed in one file until it grows. We can also extend the organization type again to add a relation tracking who can create a space.

+
module wiki

extend type organization
relations
define can_create_space: admin


type space
relations
define organization: [organization]
define can_view_pages: member from organization

type page
relations
define space: [space]
define owner: [user]
+

fga.mod

+

To deploy this model, create the fga.mod manifest file, set a schema version, and list the individual module files that comprise the model.

+
schema: '1.2'
contents:
- core.fga
- issue-tracker/projects.fga
- issue-tracker/tickets.fga
- wiki.fga
+

Putting it all together

+

With individual parts of the modular model in place, write the model to OpenFGA and run tests against it. Below is an example of what to run in the CLI:

+
fga model write --store-id=$FGA_STORE_ID --file fga.mod
+

This model can now be queried and have tuples written to it, just like a singular file authorization model.

+

await fgaClient.write({
writes: [
{"user":"user:anne","relation":"admin","object":"organization:acme"},
{"user":"organization:acme","relation":"organization","object":"space:acme"},
{"user":"organization:acme","relation":"organization","object":"project:acme"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_create_space',
object: 'organization:acme',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

Viewing the model

+

When using the CLI to view the combined model DSL with fga model get --store-id=$FGA_STORE_ID, the DSL is annotated with comments defining the source module and file for types, relations and conditions.

+

For example, the organization type shows that the type is defined in the core.fga file as part of the core module, the can_create_project relation is defined in issue-tracker/projects.fga as part of the issuer-tracker module, and the can_create_space relation is defined in the wiki.fga file as part of the wiki module.

+
type organization # module: core, file: core.fga
relations
define admin: [user]
define member: [user] or admin
define can_create_project: admin # extended by: module: issue-tracker, file: issue-tracker/projects.fga
define can_create_space: admin # extended by: module: wiki, file: wiki.fga
+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/modular-models.html.html b/pr-preview/pr-921/docs/modeling/modular-models.html.html new file mode 100644 index 000000000..1286e01e8 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/modular-models.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/multiple-restrictions.html b/pr-preview/pr-921/docs/modeling/multiple-restrictions.html new file mode 100644 index 000000000..6c22c310a --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/multiple-restrictions.html @@ -0,0 +1,74 @@ + + + + + +Multiple Restrictions | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Multiple Restrictions

+ +

In this guide we are going to model system that requires multiple authorizations before allowing users to perform actions on particular objects using OpenFGA. +For example, users are allowed to delete a document if both of these conditions are met:

+
    +
  • they are a member of the organization that owns the document
  • +
  • they have writer permissions on the document
  • +
+

In this way, we prevent other users from deleting such document.

+
When to use

This is useful when:

    +
  • Limiting certain actions (such as deleting or reading sensitive document) to privileged users.
  • +
  • Adding restrictions and requiring multiple authorization paths before granting access.
  • +
+

Before You Start

+

In order to understand this guide correctly you must be familiar with some OpenFGA Concepts and know how to develop the things that we will list below.

+

You will start with the authorization model below, +it represents a document type that can have users +related as writer and organizations related as owner. +Document's can_write relation is based on whether user is a writer to the document. The organization type can have users related as member.

Let us also assume that we have:

    +
  • A document called "planning" owned by the ABC organization.
  • +
  • Becky is a member of the ABC organization.
  • +
  • Carl is a member of the XYZ organization.
  • +
  • Becky and Carl both have writer access to the "planning" document.
  • +
model
schema 1.1

type user

type document
relations
define owner: [organization]
define writer: [user]
define can_write: writer

type organization
relations
define member: [user]

The current state of the system is represented by the following relationship tuples being in the system already:

[// organization ABC is the owner of planning document
{
"_description": "organization ABC is the owner of planning document",
"user": "organization:ABC",
"relation": "owner",
"object": "document:planning"
}// Becky is a writer to the planning document
{
"_description": "Becky is a writer to the planning document",
"user": "user:becky",
"relation": "writer",
"object": "document:planning"
}// Carl is a writer to the planning document
{
"_description": "Carl is a writer to the planning document",
"user": "user:carl",
"relation": "writer",
"object": "document:planning"
}// Becky is a member of the organization ABC
{
"_description": "Becky is a member of the organization ABC",
"user": "user:becky",
"relation": "member",
"object": "organization:ABC"
}// Carl is a member of the organization XYZ
{
"_description": "Carl is a member of the organization XYZ",
"user": "user:carl",
"relation": "member",
"object": "organization:XYZ"
}]
info

Note that we assign the organization, not the organization's members, as owner to the planning document.


In addition, you will need to know the following:

Modeling Parent-Child Objects

You need to know how to model access based on parent-child relationships, e.g.: folders and documents. Learn more →

Modeling Roles And Permissions

You need to know how to model roles for users at the object level and model permissions for those roles. Learn more →

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • Intersection Operator: the intersection operator can be used to indicate a relationship exists if the user is in all the sets of users
  • +
+

Step By Step

+

With the above authorization model and relationship tuples, OpenFGA will correctly respond with {"allowed":true} when *check*is called to see if Carl and Becky can write this document.

+

We can verify that by issuing two check requests:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:becky',
relation: 'can_write',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:carl',
relation: 'can_write',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

What we would like to do is offer a way so that a document can be written by Becky and Carl, but only writers who are also members of the organization that owns the document can remove it.

+

To do this, we need to:

+
    +
  1. Add can_delete relation to only allow writers that are members of the ownership organization
  2. +
  3. Verify that our solutions work
  4. +
+

01. Add can_delete Relation To Only Allow Writers That Are Members Of The Ownership Organization

+

The first step is to add the relation definition for can_delete so that it requires users to be both writer and member of the owner. This is accomplished via the keyword and.

+
model
schema 1.1

type user

type document
relations
define owner: [organization]
define writer: [user]
define can_write: writer
define can_delete: writer and member from owner

type organization
relations
define member: [user]
+

02. Verify That Our Solutions Work

+

To verify that our solutions work, we need to check that Becky can delete the planning document because she is a writer AND she is a member of organization:ABC that owns the planning document.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:becky',
relation: 'can_delete',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

However, Carl cannot delete the planning document because although he is a writer, Carl is not a member of organization:ABC that owns the planning document.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:carl',
relation: 'can_delete',
object: 'document:planning',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+ +
Modeling: User Groups

Learn about how to add group members.

Modeling: Blocklists

Learn about how to set block lists.

Modeling: Public Access

Learn about model public access.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/multiple-restrictions.html.html b/pr-preview/pr-921/docs/modeling/multiple-restrictions.html.html new file mode 100644 index 000000000..417769521 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/multiple-restrictions.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/organization-context-authorization.html b/pr-preview/pr-921/docs/modeling/organization-context-authorization.html new file mode 100644 index 000000000..08dc5b869 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/organization-context-authorization.html @@ -0,0 +1,159 @@ + + + + + +Authorization Through Organization Context | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Authorization Through Organization Context

+ +

This section tackles cases where a user may have access to a particular resource through their presence in a particular organization, and they should have that access only when logged in within the context of that organization.

+
When to use

Contextual Tuples should be used when modeling cases where a user's access to an object depends on the context of their request. For example:

    +
  • An employee’s ability to access a document when they are connected to the organization VPN or the api call is originating from an internal IP address.
  • +
  • A support engineer is only able to access a user's account during office hours.
  • +
  • If a user belongs to multiple organizations, they are only able to access a resource if they set a specific organization in their current context.
  • +
+

Before You Start

+

To follow this guide, you should be familiar with some OpenFGA Concepts.

+

OpenFGA Concepts

+
    +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • A Check Request: is a call to the OpenFGA check endpoint that returns whether the user has a certain relationship with an object.
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • A Contextual Tuple: a tuple that can be added to a check request, and only exist within the context of that particular request.
  • +
+

You also need to be familiar with:

+
    +
  • Modeling Object-to-Object Relationships: You need to know how to create relationships between objects and how that might affect a user's relationships to those objects. Learn more →
  • +
  • Modeling Multiple Restrictions: You need to know how to model requiring multiple authorizations before allowing users to perform certain actions. Learn more →
  • +
+ +

Scenario

+

For the scope of this guide, we are going to consider the following scenario.

+

Consider you are building the authorization model for a multi-tenant project management system.

+

In this particular system:

+
    +
  • projects are owned and managed by companies
  • +
  • users can be members of multiple companies
  • +
  • project access is governed by the user's role in the organization that manages the project
  • +
+

In order for a user to access a project:

+
    +
  • The project needs to be managed by an organization the user is a member of
  • +
  • A project is owned by a single organization
  • +
  • A project can be shared with partner companies (that are able to view, edit but not perform admin actions, such as deletion, on the project)
  • +
  • The user should have a role that grants access to the project
  • +
  • The user should be logged in within the context of that organization
  • +
+

We will start with the following authorization model:

+
model
schema 1.1

type user

type organization
relations
define member: [user]
define project_manager: [user]
define project_editor: [user]

type project
relations
define owner: [organization]
define partner: [organization]
define manager: project_manager from owner
define editor: project_editor from owner or project_editor from partner or manager
define can_delete: manager
define can_edit: editor
define can_view: editor
+

We are considering the case that:

    +
  • Anne has a project manager role at organizations A, B and C
  • +
  • Beth has a project manager role at organization B
  • +
  • Carl has a project manager role at organization C
  • +
  • Project X is owned by organization A
  • +
  • Project X is shared with organization B
  • +

The above state translates to the following relationship tuples:


await fgaClient.write({
writes: [
// Anne has a `project manager` role at organization A
{"_description":"Anne has a `project manager` role at organization A","user":"user:anne","relation":"project_manager","object":"organization:A"},
// Anne has a `project manager` role at organization B
{"_description":"Anne has a `project manager` role at organization B","user":"user:anne","relation":"project_manager","object":"organization:B"},
// Anne has a `project manager` role at organization C
{"_description":"Anne has a `project manager` role at organization C","user":"user:anne","relation":"project_manager","object":"organization:C"},
// Beth has a `project manager` role at organization B
{"_description":"Beth has a `project manager` role at organization B","user":"user:anne","relation":"project_manager","object":"organization:B"},
// Carl has a `project manager` role at organization C
{"_description":"Carl has a `project manager` role at organization C","user":"user:carl","relation":"project_manager","object":"organization:C"},
// Organization A owns Project X
{"_description":"Organization A owns Project X","user":"organization:A","relation":"owner","object":"project:X"},
// Project X is shared with Organization B
{"_description":"Project X is shared with Organization B","user":"organization:B","relation":"partner","object":"project:X"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Requirements

+
    +
  • When logging in within the context of organization A, Anne should be able to view and delete project X.
  • +
  • When logging in within the context of organization B, Anne should be able to view, but not delete, project X.
  • +
  • When logging in within the context of organization C, Anne should not be able to view nor delete project X.
  • +
  • When logging in within the context of organization B, Beth should be able to view, but not delete, project X.
  • +
  • Carl should not be able to view nor delete project X.
  • +
+

Step By Step

+

In order to solve for the requirements above, we will break the problem down into three steps:

+
    +
  1. Understand relationships without contextual tuples. For example, we need to ensure that Anne can view and delete "Project X".
  2. +
  3. Take organization context into consideration. This includes extending the authorization model and a temporary step of adding the required tuples to mark that Anne is in an approved context.
  4. +
  5. Use contextual tuples for context related checks.
  6. +
+

Understand Relationships Without Contextual Data

+

With the authorization model and relationship tuples shown above, OpenFGA has all the information needed to ensure that Anne can view and delete "Project X".

+

We can verify that using the following checks:

+
    +
  • Anne can view Project X +

    // Run a check
    const { allowed } = await fgaClient.check({
    user: 'user:anne',
    relation: 'can_view',
    object: 'project:X',
    }, {
    authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
    });

    // allowed = true
    +
  • +
  • Anne can delete Project X +

    // Run a check
    const { allowed } = await fgaClient.check({
    user: 'user:anne',
    relation: 'can_delete',
    object: 'project:X',
    }, {
    authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
    });

    // allowed = true
    +
  • +
+
More checks
    +
  • Beth can view Project X
  • +

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:beth',
relation: 'can_view',
object: 'project:X',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
    +
  • Beth cannot delete Project X
  • +

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:beth',
relation: 'can_delete',
object: 'project:X',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
    +
  • Carl cannot view Project X
  • +

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:carl',
relation: 'can_view',
object: 'project:X',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
    +
  • Carl cannot delete Project X
  • +

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:carl',
relation: 'can_delete',
object: 'project:X',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

Note that so far, we have not prevented Anne from viewing "Project X" even if Anne is viewing it from the context of Organization C.

+

Take Organization Context Into Consideration

+
Extend The Authorization Model
+

In order to add a restriction based on the current organization context, we will make use of OpenFGA configuration language's support for intersection to specify that a user has to both have access and be in the correct context in order to be authorized.

+

We can do that by introducing some new relations and updating existing relation definitions:

+
    +
  1. On the "organization" type
  2. +
+
    +
  • Add "user_in_context" relation to mark that a user's access is being evaluated within that particular context
  • +
  • Update the "project_manager" relation to require that the user be in the correct context (by adding and user_in_context to the relation definition)
  • +
  • Considering that OpenFGA does not yet support multiple logical operations within the same definition, we will split "project_editor" into two: +
      +
    • "base_project_editor" editor which will contain the original relation definition ([user] or project_manager)
    • +
    • "project_editor" which will require that a user has both the "base_project_editor" and the "user_in_context" relations
    • +
    +
  • +
+

The "organization" type definition then becomes:

+

type organization
relations
define member: [user]
define project_manager: [user] and user_in_context
define base_project_editor: [user] or project_manager
define project_editor: base_project_editor and user_in_context
define user_in_context: [user]
+
    +
  1. On the "project" type
  2. +
+
    +
  • Nothing will need to be done, as it will inherit the updated "project_manager" and "project_editor" relation definitions from "organization"
  • +
+
Add The Required Tuples To Mark That Anne Is In An Approved Context
+

Now that we have updated our authorization model to take the current user's organization context into consideration, you will notice that Anne has lost access because nothing indicates that Anne is authorizing from the context of an organization. You can verify that by issuing the following check:

+

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'project:X',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

In order for Anne to be authorized, a tuple indicating Anne's current organization context will need to be present:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Anne is authorizing from the context of organization:A
{"_description":"Anne is authorizing from the context of organization:A","user":"user:anne","relation":"user_in_context","object":"organization:A"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

We can verify this by running a check request

+

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'project:X',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+ +

Now that we know we can authorize based on present state, we have a different problem to solve. We are storing the tuples in the state in order for OpenFGA to evaluate them, which fails in certain use-cases where Anne can be connected to two different contexts in different browser windows at the same time, as each has a different context at the same time, so if they are written to the state, which will OpenFGA use to compute Anne's access to the project?

+

For Check calls, OpenFGA has a concept called "Contextual Tuples". Contextual Tuples are tuples that do not exist in the system state and are not written beforehand to OpenFGA. They are tuples that are sent alongside the Check request and will be treated as if they already exist in the state for the context of that particular Check call. That means that Anne can be using two different sessions, each within a different organization context, and OpenFGA will correctly respond to each one with the correct authorization decision.

+

First, we will undo the temporary step and remove the stored tuples for which Anne has a user_in_context relation with organization:A.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
deletes: [
// Delete stored tuples where Anne is authorizing from the context of organization:A
{ user: 'user:anne', relation: 'user_in_context', object: 'organization:A'}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Next, when Anne is connecting from the context of organization A, OpenFGA will return {"allowed":true}:

+

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'project:X',
contextualTuples: [
{"_description":"Anne is authorizing from the context of organization:A","user":"user:anne","relation":"user_in_context","object":"organization:A"}
],
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

When Anne is connecting from the context of organization C, OpenFGA will return {"allowed":false}:

+

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:anne',
relation: 'can_view',
object: 'project:X',
contextualTuples: [
{"_description":"Anne is authorizing from the context of organization:A","user":"user:anne","relation":"user_in_context","object":"organization:C"}
],
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

Using this, you can check that the following requirements are satisfied:

+
UserOrganization ContextActionAllowed
AnneOrganization AViewYes
AnneOrganization BViewYes
AnneOrganization CViewYes
AnneOrganization ADeleteYes
AnneOrganization BDeleteNo
AnneOrganization CDeleteNo
BethOrganization BViewYes
BethOrganization BDeleteNo
CarlOrganization CViewNo
CarlOrganization CDeleteNo
+

Summary

+

Final version of the Authorization Model and Relationship tuples

model
schema 1.1

type user

type organization
relations
define member: [user]
define project_manager: [user] and user_in_context
define base_project_editor: [user] or project_manager
define project_editor: base_project_editor and user_in_context
define user_in_context: [user]

type project
relations
define owner: [organization]
define partner: [organization]
define manager: project_manager from owner
define editor: manager or project_editor from owner or project_editor from partner
define can_delete: manager
define can_edit: editor
define can_view: editor

await fgaClient.write({
writes: [
// Anne has a `project manager` role at organization A
{"_description":"Anne has a `project manager` role at organization A","user":"user:anne","relation":"project_manager","object":"organization:A"},
// Anne has a `project manager` role at organization B
{"_description":"Anne has a `project manager` role at organization B","user":"user:anne","relation":"project_manager","object":"organization:B"},
// Anne has a `project manager` role at organization C
{"_description":"Anne has a `project manager` role at organization C","user":"user:anne","relation":"project_manager","object":"organization:C"},
// Beth has a `project manager` role at organization B
{"_description":"Beth has a `project manager` role at organization B","user":"user:beth","relation":"project_manager","object":"organization:B"},
// Carl has a `project manager` role at organization C
{"_description":"Carl has a `project manager` role at organization C","user":"user:carl","relation":"project_manager","object":"organization:C"},
// Organization A owns Project X
{"_description":"Organization A owns Project X","user":"organization:A","relation":"owner","object":"project:X"},
// Project X is shared with Organization B
{"_description":"Project X is shared with Organization B","user":"organization:B","relation":"partner","object":"project:X"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
Warning

Contextual tuples:

+ +
Modeling with Multiple Restrictions

Learn how to model requiring multiple relationships before users are authorized to perform certain actions.

Contextual and Time-Based Authorization

Learn how to authorize access that depends on dynamic or contextual criteria.

OpenFGA Check API

Details on the Check API in the OpenFGA reference guide.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/organization-context-authorization.html.html b/pr-preview/pr-921/docs/modeling/organization-context-authorization.html.html new file mode 100644 index 000000000..40438c00d --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/organization-context-authorization.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/parent-child.html b/pr-preview/pr-921/docs/modeling/parent-child.html new file mode 100644 index 000000000..c87c3818b --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/parent-child.html @@ -0,0 +1,93 @@ + + + + + +Parent-Child Objects | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Parent-Child Objects

+ +

In OpenFGA, a user's relationship with an object can affect their relationship with another object. For example, an editor of a folder can also be an editor of all documents that folder is a parent of.

+
When to use

Object-to-object relationships can combine with a configured authorization model to indicate that a user's relationship with one object may influence the user's relationship with another object. They can also eliminate the need to modify relationships between objects using user groups.

The follow are examples of simple object-to-object relationships:

    +
  • managers of an employee have access to approve requests the employee has made
  • +
  • users who have a repository admin role (repo_admin) in an organization automatically have admin access to all repositories in that organization
  • +
  • users who are subscribed to a plan get access to all the features in that plan
  • +
+

Before you start

+

Familiarize yourself with basic OpenFGA Concepts:

+

Assume that you have the following authorization model.
+You have two types:

    +
  • folder that users can be related to as an editor
  • +
  • document that users can be related to as an editor
  • +
model
schema 1.1

type user

type folder
relations
define editor: [user]

type document
relations
define editor: [user]

In addition:

Direct access

Creating an authorization model and a relationship tuple can grant a user access to an object. To learn more, read about Direct Access

OpenFGA concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a group stored in OpenFGA that consists of a user, a relation, and an object
  • +
  • Union Operator: can be used to indicate that the user has multiple ways of being related to an object
  • +
+ +

Step by step

+

The following walkthrough models (a) folders that contain documents and (b) that a user who has editor access to a given folder has editor access to all documents in that folder.

+

For editors of a folder to be editors of a containing document, you must:

+
    +
  1. Update the authorization model to allow a parent relationship between folder and document
  2. +
  3. Update the editor relation in the document type definition to support cascading from folder
  4. +
+

The following three steps indicate and verify that bob is an editor of document:meeting_notes.doc because bob is an editor of folder:notes:

+
    +
  1. Create a new relationship tuple to indicate that bob is a editor of folder:notes
  2. +
  3. Create a new relationship tuple to indicate that folder:notes is a parent of document:meeting_notes.doc
  4. +
  5. Check to see if bob is an editor of document:meeting_notes.doc
  6. +
+

01. Update the Athorization Model to allow a parent relationship between folder and document

+

As documented in Modeling Concepts: Object to Object Relationships, the following update to the authorization model allows a parent relation between a folder and a document:

+
model
schema 1.1

type user

type folder
relations
define editor: [user]

type document
relations
define parent: [folder]
define editor: [user]
+
info

The document type now has a parent relation, indicating that other objects can be parents of documents

+

02. Update the editor relation in the document type definition to support cascading from folder

+

To allow cascading relations between folder and document, update the authorization model:

+
model
schema 1.1

type user

type folder
relations
define editor: [user]

type document
relations
define parent: [folder]
define editor: [user] or editor from parent
+
info

editor of a document can be the following:

    +
  1. users that are directly assigned as editors
  2. +
  3. users that are related to any parent of this document as editor (editors of the parent)
  4. +
+

After making these changes, anyone related to a folder that is a parent of a document as an editor is also an editor of that document.

+

03. Create a new relationship tuple to indicate that bob is an editor of folder:notes

+

To leverage the new cascading relation, create a relationship tuple stating that bob is an editor of folder:notes

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
{"user":"user:bob","relation":"editor","object":"folder:notes"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
caution

Note: Use unique ids for each object and user within your application domain when creating relationship tuples for OpenFGA. We use first names and simple ids below as an easy-to-follow example.

+

04. Create a new relationship tuple to indicate that folder:notes is a parent of document:meeting_notes.doc

+

Now that bob is an editor of folder:notes, we need to indicate that folder:notes is a parent of document:meeting_notes.doc

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// the notes folder is a parent of the meeting notes document
{"_description":"the notes folder is a parent of the meeting notes document","user":"folder:notes","relation":"parent","object":"document:meeting_notes.doc"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

05. Check if bob is an editor of document:meeting_notes.doc

+

After changing the authorization model and adding two new relationship tuples, verify that your configuration is correct by running the following check: is bob an editor of document:meeting_notes.doc.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'editor',
object: 'document:meeting_notes.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+
+

Note: There are no other relationship tuples in the store that dictate a direct relation between bob and document:meeting_notes.doc. The check succeeds because of the cascading relation.

+
+

The chain of resolution is:

+
    +
  • bob is an editor of folder:notes
  • +
  • folder:notes is a parent of document:meeting_notes.doc
  • +
  • editors of any parent folder of document:meeting_notes.doc are also editors of the document
  • +
  • therefore bob is an editor of document:meeting_notes.doc
  • +
+
caution

When searching tuples that are related to the object (the word after from, also called the tupleset), OpenFGA will not do any evaluation and only considers concrete objects (of the form <object_type>:<object_id>) that were directly assigned. OpenFGA will throw an error if it encounters any rewrites, a *, a type bound public access (<object_type>:*), or a userset (<object_type>:<object_id>#<relation>).

For more information on this topic, see Referencing Relations on Related Objects.

+ +
Modeling Concepts: Object to Object Relationships

Learn about how to model object to object relationships in OpenFGA.

Modeling Google Drive

See how to make folders parents of documents, and to make editors on the parent folders editors on documents inside them..

Modeling GitHub

See how to grant users access to all repositories owned by an organization.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/parent-child.html.html b/pr-preview/pr-921/docs/modeling/parent-child.html.html new file mode 100644 index 000000000..9c99ba317 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/parent-child.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/public-access.html b/pr-preview/pr-921/docs/modeling/public-access.html new file mode 100644 index 000000000..372373c77 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/public-access.html @@ -0,0 +1,57 @@ + + + + + +Public Access | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Public Access

+ +

In this guide you will learn how to grant public access to an object, such as a certain document, using type bound public access.

+
When to use

Public access allows your application to grant every user in the system access to an object. You would add a relationship tuple with type-bound public access when:

    +
  • sharing a document publicly to indicate that everyone can view it
  • +
  • a public poll is created to indicate that anyone can vote on it
  • +
  • a blog post is published and anyone should be able to read it
  • +
  • a video is made public for anyone to watch
  • +
+

Before You Start

+

In order to understand this guide correctly you must be familiar with some OpenFGA Concepts and know how to develop the things that we will list below.

+

Assume that you have the following authorization model.
+You have a type called document that can have a view relation.

model
schema 1.1

type user

type document
relations
define view: [user, user:*]

In addition, you will need to know the following:

Direct Access

You need to know how to create an authorization model and create a relationship tuple to grant a user access to an object. Learn more →

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
  • A Type Bound Public Access: is a special OpenFGA concept (represented by <type>:*) can be used in relationship tuples to represent every object of that type
  • +
+
caution

Make sure to use unique ids for each object and user within your application domain when creating relationship tuples for OpenFGA. We are using first names and simple ids to just illustrate an easy-to-follow example.

+ +

Step By Step

+

In previous guides, we have shown how to indicate that objects are related to users or objects. In some cases, you might want to indicate that everyone is related to an object (for example when sharing a document publicly).

+

01. Create A Relationship Tuple

+

To do this we need to create a relationship tuple using the type bound public access. The type bound public access syntax is used to indicate that all users of a particular type have a relation to a specific object.

+

Let us create a relationship tuple that states: any user can view document:company-psa.doc

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// user:* denotes every object of type user
{"_description":"user:* denotes every object of type user","user":"user:*","relation":"view","object":"document:company-psa.doc"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+
Wildcard syntax usage

Please note that type-bound public access is not a wildcard or a regex expression.

You cannot use the <type>:* syntax in the tuple's object field.

The following syntax is invalid:

[// It is invalid to use this syntax in the object field. The below relationship tuple is invalid and does not mean that Bob can view all documents.
{
"_description": "It is invalid to use this syntax in the object field. The below relationship tuple is invalid and does not mean that Bob can view all documents.",
"user": "user:bob",
"relation": "view",
"object": "document:*"
}]
+
Wildcard syntax usage

You cannot use <type>:* as part of a userset in the tuple's user field.

The following syntax is invalid:

[// It is invalid to use this syntax as part of a userset. The below relationship tuple is invalid and does not mean that members of any org can view the company-psa document.
{
"_description": "It is invalid to use this syntax as part of a userset. The below relationship tuple is invalid and does not mean that members of any org can view the company-psa document.",
"user": "org:*#member",
"relation": "view",
"object": "document:company-psa.doc"
}]
+

02. Check That The Relationship Exists

+

Once the above relationship tuple is added, we can check if bob cab view document:company-psa.doc. OpenFGA will return { "allowed": true } even though no relationship tuple linking bob to the document was added. That is because the relationship tuple with user:* as the user made it so every object of type user (such as user:bob) can view the document, making it public.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'view',
object: 'document:company-psa.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+ +
Modeling: Getting Started

Learn about how to get started with modeling.

Configuration Language

Learn about OpenFGA Configuration Language.

Modeling Blocklists

Learn about model block lists.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/public-access.html.html b/pr-preview/pr-921/docs/modeling/public-access.html.html new file mode 100644 index 000000000..bd5d8acd8 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/public-access.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/roles-and-permissions.html b/pr-preview/pr-921/docs/modeling/roles-and-permissions.html new file mode 100644 index 000000000..4cb1f3e28 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/roles-and-permissions.html @@ -0,0 +1,100 @@ + + + + + +Roles and Permissions | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Roles and Permissions

+ +

Roles and permissions can be modeled within OpenFGA using an authorization model and relationship tuples.

+
    +
  • Roles are assigned to users or a group of users. Any user can have more than one role, like editor or owner.
  • +
  • Permissions allow users to access certain objects based on their specific roles, like device_renamer or channel_archiver.
  • +
+

For example, the role viewer of a trip can have permissions to view bookings, while the role owners can have permissions to add or view trip bookings.

+
When to use a Roles and Permissions model

Role and permissions models in OpenFGA can both directly assign roles to users and assign permissions through relations users receive downstream from other relations. For example, you can:

    +
  • Grant someone an admin role that can edit and read a document
  • +
  • Grant someone a security_guard role that can live_video_viewer on a device
  • +
  • Grant someone a viewer role that can view_products on a shop
  • +

Implementing a Roles and Permissions model allows existing roles to have finer-grained permissions, allowing your application to check whether a user has access to a certain object without having to explicitly check that specific users role. In addition, you can add new roles/permissions or consolidate roles without affecting your application behavior. For example, if your app's checks are for the fine permissions, like check('bob', 'booking_adder', 'trip:Europe') instead of check('bob', 'owner', 'trip:Europe'), and you later decide owners can no longer add bookings to a trip, you can remove the relation within the trip type with no code changes in your application and all permissions will automatically honor the change.

+

Before you start

+

Familiarize yourself with the basics of OpenFGA Concepts.

+

Assume that you have the following authorization model and a type called trip that users can be related to as viewer and/or an owner.

model
schema 1.1

type user

type trip
relations
define owner: [user]
define viewer: [user]

In addition, you need to know the following:

Direct Access

Creating an authorization model and a relationship tuple can grant a user access to an object. To learn more, read about Direct Access

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics
  • +
  • A User: an entity in the system that can be related to an object
  • +
  • A Relation: a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be define through relationship tuples and the authorization model
  • +
  • A Relationship Tuple: a group stored in OpenFGA that consists of a user, a relation, and an object
  • +
  • A Relationship: OpenFGA will be called to check if there is a relationship between a user and an object, indicating that the access is allowed
  • +
  • Union Operator: can be used to indicate that the user has multiple ways of being related to an object
  • +
  • Direct Relationship Type Restrictions: can be used to indicate direct relationships between users and objects
  • +
  • A Check API Request: used to check for relationships between users and objects
  • +
+ +

Step by step

+

The Roles and Permissions example below is a trip booking system that has owners and/or viewers, both of which can have more granular permissions like adding bookings to a trip or viewing a trip's bookings.

+

To represent this in an OpenFGA environment, you need to:

+
    +
  1. Understand how roles are related to direct relations for the trip booking system
  2. +
  3. Add implied relations to the existing authorization model to define permissions for bookings
  4. +
  5. Check user roles and their permissions based on relationship +tuples for direct and implied relations
  6. +
+

01. Understand how roles work within the trip booking system

+

Roles are relations that are directly assigned to users. Below, the stated roles that a given user can be assigned are owner and viewer.

+
model
schema 1.1

type user

type trip
relations
define owner: [user]
define viewer: [user]
+

02. Add permissions for bookings

+

Permissions are relations that users get through other relations. To avoid adding a direct relationship type restriction to the relation in the authorization model while representing permissions, they instead define the relation via other relations in the model, which indicates that it is a permission granted to and implied from a different relation.

+

To add permissions related to bookings, add new relations to the trip object type denoting the various actions a user can take on trips, like view, edit, delete, or rename.

+

To allow viewers of a trip to have permissions to view bookings and owners to have permissions to add/view bookings, you modify the type:

+
model
schema 1.1

type user

type trip
relations
define owner: [user]
define viewer: [user]
define booking_adder: owner
define booking_viewer: viewer or owner
+
+

Note: both booking_viewer and booking_adder don't have direct relationship type restrictions, which ensures that the relation can only be assigned through the role and not directly.

+
+

03. Check user roles and their permissions

+

Your type definitions reflects the roles and permissions on how bookings can be viewed/added, so you can create relationship tuples to assign roles to users, then check if users have the proper permissions.

+

Create two relationship tuples:

+
    +
  1. give bob the role of viewer on trip called Europe.
  2. +
  3. give alice the role of owner on trip called Europe.
  4. +
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Add bob as viewer on trip:Europe
{"_description":"Add bob as viewer on trip:Europe","user":"user:bob","relation":"viewer","object":"trip:Europe"},
// Add alice as owner on trip:Europe
{"_description":"Add alice as owner on trip:Europe","user":"user:alice","relation":"owner","object":"trip:Europe"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Now check: is bob allowed to view bookings on trip Europe?

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'booking_viewer',
object: 'trip:Europe',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

bob is a booking_viewer because of the following chain of resolution:

+
    +
  1. bob is a viewer on trip: Europe
  2. +
  3. Any user related to the object trip:Europe as viewer is also related as a booking_viewer (i.e usersRelatedToObjectAs: viewer)
  4. +
  5. Therefore, all viewers on a given trip are booking_viewers
  6. +
+

To confirm that bob is not allowed to add bookings on trip Europe, run the following check:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:bob',
relation: 'booking_adder',
object: 'trip:Europe',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = false
+

You also check: is alice allowed to view and add bookings on trip Europe?

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:alice',
relation: 'booking_viewer',
object: 'trip:Europe',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:alice',
relation: 'booking_adder',
object: 'trip:Europe',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

alice is a booking_viewer and booking_adder because of the following chain of resolution:

+
    +
  1. alice is a owner on trip: Europe
  2. +
  3. Any user related to the object trip:Europe as owner is also related as a booking_viewer
  4. +
  5. Any user related to the object trip:Europe as owner is also related as a booking_adder
  6. +
  7. Therefore, all owners on a given trip are booking_viewers and booking_adders on that trip
  8. +
+
caution

Use unique ids for each object and user within your application domain when creating relationship tuples for OpenFGA. This example first names and simple ids as an easy-to-follow example.

+ +
Modeling Concepts: Concentric Relationships

Learn about how to represent a concentric relationships in OpenFGA.

Modeling Google Drive

See how to indicate that editors are commenters and viewers in Google Drive.

Modeling GitHub

See how to indicate that repository admins are writers and readers in GitHub.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/roles-and-permissions.html.html b/pr-preview/pr-921/docs/modeling/roles-and-permissions.html.html new file mode 100644 index 000000000..8e507ea6e --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/roles-and-permissions.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/testing.html b/pr-preview/pr-921/docs/modeling/testing.html new file mode 100644 index 000000000..18c4866f2 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/testing.html @@ -0,0 +1,69 @@ + + + + + +Testing Models | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Testing Models

+ +

Every OpenFGA model should be tested before deployment to ensure your authorization model is correctly designed.

+

The .fga.yaml contains tests for OpenFGA authorization models. If you are using Visual Studio Code as your IDE, install the OpenFGA extension to enable syntax coloring and validation.

+

Define the model and tuples

+

.fga.yaml files have the following top level items:

+
ObjectDescription
name (optional)A descriptive name for the test file
model or model_fileAn OpenFGA model or a reference to an external model file in fga or json format
tuples or tuple_file (optional)A set of tuples or a reference to an external tuple file in json, yaml or csv format. These are considered for all tests.
testsA set of tests that verify the return values of OpenFGA API calls
+

The example below defines a model and tuples:

+
name: Model Tests # optional

# model_file: ./model.fga # you can specify an external .fga file, or include it inline
model: |
model
schema 1.1

type user

type organization
relations
define member : [user]
define admin : [user with non_expired_grant]

condition non_expired_grant(current_time: timestamp, grant_time: timestamp, grant_duration: duration) {
current_time < grant_time + grant_duration
}

# tuple_file: ./tuples.yaml # you can specify an external file, or include it inline
tuples:

# Anne is a member of the Acme organization
- user: user:anne
relation: member
object: organization:acme

# Peter has the admin role from February 2nd 2024 0AM to 1AM
- user: user:peter
relation: admin
object: organization:acme
condition:
name: non_expired_grant
context:
grant_time : "2024-02-01T00:00:00Z"
grant_duration : 1h

+

Write tests

+

Always write tests to verify that the calls your application will make return the results you expect. A good test covers scenarios that verify every relation.

+

Tests have the following structure:

+
ObjectDescription
name (optional)A descriptive name for the test, like “Organization Membership”
tuplesA set of tuples that are only considered for the test
checkA set of tests for Check calls, each with a user/object and a set of assertions
list_objectsA set of tests for ListObjects calls, each one with a user/type and a set of assertions for any number of relations
list_usersA set of tests for ListUsers calls, each one with an object and user filter and a set of assertions for the users for any number of relations
+

Write Check tests

+

Check tests verify the results of the check API calls to validate access requirements for a user. Each check verification has the following structure:

+
ObjectDescription
userThe user type and user id you are checking for access
objectThe object type and object id related to the user
contextA set of tests for contextual parameters used to evaluate conditions
assertionsA list of relation:expected-result pairs
<relation>: <true or false>The name of the relation you want to verify and the expected result
+

The following example adds multiple check verifications in every test:

+
tests:
- name: Test
check:
- user: user:anne
object: organization:acme
assertions:
member: true
admin: false

- user: user:peter
object: organization:acme
context:
current_time : "2024-02-01T00:10:00Z"
assertions:
member: false
admin: true
+

Write List Objects tests

+

A good test covers scenarios that specify every relation for every object type that your application will need to call the list-objects API for.

+

The following verifies the expected results using the list_objects option in OpenFGA tests:

+
    list_objects:
- user: user:anne
type: organization
assertions:
member:
- organization:acme
admin: []

- user: user:peter
type: organization
context:
current_time : "2024-02-01T00:10:00Z"

assertions:
member: []
admin:
- organization:acme

+

The example above checks that user:anne has access to the organization:acme as a member and is not an admin of any organization. It also checks that user:peter, given the current time is February 1st 2024, 0:10 AM, is not related to any organization as a member, but is related to organization:acme as an admin.

+

Write List Users tests

+

List users tests verify the results of the list-users API to validate the users who or do not have access to an object

+

Each list users verification has the following structure:

+
ObjectDescription
objectThe object to list users for
user_filterSpecifies the type or userset to filter with, this must only contain one entry
user_filter.typeThe specific type of results to return with response
user_filter.relationThe specific relation of results to return with response. Specify to return usersets (optional)
contextA set of tests for contextual parameters used to evaluate conditions
assertionsA list of assertions to make
<relation>The name of the relation you want to verify
<relation>.usersThe users who should have the stated relation to the object
+

In order to simplify test writing, the following syntax is supported for the various object types included in users from the API response:

+
    +
  • <type>:<id> to represent a userset that is a user
  • +
  • <type>:<id>#<relation> to represent a userset that is a relation on a type
  • +
  • <type>:* to represent a userset that is a type bound public access for a type
  • +
+

The following is an example of using the list_users option in OpenFGA tests:

+
    list_users:
- object: organization:acme
user_filter:
- type: user
context:
current_time : "2024-02-02T00:10:00Z"
assertions:
member:
users:
- user:anne
admin:
users: []

+

The example above checks that the organization:acme, given the current time is February 2nd 2024, it has 'user:anne' as a member, nobody as an admin. If we tried with current time being February 1st 2024, then user:peter would be listed as an admin

+

Running tests

+

Tests are run using the model test CLI command. For instructions on installing the OpenFGA CLI, visit the OpenFGA CLI Github repository.

+
fga model test --tests <filename>.fga.yaml
+

When all tests pass, a summary with the number of tests passed is displayed. When a test fails, a line for every test is displayed.

+
$ fga model test --tests docs.fga.yaml
# Test Summary #
Tests 2/2 passing
Checks 4/4 passing
ListObjects 4/4 passing

$ fga model test --tests docs.fga.yaml
(FAILING) : ListUsers(1/2 passing)
ⅹ ListUsers(object={Type:organization Id:acme},relation=member,user_filter={Type:user Relation:<nil>}, context:&map[current_time:2024-02-02T00:10:00Z]): expected={Users:[user:ann]}, got={Users:[user:anne]}
---
# Test Summary #
Tests 1/2 passing
Checks 4/4 passing
ListObjects 4/4 passing
+

Running tests using GitHub Actions

+

Use the OpenFGA Model Testing Action to run tests from CI/CD flows in GitHub.

+

Set the path to the .fga.yaml file as the store-file-path parameter when configuring the action:

+
name: Test Action

on:
workflow_dispatch:
pull_request:
branches:
- main

jobs:
test:
name: Run test
runs-on: ubuntu-latest
steps:
- name: Checkout Project
uses: actions/checkout@v4
- name: Run Test
uses: openfga/action-openfga-test@v0.1.0
with:
store-file-path: ./example/model.fga.yaml

+ +
Use the FGA CLI

Learn how to use the FGA CLI.

Super Admin Example

Define a model and tests for modeling a super-admin role.

Banking Example

Define a model and tests for banking application.

Entitlements Example

Define a model and tests for B2B application entitlements.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/testing.html.html b/pr-preview/pr-921/docs/modeling/testing.html.html new file mode 100644 index 000000000..8b31c7648 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/testing.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples.html b/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples.html new file mode 100644 index 000000000..fd7225f62 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples.html @@ -0,0 +1,59 @@ + + + + + +Use Token Claims As Contextual Tuples | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

Use Token Claims As Contextual Tuples

+ +

Contextual Tuples allow authorization checks that depend on dynamic or contextual relationships that have not been written to the OpenFGA store, enabling some Attribute Based Access Control (ABAC) use cases.

+

To enable more ABAC use-cases that rely on specific attributes and conditions, you can also use OpenFGA`s conditions.

+

Before You Start

+

To follow this guide, familiarize yourself with the following OpenFGA Concepts:

+
    +
  • A Relation: is a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system.
  • +
  • A Check Request: is a call to the OpenFGA check endpoint that returns whether the user has a certain relationship with an object.
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA
  • +
+

User Directories, Identity Tokens, And Relationships

+

User directories store user information that's accessed when making authorization decisions, like the group the user belongs to, their roles, or their department. The natural way to use those relationships in a Relationship-Based Access Control system like OpenFGA is to create tuples for each relation. However, implementing a synchronization mechanism to keep the user directory data up to date with tuples in the store can be challenging.

+

When applications implement authentication using an OIDC authorization service, they receive an ID Token or an Access token, with certain claims that can be customized based on the application's needs. Instead of writing tuples to the OpenFGA, you can use the content of the token in Contextual Tuples to make authorization checks, understanding that, if those relationships change while the token has not expired, users will still get access to the resources the content of the token entitled them to.

+

Example

+

In this example, the application uses the following authorization model, in which documents can be viewed by members of a group:

+
model
schema 1.1

type user

type group
relations
define member: [user]

type document
relations
define viewer: [group#member]
+

When a group is added as a viewer of a document, the application writes tuples like those below:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Members of the marketing group can view the product-launch document
{"_description":"Members of the marketing group can view the product-launch document","user":"group:marketing#member","relation":"viewer","object":"document:product-launch"},
// Members of the everyone group can view the welcome document
{"_description":"Members of the everyone group can view the welcome document","user":"group:everyone#member","relation":"viewer","object":"document:welcome"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

Let's assume that the Access Token the application receives has a list of the groups the user belongs to:

+
{
"iss": "https://id.company.com",
"sub": "6b0b14af-59dc-4ff3-a46f-ad351f428726",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516239022,
"azp" : "yz54KAoW1KGFAUU982CEUqZgxGIdrpgg",
"groups": ["marketing", "everyone"]
}
+

When making a authorization check, the application uses the groups claim in the token and adds contextual tuple for each group, indicating that the user is a member of that group:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:6b0b14af-59dc-4ff3-a46f-ad351f428726',
relation: 'viewer',
object: 'document:product-launch',
contextualTuples: [
{"_description":"user 6b0b14af-59dc-4ff3-a46f-ad351f428726 is a member of the marketing group","user":"user:6b0b14af-59dc-4ff3-a46f-ad351f428726","relation":"member","object":"group:marketing"},{"_description":"user 6b0b14af-59dc-4ff3-a46f-ad351f428726 is a member of the everyone group","user":"user:6b0b14af-59dc-4ff3-a46f-ad351f428726","relation":"member","object":"group:everyone"}
],
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

The authorization check returns allowed = true, as there's a stored tuple saying that members of the marketing group are viewers of the product-launch document, and there's a contextual tuple indicating that the user is a member of the marketing group.

+
Warning

Contextual tuples:

+ +
Contextual and Time-Based Authorization

Learn how to authorize access that depends on dynamic or contextual criteria.

Authorization Through Organization Context

Learn to model and authorize when a user belongs to multiple organizations.

Conditions

Learn to model requiring dynamic attributes.

OpenFGA API

Details on the Check API in the OpenFGA reference guide.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples.html.html b/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples.html.html new file mode 100644 index 000000000..d7f365bf7 --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/user-groups.html b/pr-preview/pr-921/docs/modeling/user-groups.html new file mode 100644 index 000000000..930bdf7dd --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/user-groups.html @@ -0,0 +1,79 @@ + + + + + +User Groups | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

User Groups

+ +

To add users to groups and grant groups access to an object using OpenFGA.

+
When to use

Relationship tuples can specify that an entire group has a relation to an object, which is helpful when you want to encompass a set of users with the same relation to an object. For example:

    +
  • Grant viewer access to a group of engineers in roadmap.doc
  • +
  • Create a block_list of members who can't access a document
  • +
  • Sharing a document with a team
  • +
  • Granting viewer access to a photo to followers only
  • +
  • Making a file viewable for all users within an organization
  • +
  • Restricting access from or to users in a certain locale
  • +
+

Before you start

+

Familiarize yourself with the OpenFGA Concepts.

+

Assume you have the following authorization model.
: you have an object called document that users can relate to as an editor.

model
schema 1.1

type user

type document
relations
define editor: [user]

In addition, you will need to know the following:

Direct Access

You need to know how to create an authorization model and a relationship tuple to grant a user access to an object. To learn more, see direct access.

OpenFGA Concepts

    +
  • A Type: a class of objects that have similar characteristics.
  • +
  • A User: an entity in the system that can be related to an object.
  • +
  • A Relation: a string defined in the type definition of an authorization model that defines the possibility of a relationship between an object of the same type as the type definition and a user in the system.
  • +
  • An Object: represents an entity in the system. Users' relationships to it can be defined with relationship tuples and the authorization model.
  • +
  • A Relationship Tuple: a grouping consisting of a user, a relation and an object stored in OpenFGA.
  • +
+ +

Step By Step

+

There are possible use cases where a group of users have a certain role on or permission to an object. For example, members of a certain team could have an editor relation to a certain document.

+

To represent this in OpenFGA:

+
    +
  1. Introduce the concept of a team to the authorization model.
  2. +
  3. Add users as members to the team.
  4. +
  5. Assign the team members a relation to an object.
  6. +
  7. Check an individual member's access to the object.
  8. +
+

01. Introduce the concept of a team to the authorization model

+

First, define the object team in your authorization model. In this use case, a team can have members, so you make the following changes to the authorization model:

+
model
schema 1.1

type user

type document
relations
define editor: [team#member]

type team
relations
define member: [user]
+

02. Add users as members to the team

+

You can now assign users as members of teams. Create a new relationship tuple that states user:alice is a member of team:writers.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
{"user":"user:alice","relation":"member","object":"team:writers"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

03. Assign the team members a relation to an object

+

To represent groups, use the type:object_id#relation format, which represents the set of users related to the type:object_id as a certain relation. For example, team:writers#members represents the set of users related to the team:writers object as members.

+

In order to assign members of a team a relation to a document, create the following relationship tuple stating that members of team:writers are editors of document:meeting_notes.doc.

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

await fgaClient.write({
writes: [
// Set of users related to 'team:writers' as 'member'
{"_description":"Set of users related to 'team:writers' as 'member'","user":"team:writers#member","relation":"editor","object":"document:meeting_notes.doc"}
],
}, {
authorization_model_id: "01HVMMBCMGZNT3SED4Z17ECXCA"
});
+

04. Check an individual member's access to an object

+

Now that you have:

+
    +
  • a relationship tuple indicating that alice is a member of team:writers
  • +
  • a relationship tuple indicating that members of team:writers are editors of document:meeting_notes.doc
  • +
+

The *check\ is alice an editor of document:meeting_notes.doc returns the following:

+
Initialize the SDK
// ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional.
// import the SDK
const { OpenFgaClient } = require('@openfga/sdk');

// Initialize the SDK with no auth - see "How to setup SDK client" for more options
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example
storeId: process.env.FGA_STORE_ID,
authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request
});

// Run a check
const { allowed } = await fgaClient.check({
user: 'user:alice',
relation: 'editor',
object: 'document:meeting_notes.doc',
}, {
authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA',
});

// allowed = true
+

The chain of resolution is:

+
    +
  • alice is member of team:writers
  • +
  • members of team:writers are editors of document:meeting_notes
  • +
  • therefore, alice is editor of document:meeting_notes
  • +
+
caution

Note: When creating relationship tuples for OpenFGA, use unique ids for each object and user in your application domain. This example uses first names and simple ids as a suggested example.

+ +
Managing Group Membership

Learn how to add and remove users from groups

Modeling Google Drive

See how User Groups can be used to share documents within a domain in the Google Drive use-case.

Modeling GitHub

Granting teams permissions to a repo in the GitHub use-case.

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/docs/modeling/user-groups.html.html b/pr-preview/pr-921/docs/modeling/user-groups.html.html new file mode 100644 index 000000000..1402292de --- /dev/null +++ b/pr-preview/pr-921/docs/modeling/user-groups.html.html @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/icons/chevron-top.svg b/pr-preview/pr-921/icons/chevron-top.svg new file mode 100644 index 000000000..8d9488973 --- /dev/null +++ b/pr-preview/pr-921/icons/chevron-top.svg @@ -0,0 +1,3 @@ + + + diff --git a/pr-preview/pr-921/img/Notifications.svg b/pr-preview/pr-921/img/Notifications.svg new file mode 100644 index 000000000..31de81340 --- /dev/null +++ b/pr-preview/pr-921/img/Notifications.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/Pattern.svg b/pr-preview/pr-921/img/Pattern.svg new file mode 100644 index 000000000..d7786ae4a --- /dev/null +++ b/pr-preview/pr-921/img/Pattern.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pr-preview/pr-921/img/admonition-default-icon.svg b/pr-preview/pr-921/img/admonition-default-icon.svg new file mode 100644 index 000000000..cfc4e67de --- /dev/null +++ b/pr-preview/pr-921/img/admonition-default-icon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pr-preview/pr-921/img/admonition-info-icon.svg b/pr-preview/pr-921/img/admonition-info-icon.svg new file mode 100644 index 000000000..2c38b0616 --- /dev/null +++ b/pr-preview/pr-921/img/admonition-info-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/pr-preview/pr-921/img/admonition-warning-icon.svg b/pr-preview/pr-921/img/admonition-warning-icon.svg new file mode 100644 index 000000000..bd316e488 --- /dev/null +++ b/pr-preview/pr-921/img/admonition-warning-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/pr-preview/pr-921/img/banner-drive-icon.svg b/pr-preview/pr-921/img/banner-drive-icon.svg new file mode 100644 index 000000000..bd40cbdd5 --- /dev/null +++ b/pr-preview/pr-921/img/banner-drive-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pr-preview/pr-921/img/banner-entitlements-icon.svg b/pr-preview/pr-921/img/banner-entitlements-icon.svg new file mode 100644 index 000000000..8756a6248 --- /dev/null +++ b/pr-preview/pr-921/img/banner-entitlements-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/pr-preview/pr-921/img/banner-github-icon.svg b/pr-preview/pr-921/img/banner-github-icon.svg new file mode 100644 index 000000000..6a9f8da38 --- /dev/null +++ b/pr-preview/pr-921/img/banner-github-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/pr-preview/pr-921/img/banner-iot-icon.svg b/pr-preview/pr-921/img/banner-iot-icon.svg new file mode 100644 index 000000000..8f4007d16 --- /dev/null +++ b/pr-preview/pr-921/img/banner-iot-icon.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/pr-preview/pr-921/img/banner-playground-icon.svg b/pr-preview/pr-921/img/banner-playground-icon.svg new file mode 100644 index 000000000..8e9fa32b3 --- /dev/null +++ b/pr-preview/pr-921/img/banner-playground-icon.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/banner-slack-icon.svg b/pr-preview/pr-921/img/banner-slack-icon.svg new file mode 100644 index 000000000..c716c7fd1 --- /dev/null +++ b/pr-preview/pr-921/img/banner-slack-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pr-preview/pr-921/img/blog/authors/andres.jpg b/pr-preview/pr-921/img/blog/authors/andres.jpg new file mode 100644 index 000000000..1863a33ec Binary files /dev/null and b/pr-preview/pr-921/img/blog/authors/andres.jpg differ diff --git a/pr-preview/pr-921/img/blog/authors/caleb.jpg b/pr-preview/pr-921/img/blog/authors/caleb.jpg new file mode 100644 index 000000000..3817e8a6b Binary files /dev/null and b/pr-preview/pr-921/img/blog/authors/caleb.jpg differ diff --git a/pr-preview/pr-921/img/blog/authors/ewan.jpg b/pr-preview/pr-921/img/blog/authors/ewan.jpg new file mode 100644 index 000000000..89813ffae Binary files /dev/null and b/pr-preview/pr-921/img/blog/authors/ewan.jpg differ diff --git a/pr-preview/pr-921/img/blog/authors/miparnisari.jpg b/pr-preview/pr-921/img/blog/authors/miparnisari.jpg new file mode 100644 index 000000000..4c5f1614a Binary files /dev/null and b/pr-preview/pr-921/img/blog/authors/miparnisari.jpg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2023-12-bdd.png b/pr-preview/pr-921/img/blog/fgn-2023-12-bdd.png new file mode 100644 index 000000000..7ddbc5943 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2023-12-bdd.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2023-12-canonical.png b/pr-preview/pr-921/img/blog/fgn-2023-12-canonical.png new file mode 100644 index 000000000..0fa39cff5 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2023-12-canonical.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2023-12-language.png b/pr-preview/pr-921/img/blog/fgn-2023-12-language.png new file mode 100644 index 000000000..b9c3eb0bf Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2023-12-language.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2023-12-validation.png b/pr-preview/pr-921/img/blog/fgn-2023-12-validation.png new file mode 100644 index 000000000..cbfdc847d Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2023-12-validation.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-01-team.png b/pr-preview/pr-921/img/blog/fgn-2024-01-team.png new file mode 100644 index 000000000..a2e74c882 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-01-team.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-01-vscode.gif b/pr-preview/pr-921/img/blog/fgn-2024-01-vscode.gif new file mode 100644 index 000000000..6baf785f4 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-01-vscode.gif differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-06-securitycon-booth.png b/pr-preview/pr-921/img/blog/fgn-2024-06-securitycon-booth.png new file mode 100644 index 000000000..4606e5c18 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-06-securitycon-booth.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-06-securitycon-talk.jpg b/pr-preview/pr-921/img/blog/fgn-2024-06-securitycon-talk.jpg new file mode 100644 index 000000000..f418cfacc Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-06-securitycon-talk.jpg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-10-andrea-chiarelli.jpeg b/pr-preview/pr-921/img/blog/fgn-2024-10-andrea-chiarelli.jpeg new file mode 100644 index 000000000..1a64f7844 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-10-andrea-chiarelli.jpeg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-10-andres-aguiar.jpg b/pr-preview/pr-921/img/blog/fgn-2024-10-andres-aguiar.jpg new file mode 100644 index 000000000..957a736fa Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-10-andres-aguiar.jpg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-10-kiah-imani.jpeg b/pr-preview/pr-921/img/blog/fgn-2024-10-kiah-imani.jpeg new file mode 100644 index 000000000..4d7a323ea Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-10-kiah-imani.jpeg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-10-ryanpq.jpg b/pr-preview/pr-921/img/blog/fgn-2024-10-ryanpq.jpg new file mode 100644 index 000000000..f4e0fe520 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-10-ryanpq.jpg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-andrea-chiarelli1.png b/pr-preview/pr-921/img/blog/fgn-2024-11-andrea-chiarelli1.png new file mode 100644 index 000000000..94868c373 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-andrea-chiarelli1.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-andrea-chiarelli2.png b/pr-preview/pr-921/img/blog/fgn-2024-11-andrea-chiarelli2.png new file mode 100644 index 000000000..de94e74b8 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-andrea-chiarelli2.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-chicago-offsite-team-photo.png b/pr-preview/pr-921/img/blog/fgn-2024-11-chicago-offsite-team-photo.png new file mode 100644 index 000000000..08f76f0ae Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-chicago-offsite-team-photo.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-kubecon1.jpg b/pr-preview/pr-921/img/blog/fgn-2024-11-kubecon1.jpg new file mode 100644 index 000000000..2e9b5c0a0 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-kubecon1.jpg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-kubecon2.jpg b/pr-preview/pr-921/img/blog/fgn-2024-11-kubecon2.jpg new file mode 100644 index 000000000..8c0c11ef5 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-kubecon2.jpg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-linkedin.png b/pr-preview/pr-921/img/blog/fgn-2024-11-linkedin.png new file mode 100644 index 000000000..4b78fa4d6 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-linkedin.png differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-open-fga-ranks-5th.jpeg b/pr-preview/pr-921/img/blog/fgn-2024-11-open-fga-ranks-5th.jpeg new file mode 100644 index 000000000..ddc3a90b8 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-open-fga-ranks-5th.jpeg differ diff --git a/pr-preview/pr-921/img/blog/fgn-2024-11-stars.png b/pr-preview/pr-921/img/blog/fgn-2024-11-stars.png new file mode 100644 index 000000000..d7e2a8f40 Binary files /dev/null and b/pr-preview/pr-921/img/blog/fgn-2024-11-stars.png differ diff --git a/pr-preview/pr-921/img/chevron.svg b/pr-preview/pr-921/img/chevron.svg new file mode 100644 index 000000000..4059e4821 --- /dev/null +++ b/pr-preview/pr-921/img/chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/pr-preview/pr-921/img/cncf-icon-white.svg b/pr-preview/pr-921/img/cncf-icon-white.svg new file mode 100644 index 000000000..4d4fddc72 --- /dev/null +++ b/pr-preview/pr-921/img/cncf-icon-white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pr-preview/pr-921/img/getting-started-fga-logo.svg b/pr-preview/pr-921/img/getting-started-fga-logo.svg new file mode 100644 index 000000000..f71ac03cb --- /dev/null +++ b/pr-preview/pr-921/img/getting-started-fga-logo.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/getting-started-icon-dir.svg b/pr-preview/pr-921/img/getting-started-icon-dir.svg new file mode 100644 index 000000000..c5a141b87 --- /dev/null +++ b/pr-preview/pr-921/img/getting-started-icon-dir.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/pr-preview/pr-921/img/getting-started-icon-doc.svg b/pr-preview/pr-921/img/getting-started-icon-doc.svg new file mode 100644 index 000000000..1444a4323 --- /dev/null +++ b/pr-preview/pr-921/img/getting-started-icon-doc.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/pr-preview/pr-921/img/getting-started-icon-drive.svg b/pr-preview/pr-921/img/getting-started-icon-drive.svg new file mode 100644 index 000000000..142e0c4b2 --- /dev/null +++ b/pr-preview/pr-921/img/getting-started-icon-drive.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/getting-started-icon-org.svg b/pr-preview/pr-921/img/getting-started-icon-org.svg new file mode 100644 index 000000000..2f9bbaa3a --- /dev/null +++ b/pr-preview/pr-921/img/getting-started-icon-org.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/og-rich-embed.png b/pr-preview/pr-921/img/og-rich-embed.png new file mode 100644 index 000000000..b5a84817d Binary files /dev/null and b/pr-preview/pr-921/img/og-rich-embed.png differ diff --git a/pr-preview/pr-921/img/openfga-icon.svg b/pr-preview/pr-921/img/openfga-icon.svg new file mode 100644 index 000000000..dab5a47d4 --- /dev/null +++ b/pr-preview/pr-921/img/openfga-icon.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/openfga_logo-white.svg b/pr-preview/pr-921/img/openfga_logo-white.svg new file mode 100644 index 000000000..16176e19f --- /dev/null +++ b/pr-preview/pr-921/img/openfga_logo-white.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/openfga_logo.svg b/pr-preview/pr-921/img/openfga_logo.svg new file mode 100644 index 000000000..9451961e3 --- /dev/null +++ b/pr-preview/pr-921/img/openfga_logo.svg @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pr-preview/pr-921/img/openfga_quickstart_terminal.svg b/pr-preview/pr-921/img/openfga_quickstart_terminal.svg new file mode 100644 index 000000000..c0bb758db --- /dev/null +++ b/pr-preview/pr-921/img/openfga_quickstart_terminal.svg @@ -0,0 +1,11 @@ + +Mock terminal window showing OpenFGA Quickstart commands and output + + + + + + + + + diff --git a/pr-preview/pr-921/index.html b/pr-preview/pr-921/index.html new file mode 100644 index 000000000..c9e5dff55 --- /dev/null +++ b/pr-preview/pr-921/index.html @@ -0,0 +1,23 @@ + + + + + +Fine Grained Authorization | OpenFGA + + + + + + + + + + + + + + +
Skip to main content

OpenFGA LogoRelationship-based access control made fast, scalable, and easy to use.

OpenFGA is an open-source authorization solution that allows developers to build granular access control using an easy-to-read modeling language and friendly APIs.

Quick Start

Trying OpenFGA is as easy as...

Run the following snippet in a terminal in an environment with Docker installed:

docker pull openfga/openfga && \
docker run -p 8080:8080 -p 8081:8081 \
-p 3000:3000 openfga/openfga run

OpenFGA will be running at localhost:8080 on your machine. Learn about other options and next steps in the project README.md or Getting Started guides.

Learn how to use sample authorization models and create your own with the project’s extensive documentation.

Features

Model any authorization system

OpenFGA takes the best ideas from Google's Zanzibar paper for Relationship-Based Access Control, and also solves problems for Role-based Access Control and Attribute-Based Access Control use cases. The modeling language is powerful enough for engineers, but friendly enough for other stakeholders on your team as well.

Works with your code

SDKs for the most popular languages have already been written, making it easy to integrate and grow alongside your applications. OpenFGA also makes it trivial to contribute new SDKs to support your project's language.

Blazing fast

OpenFGA is designed to answer authorization check calls in milliseconds, which lets it scale with projects of any size. It works just as well for small startups and hobby programmers building single applications as it does for enterprise companies building platforms on a global scale.

Built in the open

Transparency and peer review are important for building secure, stable, and sustainable software. OpenFGA's RFC process and governance model invite anyone to become a contributor, and collaboratively develop the public roadmap. Come create the next standard for authorization with us!

CNCF Sandbox Project

We are a Cloud Native Computing Foundation sandbox project.

Get Involved

Join OpenFGA's active Slack and GitHub community, check out existing RFCs to understand where the project is headed, and learn more about how to take part by reading our CONTRIBUTING.md.

Learn how to get involved →

Since you're here, you might be interested in some ReBAC resources:

+ + \ No newline at end of file diff --git a/pr-preview/pr-921/search-index.json b/pr-preview/pr-921/search-index.json new file mode 100644 index 000000000..ee63f046b --- /dev/null +++ b/pr-preview/pr-921/search-index.json @@ -0,0 +1 @@ +[{"documents":[{"i":1,"t":"","u":"/pr-preview/pr-921/blog/archive","b":["Home"]},{"i":2,"t":"","u":"/pr-preview/pr-921/blog/authors","b":["Home"]},{"i":3,"t":"Conditional Relationship Tuples for OpenFGA","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","b":["Home"]},{"i":13,"t":"Fine Grained News - December 2023","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","b":["Home"]},{"i":37,"t":"Fine Grained News - January 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","b":["Home"]},{"i":63,"t":"Fine Grained News - February 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","b":["Home"]},{"i":81,"t":"Fine Grained News - March 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","b":["Home"]},{"i":97,"t":"Fine Grained News - April 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","b":["Home"]},{"i":111,"t":"Fine Grained News - May 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","b":["Home"]},{"i":125,"t":"Fine Grained News - July 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","b":["Home"]},{"i":143,"t":"Fine Grained News - September 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","b":["Home"]},{"i":157,"t":"Fine Grained News - June 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","b":["Home"]},{"i":173,"t":"Fine Grained News - October 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","b":["Home"]},{"i":187,"t":"Join the OpenFGA team at KubeCon NA 2023","u":"/pr-preview/pr-921/blog/kubecon-na-2023","b":["Home"]},{"i":189,"t":"Fine Grained News - November 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","b":["Home"]},{"i":203,"t":"List Users API","u":"/pr-preview/pr-921/blog/list-users-announcement","b":["Home"]},{"i":209,"t":"Fine Grained News - August 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","b":["Home"]},{"i":229,"t":"Modular Models","u":"/pr-preview/pr-921/blog/modular-models-announcement","b":["Home"]},{"i":237,"t":"Query Consistency Options in OpenFGA","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","b":["Home"]},{"i":247,"t":"Authorization Concepts","u":"/pr-preview/pr-921/docs/authorization-concepts","b":["Home"]},{"i":262,"t":"OpenFGA Community","u":"/pr-preview/pr-921/docs/community","b":["Home"]},{"i":277,"t":"","u":"/pr-preview/pr-921/blog/page/2","b":["Home"]},{"i":382,"t":"Introduction to OpenFGA","u":"/pr-preview/pr-921/docs/fga","b":["Home"]},{"i":390,"t":"Content","u":"/pr-preview/pr-921/docs/getting-started","b":["Home","Getting Started"]},{"i":392,"t":"Use the FGA CLI","u":"/pr-preview/pr-921/docs/getting-started/cli","b":["Home","Getting Started"]},{"i":414,"t":"Configuration Language","u":"/pr-preview/pr-921/docs/configuration-language","b":["Home"]},{"i":434,"t":"Configure Authorization Model for a Store","u":"/pr-preview/pr-921/docs/getting-started/configure-model","b":["Home","Getting Started"]},{"i":442,"t":"Create a Store","u":"/pr-preview/pr-921/docs/getting-started/create-store","b":["Home","Getting Started"]},{"i":446,"t":"Configure SDK Client Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","b":["Home","Getting Started"]},{"i":460,"t":"Immutable Authorization Models","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","b":["Home","Getting Started"]},{"i":475,"t":"Install SDK Client","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","b":["Home","Getting Started"]},{"i":489,"t":"Integrate Within a Framework","u":"/pr-preview/pr-921/docs/getting-started/framework","b":["Home","Getting Started"]},{"i":503,"t":"Perform a Check","u":"/pr-preview/pr-921/docs/getting-started/perform-check","b":["Home","Getting Started"]},{"i":517,"t":"Perform a list objects call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","b":["Home","Getting Started"]},{"i":529,"t":"Running OpenFGA in Production","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","b":["Home","Getting Started"]},{"i":541,"t":"🛡️Setup Access Control","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","b":["Home","Getting Started","Setup OpenFGA"]},{"i":560,"t":"Configuring OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","b":["Home","Getting Started","Setup OpenFGA"]},{"i":598,"t":"🐳 Setup OpenFGA with Docker","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","b":["Home","Getting Started","Setup OpenFGA"]},{"i":616,"t":"☸️ Setup OpenFGA with Kubernetes","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/kubernetes","b":["Home","Getting Started","Setup OpenFGA"]},{"i":618,"t":"Setup OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/overview","b":["Home","Getting Started","Setup OpenFGA"]},{"i":620,"t":"Using the OpenFGA Playground","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/playground","b":["Home","Getting Started","Setup OpenFGA"]},{"i":626,"t":"Setup SDK Client for Store","u":"/pr-preview/pr-921/docs/getting-started/setup-sdk-client","b":["Home","Getting Started"]},{"i":634,"t":"Best Practices of Managing Tuples and Invoking APIs","u":"/pr-preview/pr-921/docs/getting-started/tuples-api-best-practices","b":["Home","Getting Started"]},{"i":642,"t":"Perform a List Users call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","b":["Home","Getting Started"]},{"i":658,"t":"Content","u":"/pr-preview/pr-921/docs/interacting","b":["Home","Interacting with the API"]},{"i":660,"t":"Query Consistency Modes","u":"/pr-preview/pr-921/docs/interacting/consistency","b":["Home","Interacting with the API"]},{"i":671,"t":"Update Relationship Tuples","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","b":["Home","Getting Started"]},{"i":685,"t":"Managing Group Access","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","b":["Home","Interacting with the API"]},{"i":702,"t":"Managing User Access","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","b":["Home","Interacting with the API"]},{"i":717,"t":"How to get tuple changes","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","b":["Home","Interacting with the API"]},{"i":729,"t":"Search With Permissions","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","b":["Home","Interacting with the API"]},{"i":743,"t":"Content","u":"/pr-preview/pr-921/docs/modeling","b":["Home","Modeling Guides"]},{"i":745,"t":"Advanced Use-Cases","u":"/pr-preview/pr-921/docs/modeling/advanced","b":["Home","Modeling Guides","Advanced Use-Cases"]},{"i":751,"t":"Transactional Writes","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","b":["Home","Interacting with the API"]},{"i":768,"t":"Content","u":"/pr-preview/pr-921/docs/modeling/building-blocks","b":["Home","Modeling Guides","Building Blocks"]},{"i":770,"t":"Concentric Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","b":["Home","Modeling Guides","Building Blocks"]},{"i":786,"t":"Usersets","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","b":["Home","Modeling Guides","Building Blocks"]},{"i":797,"t":"Conditions","u":"/pr-preview/pr-921/docs/modeling/conditions","b":["Home","Modeling Guides"]},{"i":812,"t":"Custom Roles","u":"/pr-preview/pr-921/docs/modeling/custom-roles","b":["Home","Modeling Guides"]},{"i":836,"t":"Direct Access","u":"/pr-preview/pr-921/docs/modeling/direct-access","b":["Home","Modeling Guides"]},{"i":850,"t":"Content","u":"/pr-preview/pr-921/docs/modeling/migrating","b":["Home","Modeling Guides","Migrations"]},{"i":852,"t":"Model Migrations","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-models","b":["Home","Modeling Guides","Migrations"]},{"i":860,"t":"Get Started with Modeling","u":"/pr-preview/pr-921/docs/modeling/getting-started","b":["Home","Modeling Guides"]},{"i":880,"t":"Modular Models","u":"/pr-preview/pr-921/docs/modeling/modular-models","b":["Home","Modeling Guides"]},{"i":903,"t":"Multiple Restrictions","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","b":["Home","Modeling Guides"]},{"i":921,"t":"Parent-Child Objects","u":"/pr-preview/pr-921/docs/modeling/parent-child","b":["Home","Modeling Guides"]},{"i":943,"t":"User Groups","u":"/pr-preview/pr-921/docs/modeling/user-groups","b":["Home","Modeling Guides"]},{"i":963,"t":"Testing Models","u":"/pr-preview/pr-921/docs/modeling/testing","b":["Home","Modeling Guides"]},{"i":981,"t":"Use Token Claims As Contextual Tuples","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","b":["Home","Modeling Guides"]},{"i":991,"t":"Concepts","u":"/pr-preview/pr-921/docs/concepts","b":["Home"]},{"i":1033,"t":"Public Access","u":"/pr-preview/pr-921/docs/modeling/public-access","b":["Home","Modeling Guides"]},{"i":1049,"t":"Managing Group Membership","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","b":["Home","Interacting with the API"]},{"i":1066,"t":"Managing Relationships Between Objects","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","b":["Home","Interacting with the API"]},{"i":1088,"t":"Relationship Queries: Check, Read, Expand, ListObjects and ListUsers","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","b":["Home","Interacting with the API"]},{"i":1140,"t":"Blocklists","u":"/pr-preview/pr-921/docs/modeling/blocklists","b":["Home","Modeling Guides"]},{"i":1158,"t":"Direct Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","b":["Home","Modeling Guides","Building Blocks"]},{"i":1178,"t":"Object to Object Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","b":["Home","Modeling Guides","Building Blocks"]},{"i":1205,"t":"Migrating Relations","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","b":["Home","Modeling Guides","Migrations"]},{"i":1221,"t":"Roles and Permissions","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","b":["Home","Modeling Guides"]},{"i":1239,"t":"Authorization Through Organization Context","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","b":["Home","Modeling Guides"]},{"i":1261,"t":"Modeling Entitlements for a System with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","b":["Home","Modeling Guides","Advanced Use-Cases"]},{"i":1282,"t":"Modeling Authorization for an IoT Security System with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","b":["Home","Modeling Guides","Advanced Use-Cases"]},{"i":1310,"t":"Modeling Google Drive permissions with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","b":["Home","Modeling Guides","Advanced Use-Cases"]},{"i":1333,"t":"Modeling GitHub permissions with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/github","b":["Home","Modeling Guides","Advanced Use-Cases"]},{"i":1356,"t":"Modeling Authorization for Slack with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","b":["Home","Modeling Guides","Advanced Use-Cases"]},{"i":1380,"t":"Contextual and Time-Based Authorization","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","b":["Home","Modeling Guides"]}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/1",[]],["t/2",[]],["t/3",[0,3.141,1,2.169,2,2.443,3,1.471]],["t/13",[4,1.534,5,1.534,6,1.534,7,3.21,8,2.806]],["t/37",[4,1.534,5,1.534,6,1.534,9,3.21,10,1.6]],["t/63",[4,1.534,5,1.534,6,1.534,10,1.6,11,3.21]],["t/81",[4,1.534,5,1.534,6,1.534,10,1.6,12,3.21]],["t/97",[4,1.534,5,1.534,6,1.534,10,1.6,13,3.21]],["t/111",[4,1.717,5,1.717,6,1.717,10,1.791]],["t/125",[4,1.534,5,1.534,6,1.534,10,1.6,14,3.21]],["t/143",[4,1.534,5,1.534,6,1.534,10,1.6,15,3.21]],["t/157",[4,1.534,5,1.534,6,1.534,10,1.6,16,3.21]],["t/173",[4,1.534,5,1.534,6,1.534,10,1.6,17,3.21]],["t/187",[3,1.188,8,2.536,18,2.901,19,2.901,20,2.901,21,2.901]],["t/189",[4,1.534,5,1.534,6,1.534,10,1.6,22,3.21]],["t/203",[23,3.228,24,2.976,25,3.566]],["t/209",[4,1.534,5,1.534,6,1.534,10,1.6,26,3.21]],["t/229",[27,4.125,28,2.255]],["t/237",[3,1.471,29,2.843,30,3.141,31,3.593]],["t/247",[32,2.848,33,4.125]],["t/262",[3,1.932,34,4.719]],["t/277",[]],["t/382",[3,1.932,35,4.719]],["t/390",[36,3.805]],["t/392",[37,2.976,38,4.08,39,4.08]],["t/414",[40,3.442,41,4.719]],["t/434",[28,1.717,32,2.169,40,2.621,42,2.843]],["t/442",[42,3.734,43,4.719]],["t/446",[40,2.621,44,2.843,45,2.843,46,3.593]],["t/460",[28,1.949,32,2.463,47,4.08]],["t/475",[44,3.228,45,3.228,48,4.08]],["t/489",[49,4.08,50,4.08,51,4.08]],["t/503",[52,3.734,53,4.125]],["t/517",[23,2.843,52,2.843,54,2.621,55,3.141]],["t/529",[3,1.67,56,4.08,57,4.08]],["t/541",[58,2.774,59,2.774,60,4.08]],["t/560",[3,1.932,40,3.442]],["t/598",[3,1.471,58,2.443,61,3.141,62,3.593]],["t/616",[3,1.471,58,2.443,61,3.141,63,3.593]],["t/618",[3,1.932,58,3.209]],["t/620",[3,1.67,37,2.976,64,4.08]],["t/626",[42,2.843,44,2.843,45,2.843,58,2.443]],["t/634",[2,1.973,25,2.536,65,2.901,66,2.901,67,1.973,68,2.901]],["t/642",[23,2.843,24,2.621,52,2.843,55,3.141]],["t/658",[36,3.805]],["t/660",[29,3.228,30,3.566,69,4.08]],["t/671",[1,2.463,2,2.774,70,4.08]],["t/685",[59,2.774,67,2.774,71,3.228]],["t/702",[24,2.976,59,2.774,67,2.774]],["t/717",[2,3.209,72,4.719]],["t/729",[73,4.719,74,3.442]],["t/743",[36,3.805]],["t/745",[37,2.976,75,4.08,76,4.08]],["t/751",[77,4.719,78,4.719]],["t/768",[36,3.805]],["t/770",[1,2.848,79,4.719]],["t/786",[80,5.595]],["t/797",[0,4.891]],["t/812",[81,4.719,82,4.125]],["t/836",[59,3.209,83,4.125]],["t/850",[36,3.805]],["t/852",[28,2.255,84,4.125]],["t/860",[28,2.255,85,4.719]],["t/880",[27,4.125,28,2.255]],["t/903",[86,4.719,87,4.719]],["t/921",[54,2.976,88,4.08,89,4.08]],["t/943",[24,3.442,71,3.734]],["t/963",[28,2.255,90,4.719]],["t/981",[2,2.183,37,2.342,91,3.21,92,3.21,93,2.806]],["t/991",[33,4.891]],["t/1033",[59,3.209,94,4.719]],["t/1049",[67,2.774,71,3.228,95,4.08]],["t/1066",[1,2.169,54,2.621,67,2.443,96,3.593]],["t/1088",[1,1.597,29,2.094,53,2.313,97,2.646,98,2.646,99,2.646,100,2.646]],["t/1140",[101,5.595]],["t/1158",[1,2.848,83,4.125]],["t/1178",[1,2.463,54,4.086]],["t/1205",[84,4.125,102,4.719]],["t/1221",[74,3.442,82,4.125]],["t/1239",[32,2.169,103,3.593,104,3.593,105,3.593]],["t/1261",[3,1.471,28,1.717,106,3.593,107,3.141]],["t/1282",[3,1.188,28,1.386,32,1.751,107,2.536,108,2.901,109,2.901]],["t/1310",[3,1.314,28,1.534,74,2.342,110,3.21,111,3.21]],["t/1333",[3,1.471,28,1.717,74,2.621,112,3.593]],["t/1356",[3,1.471,28,1.717,32,2.169,113,3.593]],["t/1380",[32,2.169,93,3.141,114,3.593,115,3.593]]],"invertedIndex":[["",{"_index":61,"t":{"598":{"position":[[0,2]]},"616":{"position":[[0,2]]}}}],["2023",{"_index":8,"t":{"13":{"position":[[29,4]]},"187":{"position":[[36,4]]}}}],["2024",{"_index":10,"t":{"37":{"position":[[28,4]]},"63":{"position":[[29,4]]},"81":{"position":[[26,4]]},"97":{"position":[[26,4]]},"111":{"position":[[24,4]]},"125":{"position":[[25,4]]},"143":{"position":[[30,4]]},"157":{"position":[[25,4]]},"173":{"position":[[28,4]]},"189":{"position":[[29,4]]},"209":{"position":[[27,4]]}}}],["access",{"_index":59,"t":{"541":{"position":[[9,6]]},"685":{"position":[[15,6]]},"702":{"position":[[14,6]]},"836":{"position":[[7,6]]},"1033":{"position":[[7,6]]}}}],["advanc",{"_index":75,"t":{"745":{"position":[[0,8]]}}}],["api",{"_index":25,"t":{"203":{"position":[[11,3]]},"634":{"position":[[47,4]]}}}],["april",{"_index":13,"t":{"97":{"position":[[20,5]]}}}],["august",{"_index":26,"t":{"209":{"position":[[20,6]]}}}],["author",{"_index":32,"t":{"247":{"position":[[0,13]]},"434":{"position":[[10,13]]},"460":{"position":[[10,13]]},"1239":{"position":[[0,13]]},"1282":{"position":[[9,13]]},"1356":{"position":[[9,13]]},"1380":{"position":[[26,13]]}}}],["base",{"_index":115,"t":{"1380":{"position":[[20,5]]}}}],["best",{"_index":65,"t":{"634":{"position":[[0,4]]}}}],["between",{"_index":96,"t":{"1066":{"position":[[23,7]]}}}],["blocklist",{"_index":101,"t":{"1140":{"position":[[0,10]]}}}],["call",{"_index":55,"t":{"517":{"position":[[23,4]]},"642":{"position":[[21,4]]}}}],["case",{"_index":76,"t":{"745":{"position":[[13,5]]}}}],["chang",{"_index":72,"t":{"717":{"position":[[17,7]]}}}],["check",{"_index":53,"t":{"503":{"position":[[10,5]]},"1088":{"position":[[22,6]]}}}],["child",{"_index":89,"t":{"921":{"position":[[7,5]]}}}],["claim",{"_index":92,"t":{"981":{"position":[[10,6]]}}}],["cli",{"_index":39,"t":{"392":{"position":[[12,3]]}}}],["client",{"_index":45,"t":{"446":{"position":[[14,6]]},"475":{"position":[[12,6]]},"626":{"position":[[10,6]]}}}],["commun",{"_index":34,"t":{"262":{"position":[[8,9]]}}}],["concentr",{"_index":79,"t":{"770":{"position":[[0,10]]}}}],["concept",{"_index":33,"t":{"247":{"position":[[14,8]]},"991":{"position":[[0,8]]}}}],["condit",{"_index":0,"t":{"3":{"position":[[0,11]]},"797":{"position":[[0,10]]}}}],["configur",{"_index":40,"t":{"414":{"position":[[0,13]]},"434":{"position":[[0,9]]},"446":{"position":[[0,9]]},"560":{"position":[[0,11]]}}}],["consist",{"_index":30,"t":{"237":{"position":[[6,11]]},"660":{"position":[[6,11]]}}}],["content",{"_index":36,"t":{"390":{"position":[[0,7]]},"658":{"position":[[0,7]]},"743":{"position":[[0,7]]},"768":{"position":[[0,7]]},"850":{"position":[[0,7]]}}}],["context",{"_index":105,"t":{"1239":{"position":[[35,7]]}}}],["contextu",{"_index":93,"t":{"981":{"position":[[20,10]]},"1380":{"position":[[0,10]]}}}],["control",{"_index":60,"t":{"541":{"position":[[16,7]]}}}],["creat",{"_index":43,"t":{"442":{"position":[[0,6]]}}}],["custom",{"_index":81,"t":{"812":{"position":[[0,6]]}}}],["decemb",{"_index":7,"t":{"13":{"position":[[20,8]]}}}],["direct",{"_index":83,"t":{"836":{"position":[[0,6]]},"1158":{"position":[[0,6]]}}}],["docker",{"_index":62,"t":{"598":{"position":[[22,6]]}}}],["drive",{"_index":111,"t":{"1310":{"position":[[16,5]]}}}],["entitl",{"_index":106,"t":{"1261":{"position":[[9,12]]}}}],["expand",{"_index":98,"t":{"1088":{"position":[[35,7]]}}}],["februari",{"_index":11,"t":{"63":{"position":[[20,8]]}}}],["fga",{"_index":38,"t":{"392":{"position":[[8,3]]}}}],["fine",{"_index":4,"t":{"13":{"position":[[0,4]]},"37":{"position":[[0,4]]},"63":{"position":[[0,4]]},"81":{"position":[[0,4]]},"97":{"position":[[0,4]]},"111":{"position":[[0,4]]},"125":{"position":[[0,4]]},"143":{"position":[[0,4]]},"157":{"position":[[0,4]]},"173":{"position":[[0,4]]},"189":{"position":[[0,4]]},"209":{"position":[[0,4]]}}}],["framework",{"_index":51,"t":{"489":{"position":[[19,9]]}}}],["github",{"_index":112,"t":{"1333":{"position":[[9,6]]}}}],["googl",{"_index":110,"t":{"1310":{"position":[[9,6]]}}}],["grain",{"_index":5,"t":{"13":{"position":[[5,7]]},"37":{"position":[[5,7]]},"63":{"position":[[5,7]]},"81":{"position":[[5,7]]},"97":{"position":[[5,7]]},"111":{"position":[[5,7]]},"125":{"position":[[5,7]]},"143":{"position":[[5,7]]},"157":{"position":[[5,7]]},"173":{"position":[[5,7]]},"189":{"position":[[5,7]]},"209":{"position":[[5,7]]}}}],["group",{"_index":71,"t":{"685":{"position":[[9,5]]},"943":{"position":[[5,6]]},"1049":{"position":[[9,5]]}}}],["immut",{"_index":47,"t":{"460":{"position":[[0,9]]}}}],["instal",{"_index":48,"t":{"475":{"position":[[0,7]]}}}],["integr",{"_index":49,"t":{"489":{"position":[[0,9]]}}}],["introduct",{"_index":35,"t":{"382":{"position":[[0,12]]}}}],["invok",{"_index":68,"t":{"634":{"position":[[38,8]]}}}],["iot",{"_index":108,"t":{"1282":{"position":[[30,3]]}}}],["januari",{"_index":9,"t":{"37":{"position":[[20,7]]}}}],["join",{"_index":18,"t":{"187":{"position":[[0,4]]}}}],["juli",{"_index":14,"t":{"125":{"position":[[20,4]]}}}],["june",{"_index":16,"t":{"157":{"position":[[20,4]]}}}],["kubecon",{"_index":20,"t":{"187":{"position":[[25,7]]}}}],["kubernet",{"_index":63,"t":{"616":{"position":[[22,10]]}}}],["languag",{"_index":41,"t":{"414":{"position":[[14,8]]}}}],["list",{"_index":23,"t":{"203":{"position":[[0,4]]},"517":{"position":[[10,4]]},"642":{"position":[[10,4]]}}}],["listobject",{"_index":99,"t":{"1088":{"position":[[43,11]]}}}],["listus",{"_index":100,"t":{"1088":{"position":[[59,9]]}}}],["manag",{"_index":67,"t":{"634":{"position":[[18,8]]},"685":{"position":[[0,8]]},"702":{"position":[[0,8]]},"1049":{"position":[[0,8]]},"1066":{"position":[[0,8]]}}}],["march",{"_index":12,"t":{"81":{"position":[[20,5]]}}}],["membership",{"_index":95,"t":{"1049":{"position":[[15,10]]}}}],["migrat",{"_index":84,"t":{"852":{"position":[[6,10]]},"1205":{"position":[[0,9]]}}}],["mode",{"_index":69,"t":{"660":{"position":[[18,5]]}}}],["model",{"_index":28,"t":{"229":{"position":[[8,6]]},"434":{"position":[[24,5]]},"460":{"position":[[24,6]]},"852":{"position":[[0,5]]},"860":{"position":[[17,8]]},"880":{"position":[[8,6]]},"963":{"position":[[8,6]]},"1261":{"position":[[0,8]]},"1282":{"position":[[0,8]]},"1310":{"position":[[0,8]]},"1333":{"position":[[0,8]]},"1356":{"position":[[0,8]]}}}],["modular",{"_index":27,"t":{"229":{"position":[[0,7]]},"880":{"position":[[0,7]]}}}],["multipl",{"_index":86,"t":{"903":{"position":[[0,8]]}}}],["na",{"_index":21,"t":{"187":{"position":[[33,2]]}}}],["new",{"_index":6,"t":{"13":{"position":[[13,4]]},"37":{"position":[[13,4]]},"63":{"position":[[13,4]]},"81":{"position":[[13,4]]},"97":{"position":[[13,4]]},"111":{"position":[[13,4]]},"125":{"position":[[13,4]]},"143":{"position":[[13,4]]},"157":{"position":[[13,4]]},"173":{"position":[[13,4]]},"189":{"position":[[13,4]]},"209":{"position":[[13,4]]}}}],["novemb",{"_index":22,"t":{"189":{"position":[[20,8]]}}}],["object",{"_index":54,"t":{"517":{"position":[[15,7]]},"921":{"position":[[13,7]]},"1066":{"position":[[31,7]]},"1178":{"position":[[0,6],[10,6]]}}}],["octob",{"_index":17,"t":{"173":{"position":[[20,7]]}}}],["openfga",{"_index":3,"t":{"3":{"position":[[36,7]]},"187":{"position":[[9,7]]},"237":{"position":[[29,7]]},"262":{"position":[[0,7]]},"382":{"position":[[16,7]]},"529":{"position":[[8,7]]},"560":{"position":[[12,7]]},"598":{"position":[[9,7]]},"616":{"position":[[9,7]]},"618":{"position":[[6,7]]},"620":{"position":[[10,7]]},"1261":{"position":[[40,7]]},"1282":{"position":[[55,7]]},"1310":{"position":[[39,7]]},"1333":{"position":[[33,7]]},"1356":{"position":[[38,7]]}}}],["option",{"_index":31,"t":{"237":{"position":[[18,7]]}}}],["organ",{"_index":104,"t":{"1239":{"position":[[22,12]]}}}],["parent",{"_index":88,"t":{"921":{"position":[[0,6]]}}}],["perform",{"_index":52,"t":{"503":{"position":[[0,7]]},"517":{"position":[[0,7]]},"642":{"position":[[0,7]]}}}],["permiss",{"_index":74,"t":{"729":{"position":[[12,11]]},"1221":{"position":[[10,11]]},"1310":{"position":[[22,11]]},"1333":{"position":[[16,11]]}}}],["playground",{"_index":64,"t":{"620":{"position":[[18,10]]}}}],["practic",{"_index":66,"t":{"634":{"position":[[5,9]]}}}],["product",{"_index":57,"t":{"529":{"position":[[19,10]]}}}],["public",{"_index":94,"t":{"1033":{"position":[[0,6]]}}}],["queri",{"_index":29,"t":{"237":{"position":[[0,5]]},"660":{"position":[[0,5]]},"1088":{"position":[[13,8]]}}}],["read",{"_index":97,"t":{"1088":{"position":[[29,5]]}}}],["relat",{"_index":102,"t":{"1205":{"position":[[10,9]]}}}],["relationship",{"_index":1,"t":{"3":{"position":[[12,12]]},"671":{"position":[[7,12]]},"770":{"position":[[11,13]]},"1066":{"position":[[9,13]]},"1088":{"position":[[0,12]]},"1158":{"position":[[7,13]]},"1178":{"position":[[17,13]]}}}],["restrict",{"_index":87,"t":{"903":{"position":[[9,12]]}}}],["role",{"_index":82,"t":{"812":{"position":[[7,5]]},"1221":{"position":[[0,5]]}}}],["run",{"_index":56,"t":{"529":{"position":[[0,7]]}}}],["sdk",{"_index":44,"t":{"446":{"position":[[10,3]]},"475":{"position":[[8,3]]},"626":{"position":[[6,3]]}}}],["search",{"_index":73,"t":{"729":{"position":[[0,6]]}}}],["secur",{"_index":109,"t":{"1282":{"position":[[34,8]]}}}],["septemb",{"_index":15,"t":{"143":{"position":[[20,9]]}}}],["setup",{"_index":58,"t":{"541":{"position":[[0,8]]},"598":{"position":[[3,5]]},"616":{"position":[[3,5]]},"618":{"position":[[0,5]]},"626":{"position":[[0,5]]}}}],["slack",{"_index":113,"t":{"1356":{"position":[[27,5]]}}}],["start",{"_index":85,"t":{"860":{"position":[[4,7]]}}}],["store",{"_index":42,"t":{"434":{"position":[[36,5]]},"442":{"position":[[9,5]]},"626":{"position":[[21,5]]}}}],["system",{"_index":107,"t":{"1261":{"position":[[28,6]]},"1282":{"position":[[43,6]]}}}],["team",{"_index":19,"t":{"187":{"position":[[17,4]]}}}],["telemetri",{"_index":46,"t":{"446":{"position":[[21,9]]}}}],["test",{"_index":90,"t":{"963":{"position":[[0,7]]}}}],["through",{"_index":103,"t":{"1239":{"position":[[14,7]]}}}],["time",{"_index":114,"t":{"1380":{"position":[[15,4]]}}}],["token",{"_index":91,"t":{"981":{"position":[[4,5]]}}}],["transact",{"_index":77,"t":{"751":{"position":[[0,13]]}}}],["tupl",{"_index":2,"t":{"3":{"position":[[25,6]]},"634":{"position":[[27,6]]},"671":{"position":[[20,6]]},"717":{"position":[[11,5]]},"981":{"position":[[31,6]]}}}],["updat",{"_index":70,"t":{"671":{"position":[[0,6]]}}}],["us",{"_index":37,"t":{"392":{"position":[[0,3]]},"620":{"position":[[0,5]]},"745":{"position":[[9,3]]},"981":{"position":[[0,3]]}}}],["user",{"_index":24,"t":{"203":{"position":[[5,5]]},"642":{"position":[[15,5]]},"702":{"position":[[9,4]]},"943":{"position":[[0,4]]}}}],["userset",{"_index":80,"t":{"786":{"position":[[0,8]]}}}],["within",{"_index":50,"t":{"489":{"position":[[10,6]]}}}],["write",{"_index":78,"t":{"751":{"position":[[14,6]]}}}]],"pipeline":["stemmer"]}},{"documents":[{"i":5,"t":"Use Cases","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#use-cases","p":3},{"i":7,"t":"How to use it?","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#how-to-use-it","p":3},{"i":9,"t":"What’s Next?","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#whats-next","p":3},{"i":11,"t":"Reach out!","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#reach-out","p":3},{"i":15,"t":"Team News","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#team-news","p":13},{"i":17,"t":"Behavior Driven Development with OpenFGA","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#behavior-driven-development-with-openfga","p":13},{"i":19,"t":"GoDaddy & OpenFGA","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#godaddy--openfga","p":13},{"i":21,"t":"Canonical & OpenFGA","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#canonical--openfga","p":13},{"i":23,"t":"OpenFGA v1.4!","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#openfga-v14","p":13},{"i":25,"t":"SDK Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#sdk-improvements","p":13},{"i":27,"t":"Language Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#language-improvements","p":13},{"i":29,"t":"VS Code Extension Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#vs-code-extension-improvements","p":13},{"i":31,"t":"KubeCon EU 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#kubecon-eu-2024","p":13},{"i":33,"t":"OpenFGA Community","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#openfga-community","p":13},{"i":35,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#see-you-next-month","p":13},{"i":39,"t":"Team News","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#team-news","p":37},{"i":41,"t":"KubeCon Europe 2024!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#kubecon-europe-2024","p":37},{"i":43,"t":"OpenFGA ⚡️Enlightning Session!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#openfga-️enlightning-session","p":37},{"i":45,"t":"Visual Studio Code Integration Enhancements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#visual-studio-code-integration-enhancements","p":37},{"i":47,"t":"CLI improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#cli-improvements","p":37},{"i":49,"t":"OpenFGA v1.4.3","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#openfga-v143","p":37},{"i":51,"t":"SDK Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#sdk-improvements","p":37},{"i":53,"t":"Language Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#language-improvements","p":37},{"i":55,"t":"Github Actions","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#github-actions","p":37},{"i":57,"t":"What's Next? Check our RFCs!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#whats-next-check-our-rfcs","p":37},{"i":59,"t":"OpenFGA Community","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#openfga-community","p":37},{"i":61,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#see-you-next-month","p":37},{"i":65,"t":"KubeCon Europe 2024 is getting closer!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#kubecon-europe-2024-is-getting-closer","p":63},{"i":67,"t":"Documentation Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#documentation-improvements","p":63},{"i":69,"t":"OpenFGA in the Java Ecosystem","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#openfga-in-the-java-ecosystem","p":63},{"i":71,"t":"SDK Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#sdk-improvements","p":63},{"i":73,"t":"Modular Models","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#modular-models","p":63},{"i":75,"t":"Community News","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#community-news","p":63},{"i":77,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#transitioning-from-discord-to-cncfs-slack","p":63},{"i":79,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#see-you-next-month","p":63},{"i":83,"t":"KubeCon Europe 2024 was super-busy!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#kubecon-europe-2024-was-super-busy","p":81},{"i":85,"t":"CNCF incubation","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#cncf-incubation","p":81},{"i":87,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#new-adopters","p":81},{"i":89,"t":"Community News","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#community-news","p":81},{"i":91,"t":"New Releases","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#new-releases","p":81},{"i":93,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#transitioning-from-discord-to-cncfs-slack","p":81},{"i":95,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#see-you-next-month","p":81},{"i":99,"t":"New Releases!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#new-releases","p":97},{"i":101,"t":"OpenFGA Hackathon","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#openfga-hackathon","p":97},{"i":103,"t":"OpenFGA Security Assessment","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#openfga-security-assessment","p":97},{"i":105,"t":"What's Next","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#whats-next","p":97},{"i":107,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#transitioning-from-discord-to-cncfs-slack","p":97},{"i":109,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#see-you-next-month","p":97},{"i":113,"t":"New Releases!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#new-releases","p":111},{"i":115,"t":"What's Next","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#whats-next","p":111},{"i":117,"t":"OpenFGA @ CloudNative SecurityCon","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#openfga--cloudnative-securitycon","p":111},{"i":119,"t":"Latest Features","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#latest-features","p":111},{"i":121,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#transitioning-from-discord-to-cncfs-slack","p":111},{"i":123,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#see-you-next-month","p":111},{"i":127,"t":"Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#improvements","p":125},{"i":129,"t":"Breaking Changes","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#breaking-changes","p":125},{"i":131,"t":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#in-progress","p":125},{"i":133,"t":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#community-highlights","p":125},{"i":135,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#new-adopters","p":125},{"i":137,"t":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#announcements","p":125},{"i":139,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#transitioning-from-discord-to-cncfs-slack","p":125},{"i":141,"t":"See You Next Month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#see-you-next-month","p":125},{"i":145,"t":"Just Shipped","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#just-shipped","p":143},{"i":147,"t":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#in-progress","p":143},{"i":149,"t":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#community-highlights","p":143},{"i":151,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#new-adopters","p":143},{"i":153,"t":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#announcements","p":143},{"i":155,"t":"See You Next Month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#see-you-next-month","p":143},{"i":159,"t":"What are we working on?","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#what-are-we-working-on","p":157},{"i":161,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#new-adopters","p":157},{"i":163,"t":"Community","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#community","p":157},{"i":165,"t":"OpenFGA @ CloudNative SecurityCon","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#openfga--cloudnative-securitycon","p":157},{"i":167,"t":"Latest Features","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#latest-features","p":157},{"i":169,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#transitioning-from-discord-to-cncfs-slack","p":157},{"i":171,"t":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#see-you-next-month","p":157},{"i":175,"t":"Just Shipped","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#just-shipped","p":173},{"i":177,"t":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#in-progress","p":173},{"i":179,"t":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#community-highlights","p":173},{"i":181,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#new-adopters","p":173},{"i":183,"t":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#announcements","p":173},{"i":185,"t":"See you Next Month","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#see-you-next-month","p":173},{"i":191,"t":"Just Shipped","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#just-shipped","p":189},{"i":193,"t":"Coming Up","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#coming-up","p":189},{"i":195,"t":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#community-highlights","p":189},{"i":197,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#new-adopters","p":189},{"i":199,"t":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#announcements","p":189},{"i":201,"t":"See You Next Month:","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#see-you-next-month","p":189},{"i":205,"t":"How to use it?","u":"/pr-preview/pr-921/blog/list-users-announcement","h":"#how-to-use-it","p":203},{"i":207,"t":"We want your feedback!","u":"/pr-preview/pr-921/blog/list-users-announcement","h":"#we-want-your-feedback","p":203},{"i":211,"t":"Just Shipped!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#just-shipped","p":209},{"i":213,"t":"Security Advisory","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#security-advisory","p":209},{"i":215,"t":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#in-progress","p":209},{"i":217,"t":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#community-highlights","p":209},{"i":219,"t":"Upcoming Events","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#upcoming-events","p":209},{"i":221,"t":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#new-adopters","p":209},{"i":223,"t":"OpenFGA Service Providers","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#openfga-service-providers","p":209},{"i":225,"t":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#announcements","p":209},{"i":227,"t":"See You Next Month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#see-you-next-month","p":209},{"i":231,"t":"How to use it?","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"#how-to-use-it","p":229},{"i":233,"t":"What's next?","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"#whats-next","p":229},{"i":235,"t":"Reach out!","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"#reach-out","p":229},{"i":239,"t":"How to use it?","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#how-to-use-it","p":237},{"i":241,"t":"Custom database adapter implementations","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#custom-database-adapter-implementations","p":237},{"i":243,"t":"Future work","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#future-work","p":237},{"i":245,"t":"We want your feedback!","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#we-want-your-feedback","p":237},{"i":248,"t":"Authentication and Authorization","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#authentication-and-authorization","p":247},{"i":250,"t":"What is Fine-Grained Authorization?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-fine-grained-authorization","p":247},{"i":252,"t":"What is Role-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-role-based-access-control","p":247},{"i":254,"t":"What is Attribute-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-attribute-based-access-control","p":247},{"i":256,"t":"What is Policy-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-policy-based-access-control","p":247},{"i":258,"t":"What is Relationship-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-relationship-based-access-control","p":247},{"i":260,"t":"What is Zanzibar?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-zanzibar","p":247},{"i":263,"t":"Slack (CNCF Community)","u":"/pr-preview/pr-921/docs/community","h":"#slack-cncf-community","p":262},{"i":265,"t":"GitHub Discussions","u":"/pr-preview/pr-921/docs/community","h":"#github-discussions","p":262},{"i":267,"t":"X (formerly Twitter)","u":"/pr-preview/pr-921/docs/community","h":"#x-formerly-twitter","p":262},{"i":269,"t":"YouTube","u":"/pr-preview/pr-921/docs/community","h":"#youtube","p":262},{"i":271,"t":"LinkedIn","u":"/pr-preview/pr-921/docs/community","h":"#linkedin","p":262},{"i":273,"t":"Mastodon","u":"/pr-preview/pr-921/docs/community","h":"#mastodon","p":262},{"i":275,"t":"Monthly Community Meetings","u":"/pr-preview/pr-921/docs/community","h":"#monthly-community-meetings","p":262},{"i":278,"t":"Modular Models","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":280,"t":"How to use it?","u":"/pr-preview/pr-921/blog/page/2","h":"#how-to-use-it","p":277},{"i":282,"t":"What's next?","u":"/pr-preview/pr-921/blog/page/2","h":"#whats-next","p":277},{"i":284,"t":"Reach out!","u":"/pr-preview/pr-921/blog/page/2","h":"#reach-out","p":277},{"i":286,"t":"Fine Grained News - March 2024","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":288,"t":"KubeCon Europe 2024 was super-busy!","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-europe-2024-was-super-busy","p":277},{"i":290,"t":"CNCF incubation","u":"/pr-preview/pr-921/blog/page/2","h":"#cncf-incubation","p":277},{"i":292,"t":"New Adopters","u":"/pr-preview/pr-921/blog/page/2","h":"#new-adopters","p":277},{"i":294,"t":"Community News","u":"/pr-preview/pr-921/blog/page/2","h":"#community-news","p":277},{"i":296,"t":"New Releases","u":"/pr-preview/pr-921/blog/page/2","h":"#new-releases","p":277},{"i":298,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/page/2","h":"#transitioning-from-discord-to-cncfs-slack","p":277},{"i":300,"t":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":302,"t":"Fine Grained News - February 2024","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":304,"t":"KubeCon Europe 2024 is getting closer!","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-europe-2024-is-getting-closer","p":277},{"i":306,"t":"Documentation Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#documentation-improvements","p":277},{"i":308,"t":"OpenFGA in the Java Ecosystem","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-in-the-java-ecosystem","p":277},{"i":310,"t":"SDK Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#sdk-improvements","p":277},{"i":312,"t":"Modular Models","u":"/pr-preview/pr-921/blog/page/2","h":"#modular-models","p":277},{"i":314,"t":"Community News","u":"/pr-preview/pr-921/blog/page/2","h":"#community-news","p":277},{"i":316,"t":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/page/2","h":"#transitioning-from-discord-to-cncfs-slack","p":277},{"i":318,"t":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":320,"t":"Fine Grained News - January 2024","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":322,"t":"Team News","u":"/pr-preview/pr-921/blog/page/2","h":"#team-news","p":277},{"i":324,"t":"KubeCon Europe 2024!","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-europe-2024","p":277},{"i":326,"t":"OpenFGA ⚡️Enlightning Session!","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-️enlightning-session","p":277},{"i":328,"t":"Visual Studio Code Integration Enhancements","u":"/pr-preview/pr-921/blog/page/2","h":"#visual-studio-code-integration-enhancements","p":277},{"i":330,"t":"CLI improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#cli-improvements","p":277},{"i":332,"t":"OpenFGA v1.4.3","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-v143","p":277},{"i":334,"t":"SDK Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#sdk-improvements","p":277},{"i":336,"t":"Language Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#language-improvements","p":277},{"i":338,"t":"Github Actions","u":"/pr-preview/pr-921/blog/page/2","h":"#github-actions","p":277},{"i":340,"t":"What's Next? Check our RFCs!","u":"/pr-preview/pr-921/blog/page/2","h":"#whats-next-check-our-rfcs","p":277},{"i":342,"t":"OpenFGA Community","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-community","p":277},{"i":344,"t":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":346,"t":"Fine Grained News - December 2023","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":348,"t":"Team News","u":"/pr-preview/pr-921/blog/page/2","h":"#team-news","p":277},{"i":350,"t":"Behavior Driven Development with OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"#behavior-driven-development-with-openfga","p":277},{"i":352,"t":"GoDaddy & OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"#godaddy--openfga","p":277},{"i":354,"t":"Canonical & OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"#canonical--openfga","p":277},{"i":356,"t":"OpenFGA v1.4!","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-v14","p":277},{"i":358,"t":"SDK Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#sdk-improvements","p":277},{"i":360,"t":"Language Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#language-improvements","p":277},{"i":362,"t":"VS Code Extension Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#vs-code-extension-improvements","p":277},{"i":364,"t":"KubeCon EU 2024","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-eu-2024","p":277},{"i":366,"t":"OpenFGA Community","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-community","p":277},{"i":368,"t":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":370,"t":"Conditional Relationship Tuples for OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":372,"t":"Use Cases","u":"/pr-preview/pr-921/blog/page/2","h":"#use-cases","p":277},{"i":374,"t":"How to use it?","u":"/pr-preview/pr-921/blog/page/2","h":"#how-to-use-it","p":277},{"i":376,"t":"What’s Next?","u":"/pr-preview/pr-921/blog/page/2","h":"#whats-next","p":277},{"i":378,"t":"Reach out!","u":"/pr-preview/pr-921/blog/page/2","h":"#reach-out","p":277},{"i":380,"t":"Join the OpenFGA team at KubeCon NA 2023","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":384,"t":"Benefits","u":"/pr-preview/pr-921/docs/fga","h":"#benefits","p":382},{"i":386,"t":"Features","u":"/pr-preview/pr-921/docs/fga","h":"#features","p":382},{"i":388,"t":"Related Sections","u":"/pr-preview/pr-921/docs/fga","h":"#related-sections","p":382},{"i":394,"t":"Configuration","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#configuration","p":392},{"i":396,"t":"Basic operations","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#basic-operations","p":392},{"i":398,"t":"Work with authorization model versions","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#work-with-authorization-model-versions","p":392},{"i":400,"t":"Import tuples","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#import-tuples","p":392},{"i":402,"t":"yaml","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#yaml","p":392},{"i":404,"t":"JSON","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#json","p":392},{"i":406,"t":"CSV","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#csv","p":392},{"i":408,"t":"Delete Tuples","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#delete-tuples","p":392},{"i":410,"t":"Import stores","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#import-stores","p":392},{"i":412,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#related-sections","p":392},{"i":416,"t":"What Does The Configuration Language Look Like?","u":"/pr-preview/pr-921/docs/configuration-language","h":"#what-does-the-configuration-language-look-like","p":414},{"i":418,"t":"Direct Relationship Type Restrictions","u":"/pr-preview/pr-921/docs/configuration-language","h":"#direct-relationship-type-restrictions","p":414},{"i":420,"t":"Referencing Other Relations On The Same Object","u":"/pr-preview/pr-921/docs/configuration-language","h":"#referencing-other-relations-on-the-same-object","p":414},{"i":422,"t":"Referencing Relations On Related Objects","u":"/pr-preview/pr-921/docs/configuration-language","h":"#referencing-relations-on-related-objects","p":414},{"i":424,"t":"The Union Operator","u":"/pr-preview/pr-921/docs/configuration-language","h":"#the-union-operator","p":414},{"i":426,"t":"The Intersection Operator","u":"/pr-preview/pr-921/docs/configuration-language","h":"#the-intersection-operator","p":414},{"i":428,"t":"The Exclusion Operator","u":"/pr-preview/pr-921/docs/configuration-language","h":"#the-exclusion-operator","p":414},{"i":430,"t":"Equivalent Zanzibar Concepts","u":"/pr-preview/pr-921/docs/configuration-language","h":"#equivalent-zanzibar-concepts","p":414},{"i":432,"t":"Related Sections","u":"/pr-preview/pr-921/docs/configuration-language","h":"#related-sections","p":414},{"i":436,"t":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"#before-you-start","p":434},{"i":438,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"#step-by-step","p":434},{"i":440,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"#related-sections","p":434},{"i":444,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/create-store","h":"#step-by-step","p":442},{"i":448,"t":"Enabling Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#enabling-telemetry","p":446},{"i":450,"t":"Customizing Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#customizing-telemetry","p":446},{"i":452,"t":"Examples","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#examples","p":446},{"i":454,"t":"Supported Metrics","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#supported-metrics","p":446},{"i":456,"t":"Supported Attributes","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#supported-attributes","p":446},{"i":458,"t":"Tracing","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#tracing","p":446},{"i":462,"t":"Viewing all the authorization models","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#viewing-all-the-authorization-models","p":460},{"i":464,"t":"How to target a particular model","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#how-to-target-a-particular-model","p":460},{"i":466,"t":"Benefits of passing in an authorization model ID","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#benefits-of-passing-in-an-authorization-model-id","p":460},{"i":468,"t":"Potential use-cases","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#potential-use-cases","p":460},{"i":469,"t":"Complex model migrations","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#complex-model-migrations","p":460},{"i":471,"t":"Progresivelly rollout changes","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#progresivelly-rollout-changes","p":460},{"i":473,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#related-sections","p":460},{"i":477,"t":"Brew","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#brew","p":475},{"i":479,"t":"Linux (deb, rpm and apk) packages","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#linux-deb-rpm-and-apk-packages","p":475},{"i":481,"t":"Docker","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#docker","p":475},{"i":483,"t":"Go","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#go","p":475},{"i":485,"t":"Manually","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#manually","p":475},{"i":487,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#related-sections","p":475},{"i":491,"t":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#before-you-start","p":489},{"i":493,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#step-by-step","p":489},{"i":495,"t":"01. Install and setup framework","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#01-install-and-setup-framework","p":489},{"i":497,"t":"02. Authenticate and get user ID","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#02-authenticate-and-get-user-id","p":489},{"i":499,"t":"03. Integrate the OpenFGA check API into the service","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#03-integrate-the--check-api-into-the-service","p":489},{"i":501,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#related-sections","p":489},{"i":505,"t":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#before-you-start","p":503},{"i":507,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#step-by-step","p":503},{"i":509,"t":"01. Configure the OpenFGA API client","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#01-configure-the--api-client","p":503},{"i":511,"t":"02. Calling Check API","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#02-calling-check-api","p":503},{"i":513,"t":"03. Calling Batch Check API","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#03-calling-batch-check-api","p":503},{"i":515,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#related-sections","p":503},{"i":519,"t":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#before-you-start","p":517},{"i":521,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#step-by-step","p":517},{"i":523,"t":"01. Configure the OpenFGA API client","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#01-configure-the--api-client","p":517},{"i":525,"t":"02. Calling list objects API","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#02-calling-list-objects-api","p":517},{"i":527,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#related-sections","p":517},{"i":531,"t":"Cluster recommendations","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#cluster-recommendations","p":529},{"i":533,"t":"Database recommendations","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#database-recommendations","p":529},{"i":535,"t":"Concurrency limits","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#concurrency-limits","p":529},{"i":537,"t":"Maximum results","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#maximum-results","p":529},{"i":539,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#related-sections","p":529},{"i":543,"t":"Requirements","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#requirements","p":541},{"i":545,"t":"01. Ensure the server is running (with access control disabled)","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#01-ensure-the-server-is-running-with-access-control-disabled","p":541},{"i":547,"t":"02. Create the access control store and model","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#02-create-the-access-control-store-and-model","p":541},{"i":549,"t":"03. Enable access control","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#03-enable-access-control","p":541},{"i":550,"t":"i. Enable access control in the server","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#i-enable-access-control-in-the-server","p":541},{"i":552,"t":"ii. Customize what claim you want the API to use (optional)","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#ii-customize-what-claim-you-want-the-api-to-use-optional","p":541},{"i":554,"t":"iii. Restart the server","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#iii-restart-the-server","p":541},{"i":556,"t":"04. Grant access to a store","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#04-grant-access-to-a-store","p":541},{"i":558,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#related-sections","p":541},{"i":562,"t":"Using a configuration file","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#using-a-configuration-file","p":560},{"i":564,"t":"Using environment variables","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#using-environment-variables","p":560},{"i":566,"t":"Using command line variables","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#using-command-line-variables","p":560},{"i":568,"t":"Configuring data storage","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#configuring-data-storage","p":560},{"i":570,"t":"Postgres","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#postgres","p":560},{"i":572,"t":"MySQL","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#mysql","p":560},{"i":574,"t":"SQLite","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#sqlite","p":560},{"i":576,"t":"Configuring authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#configuring-authentication","p":560},{"i":578,"t":"Pre-shared key authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#pre-shared-key-authentication","p":560},{"i":580,"t":"OIDC","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#oidc","p":560},{"i":582,"t":"Profiler (pprof)","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#profiler-pprof","p":560},{"i":584,"t":"Health check","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#health-check","p":560},{"i":586,"t":"Experimental features","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#experimental-features","p":560},{"i":588,"t":"Telemetry","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#telemetry","p":560},{"i":590,"t":"Metrics","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#metrics","p":560},{"i":592,"t":"Tracing","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#tracing","p":560},{"i":594,"t":"Logging","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#logging","p":560},{"i":596,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#related-sections","p":560},{"i":600,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#step-by-step","p":598},{"i":602,"t":"Using Postgres","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#using-postgres","p":598},{"i":604,"t":"Using MySQL","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#using-mysql","p":598},{"i":606,"t":"Using SQLite","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#using-sqlite","p":598},{"i":608,"t":"Pre-shared key authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#pre-shared-key-authentication","p":598},{"i":610,"t":"OIDC authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#oidc-authentication","p":598},{"i":612,"t":"Enabling profiling","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#enabling-profiling","p":598},{"i":614,"t":"Related sections","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#related-sections","p":598},{"i":622,"t":"Running the Playground in a different port","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/playground","h":"#running-the-playground-in-a-different-port","p":620},{"i":624,"t":"Disabling the Playground","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/playground","h":"#disabling-the-playground","p":620},{"i":628,"t":"Using No Authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-sdk-client","h":"#using-no-authentication","p":626},{"i":630,"t":"Using shared key authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-sdk-client","h":"#using-shared-key-authentication","p":626},{"i":632,"t":"Using client credentials flow","u":"/pr-preview/pr-921/docs/getting-started/setup-sdk-client","h":"#using-client-credentials-flow","p":626},{"i":636,"t":"Do Not Store Personal Identifiable Information in Tuples","u":"/pr-preview/pr-921/docs/getting-started/tuples-api-best-practices","h":"#do-not-store-personal-identifiable-information-in-tuples","p":634},{"i":638,"t":"Always specify authorization model ID whenever possible","u":"/pr-preview/pr-921/docs/getting-started/tuples-api-best-practices","h":"#always-specify-authorization-model-id-whenever-possible","p":634},{"i":640,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/tuples-api-best-practices","h":"#related-sections","p":634},{"i":644,"t":"Before You Start","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#before-you-start","p":642},{"i":646,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#step-by-step","p":642},{"i":648,"t":"01. Configure the OpenFGA API client","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#01-configure-the--api-client","p":642},{"i":650,"t":"02. Calling List Users API","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#02-calling-list-users-api","p":642},{"i":652,"t":"Usersets","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#usersets","p":642},{"i":654,"t":"Type-bound public access","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#type-bound-public-access","p":642},{"i":656,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","h":"#related-sections","p":642},{"i":661,"t":"Background","u":"/pr-preview/pr-921/docs/interacting/consistency","h":"#background","p":660},{"i":663,"t":"When to use higher consistency","u":"/pr-preview/pr-921/docs/interacting/consistency","h":"#when-to-use-higher-consistency","p":660},{"i":665,"t":"Cache expiration","u":"/pr-preview/pr-921/docs/interacting/consistency","h":"#cache-expiration","p":660},{"i":667,"t":"Future work","u":"/pr-preview/pr-921/docs/interacting/consistency","h":"#future-work","p":660},{"i":669,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/consistency","h":"#related-sections","p":660},{"i":673,"t":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","h":"#before-you-start","p":671},{"i":675,"t":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","h":"#step-by-step","p":671},{"i":677,"t":"01. Configure the OpenFGA API client","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","h":"#01-configure-the--api-client","p":671},{"i":679,"t":"02. Calling write API to add new relationship tuples","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","h":"#02-calling-write-api-to-add-new-relationship-tuples","p":671},{"i":681,"t":"03. Calling write API to delete relationship tuples","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","h":"#03-calling-write-api-to-delete-relationship-tuples","p":671},{"i":683,"t":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","h":"#related-sections","p":671},{"i":687,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#before-you-start","p":685},{"i":689,"t":"Modeling user groups","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#modeling-user-groups","p":685},{"i":691,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#-concepts","p":685},{"i":693,"t":"Step by step","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#step-by-step","p":685},{"i":694,"t":"01. Adding company to the document","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#01-adding-company-to-the-document","p":685},{"i":696,"t":"02. Add an employee to the company","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#02-add-an-employee-to-the-company","p":685},{"i":698,"t":"03. Checking an individual member's access to an object","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#03-checking-an-individual-members-access-to-an-object","p":685},{"i":700,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","h":"#related-sections","p":685},{"i":704,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#before-you-start","p":702},{"i":706,"t":"Direct access","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#direct-access","p":702},{"i":708,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#-concepts","p":702},{"i":710,"t":"Step by step","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#step-by-step","p":702},{"i":711,"t":"01. Adding direct relationship","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#01-adding-direct-relationship","p":702},{"i":713,"t":"02. Removing direct relationship","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#02-removing-direct-relationship","p":702},{"i":715,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","h":"#related-sections","p":702},{"i":719,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","h":"#before-you-start","p":717},{"i":721,"t":"Step by step","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","h":"#step-by-step","p":717},{"i":723,"t":"01. Configure The OpenFGA API Client","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","h":"#01-configure-the--api-client","p":717},{"i":725,"t":"02. Get changes for all object types","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","h":"#02-get-changes-for-all-object-types","p":717},{"i":727,"t":"03. Get changes for a specific object type","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","h":"#03-get-changes-for-a-specific-object-type","p":717},{"i":731,"t":"Possible options","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","h":"#possible-options","p":729},{"i":733,"t":"Option 1: Search, then check","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","h":"#option-1-search-then-check","p":729},{"i":735,"t":"Option 2: Build a local index from changes endpoint, search, then check","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","h":"#option-2-build-a-local-index-from-changes-endpoint-search-then-check","p":729},{"i":737,"t":"Option 3: Build a list of IDs, then search","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","h":"#option-3-build-a-list-of-ids-then-search","p":729},{"i":739,"t":"Choosing the best option","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","h":"#choosing-the-best-option","p":729},{"i":741,"t":"Summary","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","h":"#summary","p":729},{"i":747,"t":"Use-cases","u":"/pr-preview/pr-921/docs/modeling/advanced","h":"#use-cases","p":745},{"i":749,"t":"Patterns","u":"/pr-preview/pr-921/docs/modeling/advanced","h":"#patterns","p":745},{"i":753,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#before-you-start","p":751},{"i":755,"t":"Direct access","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#direct-access","p":751},{"i":757,"t":"Modeling public access","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#modeling-public-access","p":751},{"i":759,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#-concepts","p":751},{"i":761,"t":"Step by step","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#step-by-step","p":751},{"i":762,"t":"01. Add and remove relationship tuples in the same transaction","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#01-add-and-remove-relationship-tuples-in-the-same-transaction","p":751},{"i":764,"t":"02. Add multiple related relationship tuples in the same transaction","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#02-add-multiple-related-relationship-tuples-in-the-same-transaction","p":751},{"i":766,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","h":"#related-sections","p":751},{"i":772,"t":"Before You Start","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#before-you-start","p":770},{"i":774,"t":"Modeling User Groups","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#modeling-user-groups","p":770},{"i":776,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#-concepts","p":770},{"i":778,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#step-by-step","p":770},{"i":780,"t":"01. Modify our model to imply editor as viewer","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#01-modify-our-model-to-imply-editor-as-viewer","p":770},{"i":782,"t":"02. Check that editors are viewers","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#02-check-that-editors-are-viewers","p":770},{"i":784,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","h":"#related-sections","p":770},{"i":787,"t":"What is a userset?","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","h":"#what-is-a-userset","p":786},{"i":789,"t":"How do check requests work with usersets?","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","h":"#how-do-check-requests-work-with-usersets","p":786},{"i":791,"t":"How do expand requests work with usersets?","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","h":"#how-do-expand-requests-work-with-usersets","p":786},{"i":793,"t":"Internals","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","h":"#internals","p":786},{"i":795,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","h":"#related-sections","p":786},{"i":798,"t":"Overview","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#overview","p":797},{"i":800,"t":"Defining conditions in models","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#defining-conditions-in-models","p":797},{"i":802,"t":"Writing conditional relationship tuples","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#writing-conditional-relationship-tuples","p":797},{"i":804,"t":"Queries with condition context","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#queries-with-condition-context","p":797},{"i":806,"t":"Examples","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#examples","p":797},{"i":808,"t":"Supported parameter types","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#supported-parameter-types","p":797},{"i":810,"t":"Limitations","u":"/pr-preview/pr-921/docs/modeling/conditions","h":"#limitations","p":797},{"i":814,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#before-you-start","p":812},{"i":816,"t":"Initial Model","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#initial-model","p":812},{"i":818,"t":"Modeling Roles and Permissions","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#modeling-roles-and-permissions","p":812},{"i":820,"t":"Modeling Object-to-Object Relationships","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#modeling-object-to-object-relationships","p":812},{"i":822,"t":"Concepts & Configuration Language","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#concepts--configuration-language","p":812},{"i":824,"t":"Step By Step","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#step-by-step","p":812},{"i":826,"t":"01. Update The Authorization Model To Add A Role Type","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#01-update-the-authorization-model-to-add-a-role-type","p":812},{"i":828,"t":"02.Use Relationship Tuples To Tie The Users To The Roles","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#02use-relationship-tuples-to-tie-the-users-to-the-roles","p":812},{"i":830,"t":"03. Use Relationship Tuples To Associate Permissions With The Roles","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#03-use-relationship-tuples-to-associate-permissions-with-the-roles","p":812},{"i":832,"t":"04. Verify That The Authorization Model Works","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#04-verify-that-the-authorization-model-works","p":812},{"i":834,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/custom-roles","h":"#related-sections","p":812},{"i":838,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/direct-access","h":"#before-you-start","p":836},{"i":840,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/direct-access","h":"#-concepts","p":836},{"i":842,"t":"Step By Step","u":"/pr-preview/pr-921/docs/modeling/direct-access","h":"#step-by-step","p":836},{"i":844,"t":"01. Create A Relationship Tuple","u":"/pr-preview/pr-921/docs/modeling/direct-access","h":"#01-create-a-relationship-tuple","p":836},{"i":846,"t":"02. Check That The Relationship Exists","u":"/pr-preview/pr-921/docs/modeling/direct-access","h":"#02-check-that-the-relationship-exists","p":836},{"i":848,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/direct-access","h":"#related-sections","p":836},{"i":854,"t":"To add a type or relation","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-models","h":"#to-add-a-type-or-relation","p":852},{"i":856,"t":"To delete a type or relation","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-models","h":"#to-delete-a-type-or-relation","p":852},{"i":858,"t":"To rename a type or relation","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-models","h":"#to-rename-a-type-or-relation","p":852},{"i":862,"t":"Introduction To Modeling","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#introduction-to-modeling","p":860},{"i":864,"t":"A Process For Defining Authorization Models","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#a-process-for-defining-authorization-models","p":860},{"i":866,"t":"01. Pick The Most Important Feature","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#01-pick-the-most-important-feature","p":860},{"i":868,"t":"02. List The Object Types","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#02-list-the-object-types","p":860},{"i":870,"t":"03. List Relations For Those Types","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#03-list-relations-for-those-types","p":860},{"i":872,"t":"04. Define Relations","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#04-define-relations","p":860},{"i":874,"t":"05. Test The Model","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#05-test-the-model","p":860},{"i":876,"t":"06. Iterate","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#06-iterate","p":860},{"i":878,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/getting-started","h":"#related-sections","p":860},{"i":882,"t":"Key Concepts","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#key-concepts","p":880},{"i":883,"t":"fga.mod","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#fgamod","p":880},{"i":885,"t":"Modules","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#modules","p":880},{"i":887,"t":"Type Extensions","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#type-extensions","p":880},{"i":889,"t":"Example","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#example","p":880},{"i":891,"t":"Core","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#core","p":880},{"i":893,"t":"Issue tracking","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#issue-tracking","p":880},{"i":895,"t":"Wiki","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#wiki","p":880},{"i":897,"t":"fga.mod","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#fgamod-1","p":880},{"i":899,"t":"Putting it all together","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#putting-it-all-together","p":880},{"i":901,"t":"Viewing the model","u":"/pr-preview/pr-921/docs/modeling/modular-models","h":"#viewing-the-model","p":880},{"i":905,"t":"Before You Start","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#before-you-start","p":903},{"i":907,"t":"Modeling Parent-Child Objects","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#modeling-parent-child-objects","p":903},{"i":909,"t":"Modeling Roles And Permissions","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#modeling-roles-and-permissions","p":903},{"i":911,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#-concepts","p":903},{"i":913,"t":"Step By Step","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#step-by-step","p":903},{"i":915,"t":"01. Add can_delete Relation To Only Allow Writers That Are Members Of The Ownership Organization","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#01-add-can_delete-relation-to-only-allow-writers-that-are-members-of-the-ownership-organization","p":903},{"i":917,"t":"02. Verify That Our Solutions Work","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#02-verify-that-our-solutions-work","p":903},{"i":919,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","h":"#related-sections","p":903},{"i":923,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#before-you-start","p":921},{"i":925,"t":"Direct access","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#direct-access","p":921},{"i":927,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#-concepts","p":921},{"i":929,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#step-by-step","p":921},{"i":931,"t":"01. Update the Athorization Model to allow a parent relationship between folder and document","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#01-update-the-athorization-model-to-allow-a-parent-relationship-between-folder-and-document","p":921},{"i":933,"t":"02. Update the editor relation in the document type definition to support cascading from folder","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#02-update-the-editor-relation-in-the-document-type-definition-to-support-cascading-from-folder","p":921},{"i":935,"t":"03. Create a new relationship tuple to indicate that bob is an editor of folder:notes","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#03-create-a-new-relationship-tuple-to-indicate-that-bob-is-an-editor-of-foldernotes","p":921},{"i":937,"t":"04. Create a new relationship tuple to indicate that folder:notes is a parent of document:meeting_notes.doc","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#04-create-a-new-relationship-tuple-to-indicate-that-foldernotes-is-a-parent-of-documentmeeting_notesdoc","p":921},{"i":939,"t":"05. Check if bob is an editor of document:meeting_notes.doc","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#05-check-if-bob-is-an-editor-of-documentmeeting_notesdoc","p":921},{"i":941,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/parent-child","h":"#related-sections","p":921},{"i":945,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#before-you-start","p":943},{"i":947,"t":"Direct Access","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#direct-access","p":943},{"i":949,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#-concepts","p":943},{"i":951,"t":"Step By Step","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#step-by-step","p":943},{"i":953,"t":"01. Introduce the concept of a team to the authorization model","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#step-1","p":943},{"i":955,"t":"02. Add users as members to the team","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#step-2","p":943},{"i":957,"t":"03. Assign the team members a relation to an object","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#step-3","p":943},{"i":959,"t":"04. Check an individual member's access to an object","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#step-4","p":943},{"i":961,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/user-groups","h":"#related-sections","p":943},{"i":965,"t":"Define the model and tuples","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#define-the-model-and-tuples","p":963},{"i":967,"t":"Write tests","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#write-tests","p":963},{"i":969,"t":"Write Check tests","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#write-check-tests","p":963},{"i":971,"t":"Write List Objects tests","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#write-list-objects-tests","p":963},{"i":973,"t":"Write List Users tests","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#write-list-users-tests","p":963},{"i":975,"t":"Running tests","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#running-tests","p":963},{"i":977,"t":"Running tests using GitHub Actions","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#running-tests-using-github-actions","p":963},{"i":979,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/testing","h":"#related-sections","p":963},{"i":983,"t":"Before You Start","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","h":"#before-you-start","p":981},{"i":985,"t":"User Directories, Identity Tokens, And Relationships","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","h":"#user-directories-identity-tokens-and-relationships","p":981},{"i":987,"t":"Example","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","h":"#example","p":981},{"i":989,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","h":"#related-sections","p":981},{"i":993,"t":"What Is A Type?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-type","p":991},{"i":995,"t":"What Is A Type Definition?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-type-definition","p":991},{"i":997,"t":"What Is An Authorization Model?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-an-authorization-model","p":991},{"i":999,"t":"What Is A Store?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-store","p":991},{"i":1001,"t":"What Is An Object?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-an-object","p":991},{"i":1003,"t":"What Is A User?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-user","p":991},{"i":1005,"t":"What Is A Relation?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-relation","p":991},{"i":1007,"t":"What Is A Relation Definition?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-relation-definition","p":991},{"i":1009,"t":"What Is A Directly Related User Type?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-directly-related-user-type","p":991},{"i":1011,"t":"What is a Condition?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-condition","p":991},{"i":1013,"t":"What Is A Relationship Tuple?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-relationship-tuple","p":991},{"i":1015,"t":"What Is A Conditional Relationship Tuple?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-conditional-relationship-tuple","p":991},{"i":1017,"t":"What Is A Relationship?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-relationship","p":991},{"i":1019,"t":"What Are Direct And Implied Relationships?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-are-direct-and-implied-relationships","p":991},{"i":1021,"t":"What Is A Check Request?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-check-request","p":991},{"i":1023,"t":"What Is A List Objects Request?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-list-objects-request","p":991},{"i":1025,"t":"What Is A List Users Request?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-a-list-users-request","p":991},{"i":1027,"t":"What Are Contextual Tuples?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-are-contextual-tuples","p":991},{"i":1029,"t":"What Is Type Bound Public Access?","u":"/pr-preview/pr-921/docs/concepts","h":"#what-is-type-bound-public-access","p":991},{"i":1031,"t":"Related Sections","u":"/pr-preview/pr-921/docs/concepts","h":"#related-sections","p":991},{"i":1035,"t":"Before You Start","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#before-you-start","p":1033},{"i":1037,"t":"Direct Access","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#direct-access","p":1033},{"i":1039,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#-concepts","p":1033},{"i":1041,"t":"Step By Step","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#step-by-step","p":1033},{"i":1043,"t":"01. Create A Relationship Tuple","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#01-create-a-relationship-tuple","p":1033},{"i":1045,"t":"02. Check That The Relationship Exists","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#02-check-that-the-relationship-exists","p":1033},{"i":1047,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/public-access","h":"#related-sections","p":1033},{"i":1051,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#before-you-start","p":1049},{"i":1053,"t":"Modeling user groups","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#modeling-user-groups","p":1049},{"i":1055,"t":"Managing group access","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#managing-group-access","p":1049},{"i":1057,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#-concepts","p":1049},{"i":1059,"t":"Step by step","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#step-by-step","p":1049},{"i":1060,"t":"01. Revoking group membership","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#01-revoking-group-membership","p":1049},{"i":1062,"t":"02. Validating revoked member no longer has access","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#02-validating-revoked-member-no-longer-has-access","p":1049},{"i":1064,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","h":"#related-sections","p":1049},{"i":1068,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#before-you-start","p":1066},{"i":1070,"t":"Direct access","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#direct-access","p":1066},{"i":1072,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#-concepts","p":1066},{"i":1074,"t":"Step by step","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#step-by-step","p":1066},{"i":1076,"t":"01. Modify authorization model","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#01-modify-authorization-model","p":1066},{"i":1078,"t":"02. Adding relationship tuples where user is another object","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#02-adding-relationship-tuples-where-user-is-another-object","p":1066},{"i":1080,"t":"03. Adding relationship tuples to the other object","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#03-adding-relationship-tuples-to-the-other-object","p":1066},{"i":1082,"t":"04. Validating user access","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#04-validating-user-access","p":1066},{"i":1084,"t":"05. Revoking access","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#05-revoking-access","p":1066},{"i":1086,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","h":"#related-sections","p":1066},{"i":1090,"t":"Before you start","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#before-you-start","p":1088},{"i":1092,"t":"Direct access","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#direct-access","p":1088},{"i":1094,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#-concepts","p":1088},{"i":1096,"t":"Check","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#check","p":1088},{"i":1097,"t":"What is it for?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#what-is-it-for","p":1088},{"i":1099,"t":"When to use?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#when-to-use","p":1088},{"i":1101,"t":"Caveats and when not to use it","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#caveats-and-when-not-to-use-it","p":1088},{"i":1103,"t":"Batch Check","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#batch-check","p":1088},{"i":1104,"t":"What is it for?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#what-is-it-for-1","p":1088},{"i":1106,"t":"When to use?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#when-to-use-1","p":1088},{"i":1108,"t":"Caveats and when not to use it","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#caveats-and-when-not-to-use-it-1","p":1088},{"i":1110,"t":"Read","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#read","p":1088},{"i":1111,"t":"What Is It For?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#what-is-it-for-2","p":1088},{"i":1113,"t":"When to use?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#when-to-use-2","p":1088},{"i":1115,"t":"Caveats and when not to use it","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#caveats-and-when-not-to-use-it-2","p":1088},{"i":1117,"t":"Expand","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#expand","p":1088},{"i":1118,"t":"What is it for?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#what-is-it-for-3","p":1088},{"i":1120,"t":"When to use?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#when-to-use-3","p":1088},{"i":1122,"t":"ListObjects","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#listobjects","p":1088},{"i":1123,"t":"What is it for?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#what-is-it-for-4","p":1088},{"i":1125,"t":"When to use?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#when-to-use-4","p":1088},{"i":1127,"t":"Caveats","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#caveats","p":1088},{"i":1129,"t":"ListUsers","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#listusers","p":1088},{"i":1130,"t":"What is it for?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#what-is-it-for-5","p":1088},{"i":1132,"t":"When to use?","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#when-to-use-5","p":1088},{"i":1134,"t":"Caveats","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#caveats-1","p":1088},{"i":1136,"t":"Summary","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#summary","p":1088},{"i":1138,"t":"Related Sections","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","h":"#related-sections","p":1088},{"i":1142,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#before-you-start","p":1140},{"i":1144,"t":"Modeling user groups","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#modeling-user-groups","p":1140},{"i":1146,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#-concepts","p":1140},{"i":1148,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#step-by-step","p":1140},{"i":1150,"t":"01. Modify our model so users can be blocked from accessing a document","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#01-modify-our-model-so-users-can-be-blocked-from-accessing-a-document","p":1140},{"i":1152,"t":"02. Modify our model so users who are blocked can no longer edit the document","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#02-modify-our-model-so-users-who-are-blocked-can-no-longer-edit-the-document","p":1140},{"i":1154,"t":"03. Verify our solution works","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#03-verify-our-solution-works","p":1140},{"i":1156,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/blocklists","h":"#related-sections","p":1140},{"i":1160,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#before-you-start","p":1158},{"i":1162,"t":"Direct access","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#direct-access","p":1158},{"i":1164,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#-concepts","p":1158},{"i":1166,"t":"What are direct relationships?","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#what-are-direct-relationships","p":1158},{"i":1168,"t":"Enable or disable direct relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#enable-or-disable-direct-relationships","p":1158},{"i":1170,"t":"How it affects your system","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#how-it-affects-your-system","p":1158},{"i":1172,"t":"1. With direct relationships enabled","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#1-with-direct-relationships-enabled","p":1158},{"i":1174,"t":"2. With direct relationships disabled","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#2-with-direct-relationships-disabled","p":1158},{"i":1176,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","h":"#related-sections","p":1158},{"i":1180,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#before-you-start","p":1178},{"i":1182,"t":"Modeling user groups","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#modeling-user-groups","p":1178},{"i":1184,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#-concepts","p":1178},{"i":1186,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#step-by-step","p":1178},{"i":1187,"t":"01. Create parent relations in document","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#01-create-parent-relations-in-document","p":1178},{"i":1189,"t":"02. Add Parent Relationship Tuples","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#02-add-parent-relationship-tuples","p":1178},{"i":1191,"t":"03. Check that parent folders have permissions","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#03-check-that-parent-folders-have-permissions","p":1178},{"i":1193,"t":"Advanced object to object relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#advanced-object-to-object-relationships","p":1178},{"i":1195,"t":"01. Create authorization model with object to object relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#01-create-authorization-model-with-object-to-object-relationships","p":1178},{"i":1197,"t":"02. Adding relationship tuples","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#02-adding-relationship-tuples","p":1178},{"i":1199,"t":"03. Check to see if access is allowed without direct relationship","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#03-check-to-see-if-access-is-allowed-without-direct-relationship","p":1178},{"i":1201,"t":"04. Disassociating plan from feature","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#04-disassociating-plan-from-feature","p":1178},{"i":1203,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","h":"#related-sections","p":1178},{"i":1207,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#before-you-start","p":1205},{"i":1209,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#step-by-step","p":1205},{"i":1211,"t":"01. Create a backwards compatible model","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#01-create-a-backwards-compatible-model","p":1205},{"i":1213,"t":"02. Create a new relationship tuple","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#02-create-a-new-relationship-tuple","p":1205},{"i":1215,"t":"03. Migrate the existing relationship tuples","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#03-migrate-the-existing-relationship-tuples","p":1205},{"i":1217,"t":"04. Remove obsolete relationship from the model","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#04-remove-obsolete-relationship-from-the-model","p":1205},{"i":1219,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","h":"#related-sections","p":1205},{"i":1223,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#before-you-start","p":1221},{"i":1225,"t":"Direct Access","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#direct-access","p":1221},{"i":1227,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#-concepts","p":1221},{"i":1229,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#step-by-step","p":1221},{"i":1231,"t":"01. Understand how roles work within the trip booking system","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#01-understand-how-roles-work-within-the-trip-booking-system","p":1221},{"i":1233,"t":"02. Add permissions for bookings","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#02-add-permissions-for-bookings","p":1221},{"i":1235,"t":"03. Check user roles and their permissions","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#03-check-user-roles-and-their-permissions","p":1221},{"i":1237,"t":"Related sections","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","h":"#related-sections","p":1221},{"i":1241,"t":"Before You Start","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#before-you-start","p":1239},{"i":1243,"t":"OpenFGA Concepts","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#-concepts","p":1239},{"i":1245,"t":"Scenario","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#scenario","p":1239},{"i":1247,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#requirements","p":1239},{"i":1249,"t":"Step By Step","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#step-by-step","p":1239},{"i":1251,"t":"Understand Relationships Without Contextual Data","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#understand-relationships-without-contextual-data","p":1239},{"i":1253,"t":"Take Organization Context Into Consideration","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#take-organization-context-into-consideration","p":1239},{"i":1255,"t":"Use Contextual Tuples For Context Related Checks","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#use-contextual-tuples-for-context-related-checks","p":1239},{"i":1257,"t":"Summary","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#summary","p":1239},{"i":1259,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","h":"#related-sections","p":1239},{"i":1263,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#before-you-start","p":1261},{"i":1265,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#-concepts","p":1261},{"i":1267,"t":"What you will be modeling","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#what-you-will-be-modeling","p":1261},{"i":1269,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#requirements","p":1261},{"i":1271,"t":"Defined scenarios","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#defined-scenarios","p":1261},{"i":1273,"t":"Modeling entitlements for GitHub","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#modeling-entitlements-for-github","p":1261},{"i":1274,"t":"01. Building The Initial Authorization Model And Relationship Tuples","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#01-building-the-initial-authorization-model-and-relationship-tuples","p":1261},{"i":1276,"t":"02. Populating the relationship tuples","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#02-populating-the-relationship-tuples","p":1261},{"i":1278,"t":"03. Updating the authorization model","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#03-updating-the-authorization-model","p":1261},{"i":1280,"t":"Summary","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","h":"#summary","p":1261},{"i":1284,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#before-you-start","p":1282},{"i":1286,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#-concepts","p":1282},{"i":1288,"t":"What You Will be modeling","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#what-you-will-be-modeling","p":1282},{"i":1290,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#requirements","p":1282},{"i":1292,"t":"Defined Scenarios","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#defined-scenarios","p":1282},{"i":1294,"t":"Modeling device authorization","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#modeling-device-authorization","p":1282},{"i":1296,"t":"01. Writing the initial model for a device","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#01-writing-the-initial-model-for-a-device","p":1282},{"i":1298,"t":"02. Inserting some relationship tuples","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#02-inserting-some-relationship-tuples","p":1282},{"i":1300,"t":"03. Updating our authorization model to facilitate future changes","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#03-updating-our-authorization-model-to-facilitate-future-changes","p":1282},{"i":1302,"t":"04. Modeling device groups","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#04-modeling-device-groups","p":1282},{"i":1304,"t":"05. Disallow direct relationships To users","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#05-disallow-direct-relationships-to-users","p":1282},{"i":1306,"t":"Summary","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#summary","p":1282},{"i":1308,"t":"Exercises for you","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","h":"#exercises-for-you","p":1282},{"i":1312,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#before-you-start","p":1310},{"i":1314,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#-concepts","p":1310},{"i":1316,"t":"What you will be modeling","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#what-you-will-be-modeling","p":1310},{"i":1318,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#requirements","p":1310},{"i":1320,"t":"Defined scenarios","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#defined-scenarios","p":1310},{"i":1322,"t":"Modeling Google Drive's permissions","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#modeling-google-drives-permissions","p":1310},{"i":1323,"t":"01. Individual permissions","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#01-individual-permissions","p":1310},{"i":1325,"t":"02. Organization permissions","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#02-organization-permissions","p":1310},{"i":1327,"t":"03. Folder permission propagation","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#03-folder-permission-propagation","p":1310},{"i":1329,"t":"04. Sharing files and folders publicly","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#04-sharing-files-and-folders-publicly","p":1310},{"i":1331,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","h":"#related-sections","p":1310},{"i":1335,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#before-you-start","p":1333},{"i":1337,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#-concepts","p":1333},{"i":1339,"t":"What you will be modeling","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#what-you-will-be-modeling","p":1333},{"i":1341,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#requirements","p":1333},{"i":1343,"t":"Defined scenarios","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#defined-scenarios","p":1333},{"i":1345,"t":"Modeling GitHub's permissions","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#modeling-githubs-permissions","p":1333},{"i":1346,"t":"01. Permissions For Individuals In An Org","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#01-permissions-for-individuals-in-an-org","p":1333},{"i":1348,"t":"02. Permissions for teams in an org","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#02-permissions-for-teams-in-an-org","p":1333},{"i":1350,"t":"03. Permissions for child teams in an org","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#03-permissions-for-child-teams-in-an-org","p":1333},{"i":1352,"t":"04. Base permissions for org members","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#04-base-permissions-for-org-members","p":1333},{"i":1354,"t":"Summary","u":"/pr-preview/pr-921/docs/modeling/advanced/github","h":"#summary","p":1333},{"i":1358,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#before-you-start","p":1356},{"i":1360,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#-concepts","p":1356},{"i":1362,"t":"What you will be modeling","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#what-you-will-be-modeling","p":1356},{"i":1364,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#requirements","p":1356},{"i":1366,"t":"Defined scenarios","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#defined-scenarios","p":1356},{"i":1368,"t":"Modeling workspaces & channels","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#modeling-workspaces--channels","p":1356},{"i":1370,"t":"01. Individual permissions","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#01-individual-permissions","p":1356},{"i":1372,"t":"02. Updating The workspace Authorization Model With Implied Relations","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#02-updating-the-workspace-authorization-model-with-implied-relations","p":1356},{"i":1374,"t":"03. Updating the authorization model to include channels","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#03-updating-the-authorization-model-to-include-channels","p":1356},{"i":1376,"t":"Summary","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#summary","p":1356},{"i":1378,"t":"Exercises for you","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","h":"#exercises-for-you","p":1356},{"i":1382,"t":"Before you start","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#before-you-start","p":1380},{"i":1384,"t":"OpenFGA concepts","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#-concepts","p":1380},{"i":1386,"t":"Scenario","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#scenario","p":1380},{"i":1388,"t":"Requirements","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#requirements","p":1380},{"i":1390,"t":"Step by step","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#step-by-step","p":1380},{"i":1392,"t":"Understand relationships without contextual data","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#understand-relationships-without-contextual-data","p":1380},{"i":1394,"t":"Take time and IP address into consideration","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#take-time-and-ip-address-into-consideration","p":1380},{"i":1396,"t":"Use contextual tuples for context related checks","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#use-contextual-tuples-for-context-related-checks","p":1380},{"i":1398,"t":"Summary","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#summary","p":1380},{"i":1400,"t":"Taking it a step further: Banks as a service authorization","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#taking-it-a-step-further-banks-as-a-service-authorization","p":1380},{"i":1402,"t":"Related Sections","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","h":"#related-sections","p":1380}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/5",[0,3.263,1,5.552]],["t/7",[0,3.921]],["t/9",[2,6.212,3,3.647]],["t/11",[4,5.552,5,5.552]],["t/15",[6,4.6,7,3.477]],["t/17",[8,4.65,9,4.65,10,4.65,11,2.058]],["t/19",[11,2.354,12,5.319,13,4.141]],["t/21",[11,2.354,13,4.141,14,5.319]],["t/23",[11,2.749,15,6.212]],["t/25",[16,5.139,17,4.025]],["t/27",[17,4.025,18,5.139]],["t/29",[17,3.013,19,4.65,20,4.156,21,4.367]],["t/31",[22,4.034,23,5.319,24,3.851]],["t/33",[11,2.749,25,4.092]],["t/35",[3,3.123,26,3.447,27,3.503]],["t/39",[6,4.6,7,3.477]],["t/41",[22,4.034,24,3.851,28,4.4]],["t/43",[11,2.354,29,5.319,30,5.319]],["t/45",[20,3.692,31,4.131,32,4.131,33,3.879,34,4.131]],["t/47",[17,4.025,35,6.212]],["t/49",[11,2.749,36,6.212]],["t/51",[16,5.139,17,4.025]],["t/53",[17,4.025,18,5.139]],["t/55",[37,5.326,38,5.834]],["t/57",[3,2.73,39,3.846,40,2.73,41,4.65]],["t/59",[11,2.749,25,4.092]],["t/61",[3,3.123,26,3.447,27,3.503]],["t/65",[22,3.133,24,2.99,28,3.417,42,4.131,43,4.131]],["t/67",[17,4.025,44,4.837]],["t/69",[11,2.354,45,5.319,46,5.319]],["t/71",[16,5.139,17,4.025]],["t/73",[47,5.834,48,2.708]],["t/75",[7,3.477,25,4.092]],["t/77",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/79",[3,3.123,26,3.447,27,3.503]],["t/83",[22,3.133,24,2.99,28,3.417,53,4.131,54,4.131]],["t/85",[55,5.834,56,6.212]],["t/87",[7,3.477,57,4.837]],["t/89",[7,3.477,25,4.092]],["t/91",[7,3.477,58,5.552]],["t/93",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/95",[3,3.123,26,3.447,27,3.503]],["t/99",[7,3.477,58,5.552]],["t/101",[11,2.749,59,6.786]],["t/103",[11,2.354,60,5.319,61,5.811]],["t/105",[3,3.647,39,5.139]],["t/107",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/109",[3,3.123,26,3.447,27,3.503]],["t/113",[7,3.477,58,5.552]],["t/115",[3,3.647,39,5.139]],["t/117",[11,2.058,13,3.621,62,4.65,63,4.65]],["t/119",[64,6.212,65,5.139]],["t/121",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/123",[3,3.123,26,3.447,27,3.503]],["t/127",[17,4.838]],["t/129",[66,6.786,67,5.139]],["t/131",[68,6.672]],["t/133",[25,4.092,69,5.326]],["t/135",[7,3.477,57,4.837]],["t/137",[70,6.401]],["t/139",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/141",[3,3.123,26,3.447,27,3.503]],["t/145",[71,6.672]],["t/147",[68,6.672]],["t/149",[25,4.092,69,5.326]],["t/151",[7,3.477,57,4.837]],["t/153",[70,6.401]],["t/155",[3,3.123,26,3.447,27,3.503]],["t/159",[72,5.528]],["t/161",[7,3.477,57,4.837]],["t/163",[25,4.918]],["t/165",[11,2.058,13,3.621,62,4.65,63,4.65]],["t/167",[64,6.212,65,5.139]],["t/169",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/171",[3,3.123,26,3.447,27,3.503]],["t/175",[71,6.672]],["t/177",[68,6.672]],["t/179",[25,4.092,69,5.326]],["t/181",[7,3.477,57,4.837]],["t/183",[70,6.401]],["t/185",[3,3.123,26,3.447,27,3.503]],["t/191",[71,6.672]],["t/193",[73,6.786,74,6.786]],["t/195",[25,4.092,69,5.326]],["t/197",[7,3.477,57,4.837]],["t/199",[70,6.401]],["t/201",[3,3.123,26,3.447,27,3.503]],["t/205",[0,3.921]],["t/207",[75,5.834,76,6.212]],["t/211",[71,6.672]],["t/213",[60,6.212,77,6.786]],["t/215",[68,6.672]],["t/217",[25,4.092,69,5.326]],["t/219",[78,6.786,79,6.786]],["t/221",[7,3.477,57,4.837]],["t/223",[11,2.354,80,4.995,81,5.811]],["t/225",[70,6.401]],["t/227",[3,3.123,26,3.447,27,3.503]],["t/231",[0,3.921]],["t/233",[3,3.647,39,5.139]],["t/235",[4,5.552,5,5.552]],["t/239",[0,3.921]],["t/241",[82,4.367,83,4.65,84,5.08,85,5.08]],["t/243",[72,4.6,86,5.834]],["t/245",[75,5.834,76,6.212]],["t/248",[87,4.837,88,3.848]],["t/250",[88,3.294,89,4.56,90,4.56]],["t/252",[91,3.621,92,3.987,93,2.574,94,3.621]],["t/254",[92,3.987,93,2.574,94,3.621,95,4.65]],["t/256",[92,3.987,93,2.574,94,3.621,96,5.08]],["t/258",[92,3.987,93,2.574,94,3.621,97,2.209]],["t/260",[98,7.466]],["t/263",[25,3.503,52,4.034,55,4.995]],["t/265",[37,5.326,99,6.786]],["t/267",[100,5.811,101,5.811,102,5.811]],["t/269",[103,8.156]],["t/271",[104,8.156]],["t/273",[105,8.156]],["t/275",[25,3.503,106,5.811,107,5.811]],["t/278",[47,5.834,48,2.708]],["t/280",[0,3.921]],["t/282",[3,3.647,39,5.139]],["t/284",[4,5.552,5,5.552]],["t/286",[7,2.312,24,2.99,89,3.542,90,3.542,108,4.513]],["t/288",[22,3.133,24,2.99,28,3.417,53,4.131,54,4.131]],["t/290",[55,5.834,56,6.212]],["t/292",[7,3.477,57,4.837]],["t/294",[7,3.477,25,4.092]],["t/296",[7,3.477,58,5.552]],["t/298",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/300",[3,3.123,26,3.447,27,3.503]],["t/302",[7,2.312,24,2.99,89,3.542,90,3.542,109,4.513]],["t/304",[22,3.133,24,2.99,28,3.417,42,4.131,43,4.131]],["t/306",[17,4.025,44,4.837]],["t/308",[11,2.354,45,5.319,46,5.319]],["t/310",[16,5.139,17,4.025]],["t/312",[47,5.834,48,2.708]],["t/314",[7,3.477,25,4.092]],["t/316",[49,3.621,50,3.621,51,3.621,52,3.527]],["t/318",[3,3.123,26,3.447,27,3.503]],["t/320",[7,2.312,24,2.99,89,3.542,90,3.542,110,4.513]],["t/322",[6,4.6,7,3.477]],["t/324",[22,4.034,24,3.851,28,4.4]],["t/326",[11,2.354,29,5.319,30,5.319]],["t/328",[20,3.692,31,4.131,32,4.131,33,3.879,34,4.131]],["t/330",[17,4.025,35,6.212]],["t/332",[11,2.749,36,6.212]],["t/334",[16,5.139,17,4.025]],["t/336",[17,4.025,18,5.139]],["t/338",[37,5.326,38,5.834]],["t/340",[3,2.73,39,3.846,40,2.73,41,4.65]],["t/342",[11,2.749,25,4.092]],["t/344",[3,3.123,26,3.447,27,3.503]],["t/346",[7,2.312,89,3.542,90,3.542,111,4.513,112,4.131]],["t/348",[6,4.6,7,3.477]],["t/350",[8,4.65,9,4.65,10,4.65,11,2.058]],["t/352",[11,2.354,12,5.319,13,4.141]],["t/354",[11,2.354,13,4.141,14,5.319]],["t/356",[11,2.749,15,6.212]],["t/358",[16,5.139,17,4.025]],["t/360",[17,4.025,18,5.139]],["t/362",[17,3.013,19,4.65,20,4.156,21,4.367]],["t/364",[22,4.034,23,5.319,24,3.851]],["t/366",[11,2.749,25,4.092]],["t/368",[3,3.123,26,3.447,27,3.503]],["t/370",[11,2.058,97,2.209,113,3.846,114,2.546]],["t/372",[0,3.263,1,5.552]],["t/374",[0,3.921]],["t/376",[2,6.212,3,3.647]],["t/378",[4,5.552,5,5.552]],["t/380",[6,2.751,11,1.644,22,2.818,112,3.716,115,4.059,116,4.059]],["t/384",[117,7.466]],["t/386",[65,6.176]],["t/388",[118,2.613,119,3.002]],["t/394",[120,5.405]],["t/396",[121,6.786,122,5.552]],["t/398",[48,2.027,72,3.443,88,2.88,123,5.08]],["t/400",[114,3.401,124,5.834]],["t/402",[125,8.156]],["t/404",[126,8.156]],["t/406",[127,8.156]],["t/408",[114,3.401,128,5.834]],["t/410",[124,5.834,129,5.326]],["t/412",[118,2.613,119,3.002]],["t/416",[18,4.4,120,3.851,130,5.811]],["t/418",[97,2.209,131,2.922,132,3.013,133,5.08]],["t/420",[118,1.956,134,4.65,135,4.367,136,2.967]],["t/422",[118,2.83,134,4.65,136,2.967]],["t/424",[122,5.552,137,6.786]],["t/426",[122,5.552,138,6.786]],["t/428",[122,5.552,139,6.786]],["t/430",[98,5.319,140,5.811,141,3.012]],["t/432",[118,2.613,119,3.002]],["t/436",[142,3.296,143,3.296]],["t/438",[144,4.603]],["t/440",[118,2.613,119,3.002]],["t/444",[144,4.603]],["t/448",[145,5.139,146,5.834]],["t/450",[82,5.834,146,5.834]],["t/452",[147,6.672]],["t/454",[148,5.552,149,6.212]],["t/456",[95,6.212,148,5.552]],["t/458",[150,7.466]],["t/462",[48,2.319,88,3.294,151,5.319]],["t/464",[48,2.319,152,5.811,153,5.811]],["t/466",[48,1.801,88,2.558,117,4.131,154,4.513,155,3.692]],["t/468",[0,2.793,1,4.753,156,5.811]],["t/469",[48,2.319,157,5.811,158,5.319]],["t/471",[67,4.4,159,5.811,160,5.811]],["t/473",[118,2.613,119,3.002]],["t/477",[161,8.156]],["t/479",[162,4.513,163,4.513,164,4.513,165,4.513,166,4.513]],["t/481",[167,8.156]],["t/483",[168,8.156]],["t/485",[169,8.156]],["t/487",[118,2.613,119,3.002]],["t/491",[142,3.296,143,3.296]],["t/493",[144,4.603]],["t/495",[170,2.546,171,5.08,172,5.08,173,5.08]],["t/497",[87,3.621,155,4.156,174,2.574,175,2.88]],["t/499",[11,1.644,33,3.49,40,2.182,80,3.49,176,2.269,177,2.582]],["t/501",[118,2.613,119,3.002]],["t/505",[142,3.296,143,3.296]],["t/507",[144,4.603]],["t/509",[11,1.828,120,2.99,170,2.262,177,2.871,178,3.417]],["t/511",[40,2.73,174,2.574,177,3.232,179,3.846]],["t/513",[40,2.425,176,2.523,177,2.871,179,3.417,180,4.131]],["t/515",[118,2.613,119,3.002]],["t/519",[142,3.296,143,3.296]],["t/521",[144,4.603]],["t/523",[11,1.828,120,2.99,170,2.262,177,2.871,178,3.417]],["t/525",[136,2.635,174,2.287,177,2.871,179,3.417,181,3.133]],["t/527",[118,2.613,119,3.002]],["t/531",[182,6.786,183,6.212]],["t/533",[83,6.212,183,6.212]],["t/535",[184,6.786,185,6.212]],["t/537",[186,6.786,187,6.786]],["t/539",[118,2.613,119,3.002]],["t/543",[188,5.813]],["t/545",[93,1.869,94,2.629,170,1.849,189,3.689,190,3.171,191,3.018,192,3.018]],["t/547",[48,1.62,93,2.057,94,2.893,129,3.186,174,2.057,193,2.818]],["t/549",[93,2.574,94,3.621,145,3.846,176,2.84]],["t/550",[93,2.574,94,3.621,145,3.846,190,4.367]],["t/552",[0,1.773,75,3.171,82,3.171,177,2.347,194,3.689,195,3.689,196,2.793]],["t/554",[190,4.995,197,5.811,198,5.811]],["t/556",[93,2.574,129,3.987,199,3.366,200,5.08]],["t/558",[118,2.613,119,3.002]],["t/562",[0,2.793,120,3.851,201,5.319]],["t/564",[0,2.793,202,5.811,203,5.319]],["t/566",[0,2.442,203,4.65,204,5.08,205,5.08]],["t/568",[120,3.851,206,4.995,207,5.811]],["t/570",[208,7.466]],["t/572",[209,7.466]],["t/574",[210,7.466]],["t/576",[87,4.837,120,4.497]],["t/578",[87,3.621,211,4.65,212,4.156,213,4.156]],["t/580",[214,7.466]],["t/582",[215,6.212,216,6.786]],["t/584",[40,3.647,217,6.786]],["t/586",[65,5.139,218,6.786]],["t/588",[146,7.012]],["t/590",[149,7.466]],["t/592",[150,7.466]],["t/594",[219,8.156]],["t/596",[118,2.613,119,3.002]],["t/600",[144,4.603]],["t/602",[0,3.263,208,6.212]],["t/604",[0,3.263,209,6.212]],["t/606",[0,3.263,210,6.212]],["t/608",[87,3.621,211,4.65,212,4.156,213,4.156]],["t/610",[87,4.837,214,6.212]],["t/612",[145,5.139,215,6.212]],["t/614",[118,2.613,119,3.002]],["t/622",[191,4.156,220,4.65,221,5.08,222,5.08]],["t/624",[192,5.552,220,6.212]],["t/628",[0,3.263,87,4.837]],["t/630",[0,2.442,87,3.621,212,4.156,213,4.156]],["t/632",[0,2.442,178,3.846,223,5.08,224,5.08]],["t/636",[114,2.262,129,3.542,225,4.513,226,4.513,227,4.513]],["t/638",[48,1.472,88,2.091,155,3.018,228,3.689,229,3.689,230,3.689,231,3.377]],["t/640",[118,2.613,119,3.002]],["t/644",[142,3.296,143,3.296]],["t/646",[144,4.603]],["t/648",[11,1.828,120,2.99,170,2.262,177,2.871,178,3.417]],["t/650",[174,2.287,175,2.558,177,2.871,179,3.417,181,3.133]],["t/652",[232,6.672]],["t/654",[93,2.574,132,3.013,233,4.65,234,4.367]],["t/656",[118,2.613,119,3.002]],["t/661",[235,8.156]],["t/663",[0,2.793,236,5.811,237,5.811]],["t/665",[238,6.786,239,6.786]],["t/667",[72,4.6,86,5.834]],["t/669",[118,2.613,119,3.002]],["t/673",[142,3.296,143,3.296]],["t/675",[144,4.603]],["t/677",[11,1.828,120,2.99,170,2.262,177,2.871,178,3.417]],["t/679",[7,1.732,97,1.47,114,1.694,174,1.713,177,2.15,179,2.559,240,2.409,241,2.291]],["t/681",[97,1.604,114,1.849,128,3.171,176,2.062,177,2.347,179,2.793,240,2.629]],["t/683",[118,2.613,119,3.002]],["t/687",[142,3.296,143,3.296]],["t/689",[48,2.319,175,3.294,242,4.141]],["t/691",[11,2.749,141,3.518]],["t/693",[144,4.603]],["t/694",[44,3.621,170,2.546,243,3.987,244,4.65]],["t/696",[174,2.574,241,3.443,244,4.65,245,5.08]],["t/698",[40,2.182,93,2.057,136,2.37,176,2.269,246,3.186,247,3.716]],["t/700",[118,2.613,119,3.002]],["t/704",[142,3.296,143,3.296]],["t/706",[93,3.439,131,3.904]],["t/708",[11,2.749,141,3.518]],["t/710",[144,4.603]],["t/711",[97,2.209,131,2.922,170,2.546,243,3.987]],["t/713",[97,2.209,131,2.922,174,2.574,248,4.367]],["t/715",[118,2.613,119,3.002]],["t/719",[142,3.296,143,3.296]],["t/721",[144,4.603]],["t/723",[11,1.828,120,2.99,170,2.262,177,2.871,178,3.417]],["t/725",[67,3.846,132,3.013,136,2.967,174,2.574]],["t/727",[67,3.417,132,2.677,136,2.635,176,2.523,249,4.513]],["t/731",[196,5.139,231,6.212]],["t/733",[40,2.73,196,3.846,250,4.65,251,4.367]],["t/735",[40,1.676,67,2.362,196,2.362,251,2.682,252,2.855,253,2.682,254,3.119,255,3.119,256,3.119]],["t/737",[155,3.321,181,2.818,196,3.074,251,3.49,253,3.49,257,4.059]],["t/739",[196,4.4,258,5.811,259,5.811]],["t/741",[260,5.813]],["t/747",[0,3.263,1,5.552]],["t/749",[261,8.156]],["t/753",[142,3.296,143,3.296]],["t/755",[93,3.439,131,3.904]],["t/757",[48,2.319,93,2.944,234,4.995]],["t/759",[11,2.749,141,3.518]],["t/761",[144,4.603]],["t/762",[97,1.604,114,1.849,135,3.171,170,1.849,241,2.5,248,3.171,262,3.377]],["t/764",[97,1.47,114,1.694,118,1.301,135,2.906,174,1.713,241,2.291,262,3.094,263,3.38]],["t/766",[118,2.613,119,3.002]],["t/772",[142,3.296,143,3.296]],["t/774",[48,2.319,175,3.294,242,4.141]],["t/776",[11,2.749,141,3.518]],["t/778",[144,4.603]],["t/780",[48,1.62,170,2.034,264,3.321,265,3.49,266,3.186,267,3.716]],["t/782",[40,2.73,174,2.574,266,3.987,267,4.65]],["t/784",[118,2.613,119,3.002]],["t/787",[232,6.672]],["t/789",[40,2.73,72,3.443,232,4.156,268,3.987]],["t/791",[72,3.443,232,4.156,268,3.987,269,4.65]],["t/793",[270,8.156]],["t/795",[118,2.613,119,3.002]],["t/798",[271,8.156]],["t/800",[48,2.319,113,4.4,272,4.034]],["t/802",[97,2.209,113,3.846,114,2.546,240,3.621]],["t/804",[113,4.4,273,5.811,274,4.753]],["t/806",[147,6.672]],["t/808",[132,3.447,148,4.753,275,5.811]],["t/810",[185,7.466]],["t/814",[142,3.296,143,3.296]],["t/816",[48,2.708,276,5.834]],["t/818",[48,2.319,91,4.141,277,3.503]],["t/820",[48,2.027,97,2.209,136,4.292]],["t/822",[13,3.621,18,3.846,120,3.366,141,2.633]],["t/824",[144,4.603]],["t/826",[48,1.472,88,2.091,91,2.629,132,2.188,170,1.849,241,2.5,278,2.706]],["t/828",[91,2.893,97,1.766,114,2.034,175,2.301,279,4.059,280,4.059]],["t/830",[0,1.773,91,2.629,97,1.604,114,1.849,176,2.062,277,2.224,281,3.689]],["t/832",[48,1.801,72,3.058,88,2.558,199,2.99,282,3.879]],["t/834",[118,2.613,119,3.002]],["t/838",[142,3.296,143,3.296]],["t/840",[11,2.749,141,3.518]],["t/842",[144,4.603]],["t/844",[97,2.209,114,2.546,170,2.546,193,3.527]],["t/846",[40,2.73,97,2.209,174,2.574,283,4.367]],["t/848",[118,2.613,119,3.002]],["t/854",[118,2.237,132,3.447,241,3.938]],["t/856",[118,2.237,128,4.995,132,3.447]],["t/858",[118,2.237,132,3.447,284,5.811]],["t/862",[48,2.708,285,6.786]],["t/864",[48,2.027,88,2.88,272,3.527,286,5.08]],["t/866",[65,3.846,124,4.367,170,2.546,287,5.08]],["t/868",[132,3.013,136,2.967,174,2.574,181,3.527]],["t/870",[118,1.738,132,2.677,176,2.523,181,3.133,288,4.513]],["t/872",[118,2.237,199,3.851,272,4.034]],["t/874",[48,2.319,289,4.753,290,4.262]],["t/876",[291,6.786,292,6.786]],["t/878",[118,2.613,119,3.002]],["t/882",[141,3.518,213,5.552]],["t/883",[293,7.466]],["t/885",[294,8.156]],["t/887",[21,5.834,132,4.025]],["t/889",[147,6.672]],["t/891",[295,8.156]],["t/893",[296,6.786,297,6.786]],["t/895",[298,8.156]],["t/897",[293,7.466]],["t/899",[299,6.786,300,6.786]],["t/901",[48,2.708,151,6.212]],["t/905",[142,3.296,143,3.296]],["t/907",[48,2.027,136,2.967,301,3.846,302,4.65]],["t/909",[48,2.319,91,4.141,277,3.503]],["t/911",[11,2.749,141,3.518]],["t/913",[144,4.603]],["t/915",[118,1.201,170,1.563,241,2.114,303,3.119,304,2.682,305,3.119,306,2.448,307,3.119,308,2.682]],["t/917",[72,3.443,174,2.574,282,4.367,309,4.65]],["t/919",[118,2.613,119,3.002]],["t/923",[142,3.296,143,3.296]],["t/925",[93,3.439,131,3.904]],["t/927",[11,2.749,141,3.518]],["t/929",[144,4.603]],["t/931",[44,2.064,48,1.156,97,1.259,170,1.451,278,2.124,301,2.193,304,2.489,310,2.896,311,2.896,312,2.273]],["t/933",[44,2.064,118,1.115,132,1.718,148,2.369,174,1.467,266,2.273,278,2.124,312,2.273,313,2.489,314,2.896]],["t/935",[7,1.598,97,1.357,114,1.563,176,1.744,193,2.166,266,2.448,315,2.855,316,2.855,317,2.855]],["t/937",[7,1.598,97,1.357,114,1.563,193,2.166,199,2.067,301,2.362,315,2.855,317,2.855,318,2.855]],["t/939",[40,2.425,266,3.542,289,3.692,316,4.131,318,4.131]],["t/941",[118,2.613,119,3.002]],["t/945",[142,3.296,143,3.296]],["t/947",[93,3.439,131,3.904]],["t/949",[11,2.749,141,3.518]],["t/951",[144,4.603]],["t/953",[6,2.751,48,1.62,88,2.301,141,2.104,170,2.034,319,4.059]],["t/955",[6,3.058,174,2.287,175,2.558,241,3.058,306,3.542]],["t/957",[6,2.751,118,1.563,136,2.37,176,2.269,306,3.186,320,4.059]],["t/959",[40,2.182,93,2.057,136,2.37,199,2.69,246,3.186,247,3.716]],["t/961",[118,2.613,119,3.002]],["t/965",[48,2.319,114,2.912,272,4.034]],["t/967",[240,4.837,290,4.978]],["t/969",[40,3.123,240,4.141,290,4.262]],["t/971",[136,2.967,181,3.527,240,3.621,290,3.726]],["t/973",[175,2.88,181,3.527,240,3.621,290,3.726]],["t/975",[191,5.552,290,4.978]],["t/977",[0,2.17,37,3.542,38,3.879,191,3.692,290,3.31]],["t/979",[118,2.613,119,3.002]],["t/983",[142,3.296,143,3.296]],["t/985",[97,1.963,175,2.558,321,4.513,322,4.513,323,4.513]],["t/987",[147,6.672]],["t/989",[118,2.613,119,3.002]],["t/993",[132,4.838]],["t/995",[132,4.025,313,5.834]],["t/997",[48,2.708,88,3.848]],["t/999",[129,6.401]],["t/1001",[136,4.763]],["t/1003",[175,4.624]],["t/1005",[118,3.14]],["t/1007",[118,2.613,313,5.834]],["t/1009",[118,1.956,132,3.013,175,2.88,324,5.08]],["t/1011",[113,6.176]],["t/1013",[97,2.952,114,3.401]],["t/1015",[97,2.527,113,4.4,114,2.912]],["t/1017",[97,3.547]],["t/1019",[97,2.527,131,3.342,265,4.995]],["t/1021",[40,3.647,268,5.326]],["t/1023",[136,3.393,181,4.034,268,4.56]],["t/1025",[175,3.294,181,4.034,268,4.56]],["t/1027",[114,3.401,325,5.326]],["t/1029",[93,2.574,132,3.013,233,4.65,234,4.367]],["t/1031",[118,2.613,119,3.002]],["t/1035",[142,3.296,143,3.296]],["t/1037",[93,3.439,131,3.904]],["t/1039",[11,2.749,141,3.518]],["t/1041",[144,4.603]],["t/1043",[97,2.209,114,2.546,170,2.546,193,3.527]],["t/1045",[40,2.73,97,2.209,174,2.574,283,4.367]],["t/1047",[118,2.613,119,3.002]],["t/1051",[142,3.296,143,3.296]],["t/1053",[48,2.319,175,3.294,242,4.141]],["t/1055",[93,2.944,242,4.141,326,5.811]],["t/1057",[11,2.749,141,3.518]],["t/1059",[144,4.603]],["t/1060",[170,2.546,242,3.621,327,4.367,328,5.08]],["t/1062",[93,2.057,174,2.057,306,3.186,327,3.49,329,3.716,330,3.716]],["t/1064",[118,2.613,119,3.002]],["t/1068",[142,3.296,143,3.296]],["t/1070",[93,3.439,131,3.904]],["t/1072",[11,2.749,141,3.518]],["t/1074",[144,4.603]],["t/1076",[48,2.027,88,2.88,170,2.546,264,4.156]],["t/1078",[97,1.604,114,1.849,136,2.154,174,1.869,175,2.091,243,2.895,331,3.689]],["t/1080",[97,1.963,114,2.262,136,2.635,176,2.523,243,3.542]],["t/1082",[93,2.574,175,2.88,199,3.366,329,4.65]],["t/1084",[93,2.944,289,4.753,327,4.995]],["t/1086",[118,2.613,119,3.002]],["t/1090",[142,3.296,143,3.296]],["t/1092",[93,3.439,131,3.904]],["t/1094",[11,2.749,141,3.518]],["t/1096",[40,4.384]],["t/1097",[]],["t/1099",[0,3.921]],["t/1101",[0,3.263,332,5.326]],["t/1103",[40,3.647,180,6.212]],["t/1104",[]],["t/1106",[0,3.921]],["t/1108",[0,3.263,332,5.326]],["t/1110",[333,8.156]],["t/1111",[]],["t/1113",[0,3.921]],["t/1115",[0,3.263,332,5.326]],["t/1117",[269,7.466]],["t/1118",[]],["t/1120",[0,3.921]],["t/1122",[334,8.156]],["t/1123",[]],["t/1125",[0,3.921]],["t/1127",[332,6.401]],["t/1129",[335,8.156]],["t/1130",[]],["t/1132",[0,3.921]],["t/1134",[332,6.401]],["t/1136",[260,5.813]],["t/1138",[118,2.613,119,3.002]],["t/1142",[142,3.296,143,3.296]],["t/1144",[48,2.319,175,3.294,242,4.141]],["t/1146",[11,2.749,141,3.518]],["t/1148",[144,4.603]],["t/1150",[44,2.629,48,1.472,93,1.869,170,1.849,175,2.091,264,3.018,336,3.377]],["t/1152",[44,2.409,48,1.349,174,1.713,175,1.916,264,2.765,330,3.094,336,3.094,337,3.38]],["t/1154",[72,3.443,176,2.84,282,4.367,309,4.65]],["t/1156",[118,2.613,119,3.002]],["t/1160",[142,3.296,143,3.296]],["t/1162",[93,3.439,131,3.904]],["t/1164",[11,2.749,141,3.518]],["t/1166",[97,2.952,131,3.904]],["t/1168",[97,2.209,131,2.922,145,3.846,192,4.156]],["t/1170",[338,6.786,339,6.212]],["t/1172",[97,2.209,131,2.922,145,3.846,250,4.65]],["t/1174",[97,2.209,131,2.922,192,4.156,252,4.65]],["t/1176",[118,2.613,119,3.002]],["t/1180",[142,3.296,143,3.296]],["t/1182",[48,2.319,175,3.294,242,4.141]],["t/1184",[11,2.749,141,3.518]],["t/1186",[144,4.603]],["t/1187",[44,3.216,118,1.738,170,2.262,193,3.133,301,3.417]],["t/1189",[97,1.963,114,2.262,174,2.287,241,3.058,301,3.417]],["t/1191",[40,2.425,176,2.523,277,2.721,301,3.417,312,3.542]],["t/1193",[97,2.209,136,4.292,340,5.08]],["t/1195",[48,1.472,88,2.091,97,1.604,136,3.372,170,1.849,193,2.561]],["t/1197",[97,2.209,114,2.546,174,2.574,243,3.987]],["t/1199",[26,2.005,40,1.817,93,1.713,97,1.47,131,1.944,176,1.89,304,2.906,341,2.906]],["t/1201",[65,3.846,199,3.366,342,5.08,343,5.08]],["t/1203",[118,2.613,119,3.002]],["t/1207",[142,3.296,143,3.296]],["t/1209",[144,4.603]],["t/1211",[48,1.801,170,2.262,193,3.133,344,4.513,345,4.513]],["t/1213",[7,2.312,97,1.963,114,2.262,174,2.287,193,3.133]],["t/1215",[97,1.963,114,2.262,158,4.131,176,2.523,283,3.879]],["t/1217",[48,1.801,97,1.963,199,2.99,248,3.879,346,4.513]],["t/1219",[118,2.613,119,3.002]],["t/1223",[142,3.296,143,3.296]],["t/1225",[93,3.439,131,3.904]],["t/1227",[11,2.749,141,3.518]],["t/1229",[144,4.603]],["t/1231",[72,2.291,91,2.409,170,1.694,339,3.094,347,2.906,348,3.38,349,3.38,350,3.094]],["t/1233",[174,2.574,241,3.443,277,3.063,350,4.65]],["t/1235",[40,2.425,91,3.216,175,2.558,176,2.523,277,2.721]],["t/1237",[118,2.613,119,3.002]],["t/1241",[142,3.296,143,3.296]],["t/1243",[11,2.749,141,3.518]],["t/1245",[351,5.983]],["t/1247",[188,5.813]],["t/1249",[144,4.603]],["t/1251",[97,1.963,206,3.879,325,3.542,341,3.879,347,3.879]],["t/1253",[274,4.156,308,4.367,352,4.367,353,4.65]],["t/1255",[0,1.952,40,2.182,114,2.034,118,1.563,274,3.321,325,3.186]],["t/1257",[260,5.813]],["t/1259",[118,2.613,119,3.002]],["t/1263",[142,3.296,143,3.296]],["t/1265",[11,2.749,141,3.518]],["t/1267",[48,3.255]],["t/1269",[188,5.813]],["t/1271",[272,4.712,351,4.978]],["t/1273",[37,4.56,48,2.319,354,5.811]],["t/1274",[48,1.472,88,2.091,97,1.604,114,1.849,170,1.849,253,3.171,276,3.171]],["t/1276",[97,2.209,114,2.546,174,2.574,355,5.08]],["t/1278",[48,2.027,88,2.88,176,2.84,278,3.726]],["t/1280",[260,5.813]],["t/1284",[142,3.296,143,3.296]],["t/1286",[11,2.749,141,3.518]],["t/1288",[48,3.255]],["t/1290",[188,5.813]],["t/1292",[272,4.712,351,4.978]],["t/1294",[48,2.319,88,3.294,356,4.995]],["t/1296",[48,1.801,170,2.262,240,3.216,276,3.879,356,3.879]],["t/1298",[97,2.209,114,2.546,174,2.574,357,5.08]],["t/1300",[48,1.472,67,2.793,86,3.171,88,2.091,176,2.062,278,2.706,358,3.689]],["t/1302",[48,2.027,199,3.366,242,3.621,356,4.367]],["t/1304",[97,1.963,131,2.596,175,2.558,289,3.692,359,4.513]],["t/1306",[260,5.813]],["t/1308",[360,7.466]],["t/1312",[142,3.296,143,3.296]],["t/1314",[11,2.749,141,3.518]],["t/1316",[48,3.255]],["t/1318",[188,5.813]],["t/1320",[272,4.712,351,4.978]],["t/1322",[48,2.027,277,3.063,361,5.08,362,5.08]],["t/1323",[170,2.912,246,4.56,277,3.503]],["t/1325",[174,2.944,277,3.503,308,4.995]],["t/1327",[176,2.84,277,3.063,312,3.987,363,5.08]],["t/1329",[199,2.99,201,4.131,212,3.692,312,3.542,364,4.513]],["t/1331",[118,2.613,119,3.002]],["t/1335",[142,3.296,143,3.296]],["t/1337",[11,2.749,141,3.518]],["t/1339",[48,3.255]],["t/1341",[188,5.813]],["t/1343",[272,4.712,351,4.978]],["t/1345",[48,2.319,277,3.503,365,5.811]],["t/1346",[170,2.546,246,3.987,277,3.063,366,4.156]],["t/1348",[6,3.443,174,2.574,277,3.063,366,4.156]],["t/1350",[6,3.058,176,2.523,277,2.721,302,4.131,366,3.692]],["t/1352",[92,3.542,199,2.99,277,2.721,306,3.542,366,3.692]],["t/1354",[260,5.813]],["t/1358",[142,3.296,143,3.296]],["t/1360",[11,2.749,141,3.518]],["t/1362",[48,3.255]],["t/1364",[188,5.813]],["t/1366",[272,4.712,351,4.978]],["t/1368",[13,3.621,48,2.027,367,4.65,368,4.65]],["t/1370",[170,2.912,246,4.56,277,3.503]],["t/1372",[48,1.472,88,2.091,118,1.42,174,1.869,265,3.171,278,2.706,367,3.377]],["t/1374",[48,1.62,88,2.301,176,2.269,278,2.977,368,3.716,369,4.059]],["t/1376",[260,5.813]],["t/1378",[360,7.466]],["t/1382",[142,3.296,143,3.296]],["t/1384",[11,2.749,141,3.518]],["t/1386",[351,5.983]],["t/1388",[188,5.813]],["t/1390",[144,4.603]],["t/1392",[97,1.963,206,3.879,325,3.542,341,3.879,347,3.879]],["t/1394",[352,3.879,353,4.131,370,4.513,371,4.513,372,4.513]],["t/1396",[0,1.952,40,2.182,114,2.034,118,1.563,274,3.321,325,3.186]],["t/1398",[260,5.813]],["t/1400",[80,3.49,88,2.301,144,2.08,352,3.49,373,4.059,374,4.059]],["t/1402",[118,2.613,119,3.002]]],"invertedIndex":[["",{"_index":13,"t":{"19":{"position":[[8,1]]},"21":{"position":[[10,1]]},"117":{"position":[[8,1]]},"165":{"position":[[8,1]]},"352":{"position":[[8,1]]},"354":{"position":[[10,1]]},"822":{"position":[[9,1]]},"1368":{"position":[[20,1]]}}}],["01",{"_index":170,"t":{"495":{"position":[[0,3]]},"509":{"position":[[0,3]]},"523":{"position":[[0,3]]},"545":{"position":[[0,3]]},"648":{"position":[[0,3]]},"677":{"position":[[0,3]]},"694":{"position":[[0,3]]},"711":{"position":[[0,3]]},"723":{"position":[[0,3]]},"762":{"position":[[0,3]]},"780":{"position":[[0,3]]},"826":{"position":[[0,3]]},"844":{"position":[[0,3]]},"866":{"position":[[0,3]]},"915":{"position":[[0,3]]},"931":{"position":[[0,3]]},"953":{"position":[[0,3]]},"1043":{"position":[[0,3]]},"1060":{"position":[[0,3]]},"1076":{"position":[[0,3]]},"1150":{"position":[[0,3]]},"1187":{"position":[[0,3]]},"1195":{"position":[[0,3]]},"1211":{"position":[[0,3]]},"1231":{"position":[[0,3]]},"1274":{"position":[[0,3]]},"1296":{"position":[[0,3]]},"1323":{"position":[[0,3]]},"1346":{"position":[[0,3]]},"1370":{"position":[[0,3]]}}}],["02",{"_index":174,"t":{"497":{"position":[[0,3]]},"511":{"position":[[0,3]]},"525":{"position":[[0,3]]},"547":{"position":[[0,3]]},"650":{"position":[[0,3]]},"679":{"position":[[0,3]]},"696":{"position":[[0,3]]},"713":{"position":[[0,3]]},"725":{"position":[[0,3]]},"764":{"position":[[0,3]]},"782":{"position":[[0,3]]},"846":{"position":[[0,3]]},"868":{"position":[[0,3]]},"917":{"position":[[0,3]]},"933":{"position":[[0,3]]},"955":{"position":[[0,3]]},"1045":{"position":[[0,3]]},"1062":{"position":[[0,3]]},"1078":{"position":[[0,3]]},"1152":{"position":[[0,3]]},"1189":{"position":[[0,3]]},"1197":{"position":[[0,3]]},"1213":{"position":[[0,3]]},"1233":{"position":[[0,3]]},"1276":{"position":[[0,3]]},"1298":{"position":[[0,3]]},"1325":{"position":[[0,3]]},"1348":{"position":[[0,3]]},"1372":{"position":[[0,3]]}}}],["02.use",{"_index":279,"t":{"828":{"position":[[0,6]]}}}],["03",{"_index":176,"t":{"499":{"position":[[0,3]]},"513":{"position":[[0,3]]},"549":{"position":[[0,3]]},"681":{"position":[[0,3]]},"698":{"position":[[0,3]]},"727":{"position":[[0,3]]},"830":{"position":[[0,3]]},"870":{"position":[[0,3]]},"935":{"position":[[0,3]]},"957":{"position":[[0,3]]},"1080":{"position":[[0,3]]},"1154":{"position":[[0,3]]},"1191":{"position":[[0,3]]},"1199":{"position":[[0,3]]},"1215":{"position":[[0,3]]},"1235":{"position":[[0,3]]},"1278":{"position":[[0,3]]},"1300":{"position":[[0,3]]},"1327":{"position":[[0,3]]},"1350":{"position":[[0,3]]},"1374":{"position":[[0,3]]}}}],["04",{"_index":199,"t":{"556":{"position":[[0,3]]},"832":{"position":[[0,3]]},"872":{"position":[[0,3]]},"937":{"position":[[0,3]]},"959":{"position":[[0,3]]},"1082":{"position":[[0,3]]},"1201":{"position":[[0,3]]},"1217":{"position":[[0,3]]},"1302":{"position":[[0,3]]},"1329":{"position":[[0,3]]},"1352":{"position":[[0,3]]}}}],["05",{"_index":289,"t":{"874":{"position":[[0,3]]},"939":{"position":[[0,3]]},"1084":{"position":[[0,3]]},"1304":{"position":[[0,3]]}}}],["06",{"_index":291,"t":{"876":{"position":[[0,3]]}}}],["1",{"_index":250,"t":{"733":{"position":[[7,2]]},"1172":{"position":[[0,2]]}}}],["2",{"_index":252,"t":{"735":{"position":[[7,2]]},"1174":{"position":[[0,2]]}}}],["2023",{"_index":112,"t":{"346":{"position":[[29,4]]},"380":{"position":[[36,4]]}}}],["2024",{"_index":24,"t":{"31":{"position":[[11,4]]},"41":{"position":[[15,5]]},"65":{"position":[[15,4]]},"83":{"position":[[15,4]]},"286":{"position":[[26,4]]},"288":{"position":[[15,4]]},"302":{"position":[[29,4]]},"304":{"position":[[15,4]]},"320":{"position":[[28,4]]},"324":{"position":[[15,5]]},"364":{"position":[[11,4]]}}}],["3",{"_index":257,"t":{"737":{"position":[[7,2]]}}}],["access",{"_index":93,"t":{"252":{"position":[[19,6]]},"254":{"position":[[24,6]]},"256":{"position":[[21,6]]},"258":{"position":[[27,6]]},"545":{"position":[[39,6]]},"547":{"position":[[15,6]]},"549":{"position":[[11,6]]},"550":{"position":[[10,6]]},"556":{"position":[[10,6]]},"654":{"position":[[18,6]]},"698":{"position":[[36,6]]},"706":{"position":[[7,6]]},"755":{"position":[[7,6]]},"757":{"position":[[16,6]]},"925":{"position":[[7,6]]},"947":{"position":[[7,6]]},"959":{"position":[[33,6]]},"1029":{"position":[[26,7]]},"1037":{"position":[[7,6]]},"1055":{"position":[[15,6]]},"1062":{"position":[[44,6]]},"1070":{"position":[[7,6]]},"1082":{"position":[[20,6]]},"1084":{"position":[[13,6]]},"1092":{"position":[[7,6]]},"1150":{"position":[[50,9]]},"1162":{"position":[[7,6]]},"1199":{"position":[[20,6]]},"1225":{"position":[[7,6]]}}}],["action",{"_index":38,"t":{"55":{"position":[[7,7]]},"338":{"position":[[7,7]]},"977":{"position":[[27,7]]}}}],["ad",{"_index":243,"t":{"694":{"position":[[4,6]]},"711":{"position":[[4,6]]},"1078":{"position":[[4,6]]},"1080":{"position":[[4,6]]},"1197":{"position":[[4,6]]}}}],["adapt",{"_index":84,"t":{"241":{"position":[[16,7]]}}}],["add",{"_index":241,"t":{"679":{"position":[[25,3]]},"696":{"position":[[4,3]]},"762":{"position":[[4,3]]},"764":{"position":[[4,3]]},"826":{"position":[[38,3]]},"854":{"position":[[3,3]]},"915":{"position":[[4,3]]},"955":{"position":[[4,3]]},"1189":{"position":[[4,3]]},"1233":{"position":[[4,3]]}}}],["address",{"_index":372,"t":{"1394":{"position":[[17,7]]}}}],["adopt",{"_index":57,"t":{"87":{"position":[[4,8]]},"135":{"position":[[4,8]]},"151":{"position":[[4,8]]},"161":{"position":[[4,8]]},"181":{"position":[[4,8]]},"197":{"position":[[4,8]]},"221":{"position":[[4,8]]},"292":{"position":[[4,8]]}}}],["advanc",{"_index":340,"t":{"1193":{"position":[[0,8]]}}}],["advisori",{"_index":77,"t":{"213":{"position":[[9,8]]}}}],["affect",{"_index":338,"t":{"1170":{"position":[[7,7]]}}}],["allow",{"_index":304,"t":{"915":{"position":[[36,5]]},"931":{"position":[[37,5]]},"1199":{"position":[[30,7]]}}}],["alway",{"_index":228,"t":{"638":{"position":[[0,6]]}}}],["announc",{"_index":70,"t":{"137":{"position":[[0,13]]},"153":{"position":[[0,13]]},"183":{"position":[[0,13]]},"199":{"position":[[0,13]]},"225":{"position":[[0,13]]}}}],["anoth",{"_index":331,"t":{"1078":{"position":[[45,7]]}}}],["api",{"_index":177,"t":{"499":{"position":[[32,3]]},"509":{"position":[[26,3]]},"511":{"position":[[18,3]]},"513":{"position":[[24,3]]},"523":{"position":[[26,3]]},"525":{"position":[[25,3]]},"552":{"position":[[38,3]]},"648":{"position":[[26,3]]},"650":{"position":[[23,3]]},"677":{"position":[[26,3]]},"679":{"position":[[18,3]]},"681":{"position":[[18,3]]},"723":{"position":[[26,3]]}}}],["apk",{"_index":165,"t":{"479":{"position":[[20,4]]}}}],["assess",{"_index":61,"t":{"103":{"position":[[17,10]]}}}],["assign",{"_index":320,"t":{"957":{"position":[[4,6]]}}}],["associ",{"_index":281,"t":{"830":{"position":[[31,9]]}}}],["athor",{"_index":310,"t":{"931":{"position":[[15,12]]}}}],["attribut",{"_index":95,"t":{"254":{"position":[[8,9]]},"456":{"position":[[10,10]]}}}],["authent",{"_index":87,"t":{"248":{"position":[[0,14]]},"497":{"position":[[4,12]]},"576":{"position":[[12,14]]},"578":{"position":[[15,14]]},"608":{"position":[[15,14]]},"610":{"position":[[5,14]]},"628":{"position":[[9,14]]},"630":{"position":[[17,14]]}}}],["author",{"_index":88,"t":{"248":{"position":[[19,13]]},"250":{"position":[[21,14]]},"398":{"position":[[10,13]]},"462":{"position":[[16,13]]},"466":{"position":[[26,13]]},"638":{"position":[[15,13]]},"826":{"position":[[15,13]]},"832":{"position":[[20,13]]},"864":{"position":[[23,13]]},"953":{"position":[[43,13]]},"997":{"position":[[11,13]]},"1076":{"position":[[11,13]]},"1195":{"position":[[11,13]]},"1274":{"position":[[25,13]]},"1278":{"position":[[17,13]]},"1294":{"position":[[16,13]]},"1300":{"position":[[17,13]]},"1372":{"position":[[27,13]]},"1374":{"position":[[17,13]]},"1400":{"position":[[45,13]]}}}],["background",{"_index":235,"t":{"661":{"position":[[0,10]]}}}],["backward",{"_index":344,"t":{"1211":{"position":[[13,9]]}}}],["bank",{"_index":374,"t":{"1400":{"position":[[26,5]]}}}],["base",{"_index":92,"t":{"252":{"position":[[13,5]]},"254":{"position":[[18,5]]},"256":{"position":[[15,5]]},"258":{"position":[[21,5]]},"1352":{"position":[[4,4]]}}}],["basic",{"_index":121,"t":{"396":{"position":[[0,5]]}}}],["batch",{"_index":180,"t":{"513":{"position":[[12,5]]},"1103":{"position":[[0,5]]}}}],["befor",{"_index":142,"t":{"436":{"position":[[0,6]]},"491":{"position":[[0,6]]},"505":{"position":[[0,6]]},"519":{"position":[[0,6]]},"644":{"position":[[0,6]]},"673":{"position":[[0,6]]},"687":{"position":[[0,6]]},"704":{"position":[[0,6]]},"719":{"position":[[0,6]]},"753":{"position":[[0,6]]},"772":{"position":[[0,6]]},"814":{"position":[[0,6]]},"838":{"position":[[0,6]]},"905":{"position":[[0,6]]},"923":{"position":[[0,6]]},"945":{"position":[[0,6]]},"983":{"position":[[0,6]]},"1035":{"position":[[0,6]]},"1051":{"position":[[0,6]]},"1068":{"position":[[0,6]]},"1090":{"position":[[0,6]]},"1142":{"position":[[0,6]]},"1160":{"position":[[0,6]]},"1180":{"position":[[0,6]]},"1207":{"position":[[0,6]]},"1223":{"position":[[0,6]]},"1241":{"position":[[0,6]]},"1263":{"position":[[0,6]]},"1284":{"position":[[0,6]]},"1312":{"position":[[0,6]]},"1335":{"position":[[0,6]]},"1358":{"position":[[0,6]]},"1382":{"position":[[0,6]]}}}],["behavior",{"_index":8,"t":{"17":{"position":[[0,8]]},"350":{"position":[[0,8]]}}}],["benefit",{"_index":117,"t":{"384":{"position":[[0,8]]},"466":{"position":[[0,8]]}}}],["best",{"_index":259,"t":{"739":{"position":[[13,4]]}}}],["between",{"_index":311,"t":{"931":{"position":[[65,7]]}}}],["block",{"_index":336,"t":{"1150":{"position":[[37,7]]},"1152":{"position":[[38,7]]}}}],["bob",{"_index":316,"t":{"935":{"position":[[53,3]]},"939":{"position":[[13,3]]}}}],["book",{"_index":350,"t":{"1231":{"position":[[46,7]]},"1233":{"position":[[24,8]]}}}],["bound",{"_index":233,"t":{"654":{"position":[[5,5]]},"1029":{"position":[[13,5]]}}}],["break",{"_index":66,"t":{"129":{"position":[[0,8]]}}}],["brew",{"_index":161,"t":{"477":{"position":[[0,4]]}}}],["build",{"_index":253,"t":{"735":{"position":[[10,5]]},"737":{"position":[[10,5]]},"1274":{"position":[[4,8]]}}}],["busi",{"_index":54,"t":{"83":{"position":[[30,5]]},"288":{"position":[[30,5]]}}}],["cach",{"_index":238,"t":{"665":{"position":[[0,5]]}}}],["call",{"_index":179,"t":{"511":{"position":[[4,7]]},"513":{"position":[[4,7]]},"525":{"position":[[4,7]]},"650":{"position":[[4,7]]},"679":{"position":[[4,7]]},"681":{"position":[[4,7]]}}}],["can_delet",{"_index":303,"t":{"915":{"position":[[8,10]]}}}],["canon",{"_index":14,"t":{"21":{"position":[[0,9]]},"354":{"position":[[0,9]]}}}],["cascad",{"_index":314,"t":{"933":{"position":[[74,9]]}}}],["case",{"_index":1,"t":{"5":{"position":[[4,5]]},"372":{"position":[[4,5]]},"468":{"position":[[14,5]]},"747":{"position":[[4,5]]}}}],["caveat",{"_index":332,"t":{"1101":{"position":[[0,7]]},"1108":{"position":[[0,7]]},"1115":{"position":[[0,7]]},"1127":{"position":[[0,7]]},"1134":{"position":[[0,7]]}}}],["chang",{"_index":67,"t":{"129":{"position":[[9,7]]},"471":{"position":[[22,7]]},"725":{"position":[[8,7]]},"727":{"position":[[8,7]]},"735":{"position":[[35,7]]},"1300":{"position":[[58,7]]}}}],["channel",{"_index":368,"t":{"1368":{"position":[[22,8]]},"1374":{"position":[[48,8]]}}}],["check",{"_index":40,"t":{"57":{"position":[[13,5]]},"340":{"position":[[13,5]]},"499":{"position":[[26,5]]},"511":{"position":[[12,5]]},"513":{"position":[[18,5]]},"584":{"position":[[7,5]]},"698":{"position":[[4,8]]},"733":{"position":[[23,5]]},"735":{"position":[[66,5]]},"782":{"position":[[4,5]]},"789":{"position":[[7,5]]},"846":{"position":[[4,5]]},"939":{"position":[[4,5]]},"959":{"position":[[4,5]]},"969":{"position":[[6,5]]},"1021":{"position":[[10,5]]},"1045":{"position":[[4,5]]},"1096":{"position":[[0,5]]},"1103":{"position":[[6,5]]},"1191":{"position":[[4,5]]},"1199":{"position":[[4,5]]},"1235":{"position":[[4,5]]},"1255":{"position":[[42,6]]},"1396":{"position":[[42,6]]}}}],["child",{"_index":302,"t":{"907":{"position":[[16,5]]},"1350":{"position":[[20,5]]}}}],["choos",{"_index":258,"t":{"739":{"position":[[0,8]]}}}],["claim",{"_index":195,"t":{"552":{"position":[[19,5]]}}}],["cli",{"_index":35,"t":{"47":{"position":[[0,3]]},"330":{"position":[[0,3]]}}}],["client",{"_index":178,"t":{"509":{"position":[[30,6]]},"523":{"position":[[30,6]]},"632":{"position":[[6,6]]},"648":{"position":[[30,6]]},"677":{"position":[[30,6]]},"723":{"position":[[30,6]]}}}],["closer",{"_index":43,"t":{"65":{"position":[[31,7]]},"304":{"position":[[31,7]]}}}],["cloudn",{"_index":62,"t":{"117":{"position":[[10,11]]},"165":{"position":[[10,11]]}}}],["cluster",{"_index":182,"t":{"531":{"position":[[0,7]]}}}],["cncf",{"_index":55,"t":{"85":{"position":[[0,4]]},"263":{"position":[[6,5]]},"290":{"position":[[0,4]]}}}],["cncf'",{"_index":51,"t":{"77":{"position":[[30,6]]},"93":{"position":[[30,6]]},"107":{"position":[[30,6]]},"121":{"position":[[30,6]]},"139":{"position":[[30,6]]},"169":{"position":[[30,6]]},"298":{"position":[[30,6]]},"316":{"position":[[30,6]]}}}],["code",{"_index":20,"t":{"29":{"position":[[3,4]]},"45":{"position":[[14,4]]},"328":{"position":[[14,4]]},"362":{"position":[[3,4]]}}}],["come",{"_index":73,"t":{"193":{"position":[[0,6]]}}}],["command",{"_index":204,"t":{"566":{"position":[[6,7]]}}}],["commun",{"_index":25,"t":{"33":{"position":[[8,9]]},"59":{"position":[[8,9]]},"75":{"position":[[0,9]]},"89":{"position":[[0,9]]},"133":{"position":[[0,9]]},"149":{"position":[[0,9]]},"163":{"position":[[0,9]]},"179":{"position":[[0,9]]},"195":{"position":[[0,9]]},"217":{"position":[[0,9]]},"263":{"position":[[12,10]]},"275":{"position":[[8,9]]},"294":{"position":[[0,9]]},"314":{"position":[[0,9]]},"342":{"position":[[8,9]]},"366":{"position":[[8,9]]}}}],["compani",{"_index":244,"t":{"694":{"position":[[11,7]]},"696":{"position":[[27,7]]}}}],["compat",{"_index":345,"t":{"1211":{"position":[[23,10]]}}}],["complex",{"_index":157,"t":{"469":{"position":[[0,7]]}}}],["concept",{"_index":141,"t":{"430":{"position":[[20,8]]},"691":{"position":[[8,8]]},"708":{"position":[[8,8]]},"759":{"position":[[8,8]]},"776":{"position":[[8,8]]},"822":{"position":[[0,8]]},"840":{"position":[[8,8]]},"882":{"position":[[4,8]]},"911":{"position":[[8,8]]},"927":{"position":[[8,8]]},"949":{"position":[[8,8]]},"953":{"position":[[18,7]]},"1039":{"position":[[8,8]]},"1057":{"position":[[8,8]]},"1072":{"position":[[8,8]]},"1094":{"position":[[8,8]]},"1146":{"position":[[8,8]]},"1164":{"position":[[8,8]]},"1184":{"position":[[8,8]]},"1227":{"position":[[8,8]]},"1243":{"position":[[8,8]]},"1265":{"position":[[8,8]]},"1286":{"position":[[8,8]]},"1314":{"position":[[8,8]]},"1337":{"position":[[8,8]]},"1360":{"position":[[8,8]]},"1384":{"position":[[8,8]]}}}],["concurr",{"_index":184,"t":{"535":{"position":[[0,11]]}}}],["condit",{"_index":113,"t":{"370":{"position":[[0,11]]},"800":{"position":[[9,10]]},"802":{"position":[[8,11]]},"804":{"position":[[13,9]]},"1011":{"position":[[10,10]]},"1015":{"position":[[10,11]]}}}],["configur",{"_index":120,"t":{"394":{"position":[[0,13]]},"416":{"position":[[14,13]]},"509":{"position":[[4,9]]},"523":{"position":[[4,9]]},"562":{"position":[[8,13]]},"568":{"position":[[0,11]]},"576":{"position":[[0,11]]},"648":{"position":[[4,9]]},"677":{"position":[[4,9]]},"723":{"position":[[4,9]]},"822":{"position":[[11,13]]}}}],["consider",{"_index":353,"t":{"1253":{"position":[[31,13]]},"1394":{"position":[[30,13]]}}}],["consist",{"_index":237,"t":{"663":{"position":[[19,11]]}}}],["context",{"_index":274,"t":{"804":{"position":[[23,7]]},"1253":{"position":[[18,7]]},"1255":{"position":[[26,7]]},"1396":{"position":[[26,7]]}}}],["contextu",{"_index":325,"t":{"1027":{"position":[[9,10]]},"1251":{"position":[[33,10]]},"1255":{"position":[[4,10]]},"1392":{"position":[[33,10]]},"1396":{"position":[[4,10]]}}}],["control",{"_index":94,"t":{"252":{"position":[[26,8]]},"254":{"position":[[31,8]]},"256":{"position":[[28,8]]},"258":{"position":[[34,8]]},"545":{"position":[[46,7]]},"547":{"position":[[22,7]]},"549":{"position":[[18,7]]},"550":{"position":[[17,7]]}}}],["core",{"_index":295,"t":{"891":{"position":[[0,4]]}}}],["creat",{"_index":193,"t":{"547":{"position":[[4,6]]},"844":{"position":[[4,6]]},"935":{"position":[[4,6]]},"937":{"position":[[4,6]]},"1043":{"position":[[4,6]]},"1187":{"position":[[4,6]]},"1195":{"position":[[4,6]]},"1211":{"position":[[4,6]]},"1213":{"position":[[4,6]]}}}],["credenti",{"_index":223,"t":{"632":{"position":[[13,11]]}}}],["csv",{"_index":127,"t":{"406":{"position":[[0,3]]}}}],["custom",{"_index":82,"t":{"241":{"position":[[0,6]]},"450":{"position":[[0,11]]},"552":{"position":[[4,9]]}}}],["data",{"_index":206,"t":{"568":{"position":[[12,4]]},"1251":{"position":[[44,4]]},"1392":{"position":[[44,4]]}}}],["databas",{"_index":83,"t":{"241":{"position":[[7,8]]},"533":{"position":[[0,8]]}}}],["deb",{"_index":163,"t":{"479":{"position":[[6,5]]}}}],["decemb",{"_index":111,"t":{"346":{"position":[[20,8]]}}}],["defin",{"_index":272,"t":{"800":{"position":[[0,8]]},"864":{"position":[[14,8]]},"872":{"position":[[4,6]]},"965":{"position":[[0,6]]},"1271":{"position":[[0,7]]},"1292":{"position":[[0,7]]},"1320":{"position":[[0,7]]},"1343":{"position":[[0,7]]},"1366":{"position":[[0,7]]}}}],["definit",{"_index":313,"t":{"933":{"position":[[52,10]]},"995":{"position":[[15,11]]},"1007":{"position":[[19,11]]}}}],["delet",{"_index":128,"t":{"408":{"position":[[0,6]]},"681":{"position":[[25,6]]},"856":{"position":[[3,6]]}}}],["develop",{"_index":10,"t":{"17":{"position":[[16,11]]},"350":{"position":[[16,11]]}}}],["devic",{"_index":356,"t":{"1294":{"position":[[9,6]]},"1296":{"position":[[36,6]]},"1302":{"position":[[13,6]]}}}],["differ",{"_index":221,"t":{"622":{"position":[[28,9]]}}}],["direct",{"_index":131,"t":{"418":{"position":[[0,6]]},"706":{"position":[[0,6]]},"711":{"position":[[11,6]]},"713":{"position":[[13,6]]},"755":{"position":[[0,6]]},"925":{"position":[[0,6]]},"947":{"position":[[0,6]]},"1019":{"position":[[9,6]]},"1037":{"position":[[0,6]]},"1070":{"position":[[0,6]]},"1092":{"position":[[0,6]]},"1162":{"position":[[0,6]]},"1166":{"position":[[9,6]]},"1168":{"position":[[18,6]]},"1172":{"position":[[8,6]]},"1174":{"position":[[8,6]]},"1199":{"position":[[46,6]]},"1225":{"position":[[0,6]]},"1304":{"position":[[13,6]]}}}],["directli",{"_index":324,"t":{"1009":{"position":[[10,8]]}}}],["directori",{"_index":321,"t":{"985":{"position":[[5,12]]}}}],["disabl",{"_index":192,"t":{"545":{"position":[[54,9]]},"624":{"position":[[0,9]]},"1168":{"position":[[10,7]]},"1174":{"position":[[29,8]]}}}],["disallow",{"_index":359,"t":{"1304":{"position":[[4,8]]}}}],["disassoci",{"_index":342,"t":{"1201":{"position":[[4,14]]}}}],["discord",{"_index":50,"t":{"77":{"position":[[19,7]]},"93":{"position":[[19,7]]},"107":{"position":[[19,7]]},"121":{"position":[[19,7]]},"139":{"position":[[19,7]]},"169":{"position":[[19,7]]},"298":{"position":[[19,7]]},"316":{"position":[[19,7]]}}}],["discuss",{"_index":99,"t":{"265":{"position":[[7,11]]}}}],["docker",{"_index":167,"t":{"481":{"position":[[0,6]]}}}],["document",{"_index":44,"t":{"67":{"position":[[0,13]]},"306":{"position":[[0,13]]},"694":{"position":[[26,8]]},"931":{"position":[[84,8]]},"933":{"position":[[38,8]]},"1150":{"position":[[62,8]]},"1152":{"position":[[69,8]]},"1187":{"position":[[31,8]]}}}],["document:meeting_notes.doc",{"_index":318,"t":{"937":{"position":[[81,26]]},"939":{"position":[[33,26]]}}}],["drive'",{"_index":362,"t":{"1322":{"position":[[16,7]]}}}],["driven",{"_index":9,"t":{"17":{"position":[[9,6]]},"350":{"position":[[9,6]]}}}],["ecosystem",{"_index":46,"t":{"69":{"position":[[20,9]]},"308":{"position":[[20,9]]}}}],["edit",{"_index":337,"t":{"1152":{"position":[[60,4]]}}}],["editor",{"_index":266,"t":{"780":{"position":[[30,6]]},"782":{"position":[[15,7]]},"933":{"position":[[15,6]]},"935":{"position":[[63,6]]},"939":{"position":[[23,6]]}}}],["employe",{"_index":245,"t":{"696":{"position":[[11,8]]}}}],["enabl",{"_index":145,"t":{"448":{"position":[[0,8]]},"549":{"position":[[4,6]]},"550":{"position":[[3,6]]},"612":{"position":[[0,8]]},"1168":{"position":[[0,6]]},"1172":{"position":[[29,7]]}}}],["endpoint",{"_index":256,"t":{"735":{"position":[[43,9]]}}}],["enhanc",{"_index":34,"t":{"45":{"position":[[31,12]]},"328":{"position":[[31,12]]}}}],["enlightn",{"_index":29,"t":{"43":{"position":[[8,13]]},"326":{"position":[[8,13]]}}}],["ensur",{"_index":189,"t":{"545":{"position":[[4,6]]}}}],["entitl",{"_index":354,"t":{"1273":{"position":[[9,12]]}}}],["environ",{"_index":202,"t":{"564":{"position":[[6,11]]}}}],["equival",{"_index":140,"t":{"430":{"position":[[0,10]]}}}],["eu",{"_index":23,"t":{"31":{"position":[[8,2]]},"364":{"position":[[8,2]]}}}],["europ",{"_index":28,"t":{"41":{"position":[[8,6]]},"65":{"position":[[8,6]]},"83":{"position":[[8,6]]},"288":{"position":[[8,6]]},"304":{"position":[[8,6]]},"324":{"position":[[8,6]]}}}],["event",{"_index":79,"t":{"219":{"position":[[9,6]]}}}],["exampl",{"_index":147,"t":{"452":{"position":[[0,8]]},"806":{"position":[[0,8]]},"889":{"position":[[0,7]]},"987":{"position":[[0,7]]}}}],["exclus",{"_index":139,"t":{"428":{"position":[[4,9]]}}}],["exercis",{"_index":360,"t":{"1308":{"position":[[0,9]]},"1378":{"position":[[0,9]]}}}],["exist",{"_index":283,"t":{"846":{"position":[[32,6]]},"1045":{"position":[[32,6]]},"1215":{"position":[[16,8]]}}}],["expand",{"_index":269,"t":{"791":{"position":[[7,6]]},"1117":{"position":[[0,6]]}}}],["experiment",{"_index":218,"t":{"586":{"position":[[0,12]]}}}],["expir",{"_index":239,"t":{"665":{"position":[[6,10]]}}}],["extens",{"_index":21,"t":{"29":{"position":[[8,9]]},"362":{"position":[[8,9]]},"887":{"position":[[5,10]]}}}],["facilit",{"_index":358,"t":{"1300":{"position":[[40,10]]}}}],["featur",{"_index":65,"t":{"119":{"position":[[7,8]]},"167":{"position":[[7,8]]},"386":{"position":[[0,8]]},"586":{"position":[[13,8]]},"866":{"position":[[28,7]]},"1201":{"position":[[29,7]]}}}],["februari",{"_index":109,"t":{"302":{"position":[[20,8]]}}}],["feedback",{"_index":76,"t":{"207":{"position":[[13,9]]},"245":{"position":[[13,9]]}}}],["fga.mod",{"_index":293,"t":{"883":{"position":[[0,7]]},"897":{"position":[[0,7]]}}}],["file",{"_index":201,"t":{"562":{"position":[[22,4]]},"1329":{"position":[[12,5]]}}}],["fine",{"_index":89,"t":{"250":{"position":[[8,4]]},"286":{"position":[[0,4]]},"302":{"position":[[0,4]]},"320":{"position":[[0,4]]},"346":{"position":[[0,4]]}}}],["flow",{"_index":224,"t":{"632":{"position":[[25,4]]}}}],["folder",{"_index":312,"t":{"931":{"position":[[73,6]]},"933":{"position":[[89,6]]},"1191":{"position":[[22,7]]},"1327":{"position":[[4,6]]},"1329":{"position":[[22,7]]}}}],["folder:not",{"_index":317,"t":{"935":{"position":[[73,12]]},"937":{"position":[[53,12]]}}}],["formerli",{"_index":101,"t":{"267":{"position":[[2,9]]}}}],["framework",{"_index":173,"t":{"495":{"position":[[22,9]]}}}],["further",{"_index":373,"t":{"1400":{"position":[[17,8]]}}}],["futur",{"_index":86,"t":{"243":{"position":[[0,6]]},"667":{"position":[[0,6]]},"1300":{"position":[[51,6]]}}}],["get",{"_index":42,"t":{"65":{"position":[[23,7]]},"304":{"position":[[23,7]]}}}],["github",{"_index":37,"t":{"55":{"position":[[0,6]]},"265":{"position":[[0,6]]},"338":{"position":[[0,6]]},"977":{"position":[[20,6]]},"1273":{"position":[[26,6]]}}}],["github'",{"_index":365,"t":{"1345":{"position":[[9,8]]}}}],["go",{"_index":168,"t":{"483":{"position":[[0,2]]}}}],["godaddi",{"_index":12,"t":{"19":{"position":[[0,7]]},"352":{"position":[[0,7]]}}}],["googl",{"_index":361,"t":{"1322":{"position":[[9,6]]}}}],["grain",{"_index":90,"t":{"250":{"position":[[13,7]]},"286":{"position":[[5,7]]},"302":{"position":[[5,7]]},"320":{"position":[[5,7]]},"346":{"position":[[5,7]]}}}],["grant",{"_index":200,"t":{"556":{"position":[[4,5]]}}}],["group",{"_index":242,"t":{"689":{"position":[[14,6]]},"774":{"position":[[14,6]]},"1053":{"position":[[14,6]]},"1055":{"position":[[9,5]]},"1060":{"position":[[13,5]]},"1144":{"position":[[14,6]]},"1182":{"position":[[14,6]]},"1302":{"position":[[20,6]]}}}],["hackathon",{"_index":59,"t":{"101":{"position":[[8,9]]}}}],["health",{"_index":217,"t":{"584":{"position":[[0,6]]}}}],["higher",{"_index":236,"t":{"663":{"position":[[12,6]]}}}],["highlight",{"_index":69,"t":{"133":{"position":[[10,10]]},"149":{"position":[[10,10]]},"179":{"position":[[10,10]]},"195":{"position":[[10,10]]},"217":{"position":[[10,10]]}}}],["id",{"_index":155,"t":{"466":{"position":[[46,2]]},"497":{"position":[[30,2]]},"638":{"position":[[35,2]]},"737":{"position":[[26,4]]}}}],["ident",{"_index":322,"t":{"985":{"position":[[18,8]]}}}],["identifi",{"_index":226,"t":{"636":{"position":[[22,12]]}}}],["ii",{"_index":194,"t":{"552":{"position":[[0,3]]}}}],["iii",{"_index":197,"t":{"554":{"position":[[0,4]]}}}],["implement",{"_index":85,"t":{"241":{"position":[[24,15]]}}}],["impli",{"_index":265,"t":{"780":{"position":[[24,5]]},"1019":{"position":[[20,7]]},"1372":{"position":[[52,7]]}}}],["import",{"_index":124,"t":{"400":{"position":[[0,6]]},"410":{"position":[[0,6]]},"866":{"position":[[18,9]]}}}],["improv",{"_index":17,"t":{"25":{"position":[[4,12]]},"27":{"position":[[9,12]]},"29":{"position":[[18,12]]},"47":{"position":[[4,12]]},"51":{"position":[[4,12]]},"53":{"position":[[9,12]]},"67":{"position":[[14,12]]},"71":{"position":[[4,12]]},"127":{"position":[[0,12]]},"306":{"position":[[14,12]]},"310":{"position":[[4,12]]},"330":{"position":[[4,12]]},"334":{"position":[[4,12]]},"336":{"position":[[9,12]]},"358":{"position":[[4,12]]},"360":{"position":[[9,12]]},"362":{"position":[[18,12]]}}}],["includ",{"_index":369,"t":{"1374":{"position":[[40,7]]}}}],["incub",{"_index":56,"t":{"85":{"position":[[5,10]]},"290":{"position":[[5,10]]}}}],["index",{"_index":255,"t":{"735":{"position":[[24,5]]}}}],["indic",{"_index":315,"t":{"935":{"position":[[39,8]]},"937":{"position":[[39,8]]}}}],["individu",{"_index":246,"t":{"698":{"position":[[16,10]]},"959":{"position":[[13,10]]},"1323":{"position":[[4,10]]},"1346":{"position":[[20,11]]},"1370":{"position":[[4,10]]}}}],["inform",{"_index":227,"t":{"636":{"position":[[35,11]]}}}],["initi",{"_index":276,"t":{"816":{"position":[[0,7]]},"1274":{"position":[[17,7]]},"1296":{"position":[[16,7]]}}}],["insert",{"_index":357,"t":{"1298":{"position":[[4,9]]}}}],["instal",{"_index":171,"t":{"495":{"position":[[4,7]]}}}],["integr",{"_index":33,"t":{"45":{"position":[[19,11]]},"328":{"position":[[19,11]]},"499":{"position":[[4,9]]}}}],["intern",{"_index":270,"t":{"793":{"position":[[0,9]]}}}],["intersect",{"_index":138,"t":{"426":{"position":[[4,12]]}}}],["introduc",{"_index":319,"t":{"953":{"position":[[4,9]]}}}],["introduct",{"_index":285,"t":{"862":{"position":[[0,12]]}}}],["ip",{"_index":371,"t":{"1394":{"position":[[14,2]]}}}],["issu",{"_index":296,"t":{"893":{"position":[[0,5]]}}}],["iter",{"_index":292,"t":{"876":{"position":[[4,7]]}}}],["januari",{"_index":110,"t":{"320":{"position":[[20,7]]}}}],["java",{"_index":45,"t":{"69":{"position":[[15,4]]},"308":{"position":[[15,4]]}}}],["join",{"_index":115,"t":{"380":{"position":[[0,4]]}}}],["json",{"_index":126,"t":{"404":{"position":[[0,4]]}}}],["key",{"_index":213,"t":{"578":{"position":[[11,3]]},"608":{"position":[[11,3]]},"630":{"position":[[13,3]]},"882":{"position":[[0,3]]}}}],["kubecon",{"_index":22,"t":{"31":{"position":[[0,7]]},"41":{"position":[[0,7]]},"65":{"position":[[0,7]]},"83":{"position":[[0,7]]},"288":{"position":[[0,7]]},"304":{"position":[[0,7]]},"324":{"position":[[0,7]]},"364":{"position":[[0,7]]},"380":{"position":[[25,7]]}}}],["languag",{"_index":18,"t":{"27":{"position":[[0,8]]},"53":{"position":[[0,8]]},"336":{"position":[[0,8]]},"360":{"position":[[0,8]]},"416":{"position":[[28,8]]},"822":{"position":[[25,8]]}}}],["latest",{"_index":64,"t":{"119":{"position":[[0,6]]},"167":{"position":[[0,6]]}}}],["limit",{"_index":185,"t":{"535":{"position":[[12,6]]},"810":{"position":[[0,11]]}}}],["line",{"_index":205,"t":{"566":{"position":[[14,4]]}}}],["linkedin",{"_index":104,"t":{"271":{"position":[[0,8]]}}}],["linux",{"_index":162,"t":{"479":{"position":[[0,5]]}}}],["list",{"_index":181,"t":{"525":{"position":[[12,4]]},"650":{"position":[[12,4]]},"737":{"position":[[18,4]]},"868":{"position":[[4,4]]},"870":{"position":[[4,4]]},"971":{"position":[[6,4]]},"973":{"position":[[6,4]]},"1023":{"position":[[10,4]]},"1025":{"position":[[10,4]]}}}],["listobject",{"_index":334,"t":{"1122":{"position":[[0,11]]}}}],["listus",{"_index":335,"t":{"1129":{"position":[[0,9]]}}}],["local",{"_index":254,"t":{"735":{"position":[[18,5]]}}}],["log",{"_index":219,"t":{"594":{"position":[[0,7]]}}}],["longer",{"_index":330,"t":{"1062":{"position":[[33,6]]},"1152":{"position":[[53,6]]}}}],["look",{"_index":130,"t":{"416":{"position":[[37,4]]}}}],["manag",{"_index":326,"t":{"1055":{"position":[[0,8]]}}}],["manual",{"_index":169,"t":{"485":{"position":[[0,8]]}}}],["march",{"_index":108,"t":{"286":{"position":[[20,5]]}}}],["mastodon",{"_index":105,"t":{"273":{"position":[[0,8]]}}}],["maximum",{"_index":186,"t":{"537":{"position":[[0,7]]}}}],["meet",{"_index":107,"t":{"275":{"position":[[18,8]]}}}],["member",{"_index":306,"t":{"915":{"position":[[59,7]]},"955":{"position":[[17,7]]},"957":{"position":[[20,7]]},"1062":{"position":[[23,6]]},"1352":{"position":[[29,7]]}}}],["member'",{"_index":247,"t":{"698":{"position":[[27,8]]},"959":{"position":[[24,8]]}}}],["membership",{"_index":328,"t":{"1060":{"position":[[19,10]]}}}],["metric",{"_index":149,"t":{"454":{"position":[[10,7]]},"590":{"position":[[0,7]]}}}],["migrat",{"_index":158,"t":{"469":{"position":[[14,10]]},"1215":{"position":[[4,7]]}}}],["model",{"_index":48,"t":{"73":{"position":[[8,6]]},"278":{"position":[[8,6]]},"312":{"position":[[8,6]]},"398":{"position":[[24,5]]},"462":{"position":[[30,6]]},"464":{"position":[[27,5]]},"466":{"position":[[40,5]]},"469":{"position":[[8,5]]},"547":{"position":[[40,5]]},"638":{"position":[[29,5]]},"689":{"position":[[0,8]]},"757":{"position":[[0,8]]},"774":{"position":[[0,8]]},"780":{"position":[[15,5]]},"800":{"position":[[23,6]]},"816":{"position":[[8,5]]},"818":{"position":[[0,8]]},"820":{"position":[[0,8]]},"826":{"position":[[29,5]]},"832":{"position":[[34,5]]},"862":{"position":[[16,8]]},"864":{"position":[[37,6]]},"874":{"position":[[13,5]]},"901":{"position":[[12,5]]},"907":{"position":[[0,8]]},"909":{"position":[[0,8]]},"931":{"position":[[28,5]]},"953":{"position":[[57,5]]},"965":{"position":[[11,5]]},"997":{"position":[[25,6]]},"1053":{"position":[[0,8]]},"1076":{"position":[[25,5]]},"1144":{"position":[[0,8]]},"1150":{"position":[[15,5]]},"1152":{"position":[[15,5]]},"1182":{"position":[[0,8]]},"1195":{"position":[[25,5]]},"1211":{"position":[[34,5]]},"1217":{"position":[[42,5]]},"1267":{"position":[[17,8]]},"1273":{"position":[[0,8]]},"1274":{"position":[[39,5]]},"1278":{"position":[[31,5]]},"1288":{"position":[[17,8]]},"1294":{"position":[[0,8]]},"1296":{"position":[[24,5]]},"1300":{"position":[[31,5]]},"1302":{"position":[[4,8]]},"1316":{"position":[[17,8]]},"1322":{"position":[[0,8]]},"1339":{"position":[[17,8]]},"1345":{"position":[[0,8]]},"1362":{"position":[[17,8]]},"1368":{"position":[[0,8]]},"1372":{"position":[[41,5]]},"1374":{"position":[[31,5]]}}}],["modifi",{"_index":264,"t":{"780":{"position":[[4,6]]},"1076":{"position":[[4,6]]},"1150":{"position":[[4,6]]},"1152":{"position":[[4,6]]}}}],["modul",{"_index":294,"t":{"885":{"position":[[0,7]]}}}],["modular",{"_index":47,"t":{"73":{"position":[[0,7]]},"278":{"position":[[0,7]]},"312":{"position":[[0,7]]}}}],["month",{"_index":27,"t":{"35":{"position":[[13,6]]},"61":{"position":[[13,6]]},"79":{"position":[[13,6]]},"95":{"position":[[13,6]]},"109":{"position":[[13,6]]},"123":{"position":[[13,6]]},"141":{"position":[[13,6]]},"155":{"position":[[13,6]]},"171":{"position":[[13,6]]},"185":{"position":[[13,5]]},"201":{"position":[[13,6]]},"227":{"position":[[13,6]]},"300":{"position":[[13,6]]},"318":{"position":[[13,6]]},"344":{"position":[[13,6]]},"368":{"position":[[13,6]]}}}],["monthli",{"_index":106,"t":{"275":{"position":[[0,7]]}}}],["multipl",{"_index":263,"t":{"764":{"position":[[8,8]]}}}],["mysql",{"_index":209,"t":{"572":{"position":[[0,5]]},"604":{"position":[[6,5]]}}}],["na",{"_index":116,"t":{"380":{"position":[[33,2]]}}}],["new",{"_index":7,"t":{"15":{"position":[[5,4]]},"39":{"position":[[5,4]]},"75":{"position":[[10,4]]},"87":{"position":[[0,3]]},"89":{"position":[[10,4]]},"91":{"position":[[0,3]]},"99":{"position":[[0,3]]},"113":{"position":[[0,3]]},"135":{"position":[[0,3]]},"151":{"position":[[0,3]]},"161":{"position":[[0,3]]},"181":{"position":[[0,3]]},"197":{"position":[[0,3]]},"221":{"position":[[0,3]]},"286":{"position":[[13,4]]},"292":{"position":[[0,3]]},"294":{"position":[[10,4]]},"296":{"position":[[0,3]]},"302":{"position":[[13,4]]},"314":{"position":[[10,4]]},"320":{"position":[[13,4]]},"322":{"position":[[5,4]]},"346":{"position":[[13,4]]},"348":{"position":[[5,4]]},"679":{"position":[[29,3]]},"935":{"position":[[13,3]]},"937":{"position":[[13,3]]},"1213":{"position":[[13,3]]}}}],["next",{"_index":3,"t":{"9":{"position":[[7,5]]},"35":{"position":[[8,4]]},"57":{"position":[[7,5]]},"61":{"position":[[8,4]]},"79":{"position":[[8,4]]},"95":{"position":[[8,4]]},"105":{"position":[[7,4]]},"109":{"position":[[8,4]]},"115":{"position":[[7,4]]},"123":{"position":[[8,4]]},"141":{"position":[[8,4]]},"155":{"position":[[8,4]]},"171":{"position":[[8,4]]},"185":{"position":[[8,4]]},"201":{"position":[[8,4]]},"227":{"position":[[8,4]]},"233":{"position":[[7,5]]},"282":{"position":[[7,5]]},"300":{"position":[[8,4]]},"318":{"position":[[8,4]]},"340":{"position":[[7,5]]},"344":{"position":[[8,4]]},"368":{"position":[[8,4]]},"376":{"position":[[7,5]]}}}],["object",{"_index":136,"t":{"420":{"position":[[40,6]]},"422":{"position":[[33,7]]},"525":{"position":[[17,7]]},"698":{"position":[[49,6]]},"725":{"position":[[24,6]]},"727":{"position":[[31,6]]},"820":{"position":[[9,6],[19,6]]},"868":{"position":[[13,6]]},"907":{"position":[[22,7]]},"957":{"position":[[45,6]]},"959":{"position":[[46,6]]},"971":{"position":[[11,7]]},"1001":{"position":[[11,7]]},"1023":{"position":[[15,7]]},"1078":{"position":[[53,6]]},"1080":{"position":[[44,6]]},"1193":{"position":[[9,6],[19,6]]},"1195":{"position":[[36,6],[46,6]]}}}],["obsolet",{"_index":346,"t":{"1217":{"position":[[11,8]]}}}],["oidc",{"_index":214,"t":{"580":{"position":[[0,4]]},"610":{"position":[[0,4]]}}}],["openfga",{"_index":11,"t":{"17":{"position":[[33,7]]},"19":{"position":[[10,7]]},"21":{"position":[[12,7]]},"23":{"position":[[0,7]]},"33":{"position":[[0,7]]},"43":{"position":[[0,7]]},"49":{"position":[[0,7]]},"59":{"position":[[0,7]]},"69":{"position":[[0,7]]},"101":{"position":[[0,7]]},"103":{"position":[[0,7]]},"117":{"position":[[0,7]]},"165":{"position":[[0,7]]},"223":{"position":[[0,7]]},"308":{"position":[[0,7]]},"326":{"position":[[0,7]]},"332":{"position":[[0,7]]},"342":{"position":[[0,7]]},"350":{"position":[[33,7]]},"352":{"position":[[10,7]]},"354":{"position":[[12,7]]},"356":{"position":[[0,7]]},"366":{"position":[[0,7]]},"370":{"position":[[36,7]]},"380":{"position":[[9,7]]},"499":{"position":[[18,7]]},"509":{"position":[[18,7]]},"523":{"position":[[18,7]]},"648":{"position":[[18,7]]},"677":{"position":[[18,7]]},"691":{"position":[[0,7]]},"708":{"position":[[0,7]]},"723":{"position":[[18,7]]},"759":{"position":[[0,7]]},"776":{"position":[[0,7]]},"840":{"position":[[0,7]]},"911":{"position":[[0,7]]},"927":{"position":[[0,7]]},"949":{"position":[[0,7]]},"1039":{"position":[[0,7]]},"1057":{"position":[[0,7]]},"1072":{"position":[[0,7]]},"1094":{"position":[[0,7]]},"1146":{"position":[[0,7]]},"1164":{"position":[[0,7]]},"1184":{"position":[[0,7]]},"1227":{"position":[[0,7]]},"1243":{"position":[[0,7]]},"1265":{"position":[[0,7]]},"1286":{"position":[[0,7]]},"1314":{"position":[[0,7]]},"1337":{"position":[[0,7]]},"1360":{"position":[[0,7]]},"1384":{"position":[[0,7]]}}}],["oper",{"_index":122,"t":{"396":{"position":[[6,10]]},"424":{"position":[[10,8]]},"426":{"position":[[17,8]]},"428":{"position":[[14,8]]}}}],["option",{"_index":196,"t":{"552":{"position":[[49,10]]},"731":{"position":[[9,7]]},"733":{"position":[[0,6]]},"735":{"position":[[0,6]]},"737":{"position":[[0,6]]},"739":{"position":[[18,6]]}}}],["org",{"_index":366,"t":{"1346":{"position":[[38,3]]},"1348":{"position":[[32,3]]},"1350":{"position":[[38,3]]},"1352":{"position":[[25,3]]}}}],["organ",{"_index":308,"t":{"915":{"position":[[84,12]]},"1253":{"position":[[5,12]]},"1325":{"position":[[4,12]]}}}],["out",{"_index":5,"t":{"11":{"position":[[6,4]]},"235":{"position":[[6,4]]},"284":{"position":[[6,4]]},"378":{"position":[[6,4]]}}}],["overview",{"_index":271,"t":{"798":{"position":[[0,8]]}}}],["ownership",{"_index":307,"t":{"915":{"position":[[74,9]]}}}],["packag",{"_index":166,"t":{"479":{"position":[[25,8]]}}}],["paramet",{"_index":275,"t":{"808":{"position":[[10,9]]}}}],["parent",{"_index":301,"t":{"907":{"position":[[9,6]]},"931":{"position":[[45,6]]},"937":{"position":[[71,6]]},"1187":{"position":[[11,6]]},"1189":{"position":[[8,6]]},"1191":{"position":[[15,6]]}}}],["particular",{"_index":153,"t":{"464":{"position":[[16,10]]}}}],["pass",{"_index":154,"t":{"466":{"position":[[12,7]]}}}],["pattern",{"_index":261,"t":{"749":{"position":[[0,8]]}}}],["permiss",{"_index":277,"t":{"818":{"position":[[19,11]]},"830":{"position":[[41,11]]},"909":{"position":[[19,11]]},"1191":{"position":[[35,11]]},"1233":{"position":[[8,11]]},"1235":{"position":[[31,11]]},"1322":{"position":[[24,11]]},"1323":{"position":[[15,11]]},"1325":{"position":[[17,11]]},"1327":{"position":[[11,10]]},"1345":{"position":[[18,11]]},"1346":{"position":[[4,11]]},"1348":{"position":[[4,11]]},"1350":{"position":[[4,11]]},"1352":{"position":[[9,11]]},"1370":{"position":[[15,11]]}}}],["person",{"_index":225,"t":{"636":{"position":[[13,8]]}}}],["pick",{"_index":287,"t":{"866":{"position":[[4,4]]}}}],["plan",{"_index":343,"t":{"1201":{"position":[[19,4]]}}}],["playground",{"_index":220,"t":{"622":{"position":[[12,10]]},"624":{"position":[[14,10]]}}}],["polici",{"_index":96,"t":{"256":{"position":[[8,6]]}}}],["popul",{"_index":355,"t":{"1276":{"position":[[4,10]]}}}],["port",{"_index":222,"t":{"622":{"position":[[38,4]]}}}],["possibl",{"_index":231,"t":{"638":{"position":[[47,8]]},"731":{"position":[[0,8]]}}}],["postgr",{"_index":208,"t":{"570":{"position":[[0,8]]},"602":{"position":[[6,8]]}}}],["potenti",{"_index":156,"t":{"468":{"position":[[0,9]]}}}],["pprof",{"_index":216,"t":{"582":{"position":[[9,7]]}}}],["pre",{"_index":211,"t":{"578":{"position":[[0,3]]},"608":{"position":[[0,3]]}}}],["process",{"_index":286,"t":{"864":{"position":[[2,7]]}}}],["profil",{"_index":215,"t":{"582":{"position":[[0,8]]},"612":{"position":[[9,9]]}}}],["progresivelli",{"_index":159,"t":{"471":{"position":[[0,13]]}}}],["progress",{"_index":68,"t":{"131":{"position":[[3,8]]},"147":{"position":[[3,8]]},"177":{"position":[[3,8]]},"215":{"position":[[3,8]]}}}],["propag",{"_index":363,"t":{"1327":{"position":[[22,11]]}}}],["provid",{"_index":81,"t":{"223":{"position":[[16,9]]}}}],["public",{"_index":234,"t":{"654":{"position":[[11,6]]},"757":{"position":[[9,6]]},"1029":{"position":[[19,6]]}}}],["publicli",{"_index":364,"t":{"1329":{"position":[[30,8]]}}}],["put",{"_index":299,"t":{"899":{"position":[[0,7]]}}}],["queri",{"_index":273,"t":{"804":{"position":[[0,7]]}}}],["reach",{"_index":4,"t":{"11":{"position":[[0,5]]},"235":{"position":[[0,5]]},"284":{"position":[[0,5]]},"378":{"position":[[0,5]]}}}],["read",{"_index":333,"t":{"1110":{"position":[[0,4]]}}}],["recommend",{"_index":183,"t":{"531":{"position":[[8,15]]},"533":{"position":[[9,15]]}}}],["referenc",{"_index":134,"t":{"420":{"position":[[0,11]]},"422":{"position":[[0,11]]}}}],["relat",{"_index":118,"t":{"388":{"position":[[0,7]]},"412":{"position":[[0,7]]},"420":{"position":[[18,9]]},"422":{"position":[[12,9],[25,7]]},"432":{"position":[[0,7]]},"440":{"position":[[0,7]]},"473":{"position":[[0,7]]},"487":{"position":[[0,7]]},"501":{"position":[[0,7]]},"515":{"position":[[0,7]]},"527":{"position":[[0,7]]},"539":{"position":[[0,7]]},"558":{"position":[[0,7]]},"596":{"position":[[0,7]]},"614":{"position":[[0,7]]},"640":{"position":[[0,7]]},"656":{"position":[[0,7]]},"669":{"position":[[0,7]]},"683":{"position":[[0,7]]},"700":{"position":[[0,7]]},"715":{"position":[[0,7]]},"764":{"position":[[17,7]]},"766":{"position":[[0,7]]},"784":{"position":[[0,7]]},"795":{"position":[[0,7]]},"834":{"position":[[0,7]]},"848":{"position":[[0,7]]},"854":{"position":[[17,8]]},"856":{"position":[[20,8]]},"858":{"position":[[20,8]]},"870":{"position":[[9,9]]},"872":{"position":[[11,9]]},"878":{"position":[[0,7]]},"915":{"position":[[19,8]]},"919":{"position":[[0,7]]},"933":{"position":[[22,8]]},"941":{"position":[[0,7]]},"957":{"position":[[30,8]]},"961":{"position":[[0,7]]},"979":{"position":[[0,7]]},"989":{"position":[[0,7]]},"1005":{"position":[[10,9]]},"1007":{"position":[[10,8]]},"1009":{"position":[[19,7]]},"1031":{"position":[[0,7]]},"1047":{"position":[[0,7]]},"1064":{"position":[[0,7]]},"1086":{"position":[[0,7]]},"1138":{"position":[[0,7]]},"1156":{"position":[[0,7]]},"1176":{"position":[[0,7]]},"1187":{"position":[[18,9]]},"1203":{"position":[[0,7]]},"1219":{"position":[[0,7]]},"1237":{"position":[[0,7]]},"1255":{"position":[[34,7]]},"1259":{"position":[[0,7]]},"1331":{"position":[[0,7]]},"1372":{"position":[[60,9]]},"1396":{"position":[[34,7]]},"1402":{"position":[[0,7]]}}}],["relationship",{"_index":97,"t":{"258":{"position":[[8,12]]},"370":{"position":[[12,12]]},"418":{"position":[[7,12]]},"679":{"position":[[33,12]]},"681":{"position":[[32,12]]},"711":{"position":[[18,12]]},"713":{"position":[[20,12]]},"762":{"position":[[19,12]]},"764":{"position":[[25,12]]},"802":{"position":[[20,12]]},"820":{"position":[[26,13]]},"828":{"position":[[7,12]]},"830":{"position":[[8,12]]},"844":{"position":[[13,12]]},"846":{"position":[[19,12]]},"931":{"position":[[52,12]]},"935":{"position":[[17,12]]},"937":{"position":[[17,12]]},"985":{"position":[[39,13]]},"1013":{"position":[[10,12]]},"1015":{"position":[[22,12]]},"1017":{"position":[[10,13]]},"1019":{"position":[[28,14]]},"1043":{"position":[[13,12]]},"1045":{"position":[[19,12]]},"1078":{"position":[[11,12]]},"1080":{"position":[[11,12]]},"1166":{"position":[[16,14]]},"1168":{"position":[[25,13]]},"1172":{"position":[[15,13]]},"1174":{"position":[[15,13]]},"1189":{"position":[[15,12]]},"1193":{"position":[[26,13]]},"1195":{"position":[[53,13]]},"1197":{"position":[[11,12]]},"1199":{"position":[[53,12]]},"1213":{"position":[[17,12]]},"1215":{"position":[[25,12]]},"1217":{"position":[[20,12]]},"1251":{"position":[[11,13]]},"1274":{"position":[[49,12]]},"1276":{"position":[[19,12]]},"1298":{"position":[[19,12]]},"1304":{"position":[[20,13]]},"1392":{"position":[[11,13]]}}}],["releas",{"_index":58,"t":{"91":{"position":[[4,8]]},"99":{"position":[[4,9]]},"113":{"position":[[4,9]]},"296":{"position":[[4,8]]}}}],["remov",{"_index":248,"t":{"713":{"position":[[4,8]]},"762":{"position":[[12,6]]},"1217":{"position":[[4,6]]}}}],["renam",{"_index":284,"t":{"858":{"position":[[3,6]]}}}],["request",{"_index":268,"t":{"789":{"position":[[13,8]]},"791":{"position":[[14,8]]},"1021":{"position":[[16,8]]},"1023":{"position":[[23,8]]},"1025":{"position":[[21,8]]}}}],["requir",{"_index":188,"t":{"543":{"position":[[0,12]]},"1247":{"position":[[0,12]]},"1269":{"position":[[0,12]]},"1290":{"position":[[0,12]]},"1318":{"position":[[0,12]]},"1341":{"position":[[0,12]]},"1364":{"position":[[0,12]]},"1388":{"position":[[0,12]]}}}],["restart",{"_index":198,"t":{"554":{"position":[[5,7]]}}}],["restrict",{"_index":133,"t":{"418":{"position":[[25,12]]}}}],["result",{"_index":187,"t":{"537":{"position":[[8,7]]}}}],["revok",{"_index":327,"t":{"1060":{"position":[[4,8]]},"1062":{"position":[[15,7]]},"1084":{"position":[[4,8]]}}}],["rfc",{"_index":41,"t":{"57":{"position":[[23,5]]},"340":{"position":[[23,5]]}}}],["role",{"_index":91,"t":{"252":{"position":[[8,4]]},"818":{"position":[[9,5]]},"826":{"position":[[44,4]]},"828":{"position":[[51,5]]},"830":{"position":[[62,5]]},"909":{"position":[[9,5]]},"1231":{"position":[[19,5]]},"1235":{"position":[[15,5]]}}}],["rollout",{"_index":160,"t":{"471":{"position":[[14,7]]}}}],["rpm",{"_index":164,"t":{"479":{"position":[[12,3]]}}}],["run",{"_index":191,"t":{"545":{"position":[[25,7]]},"622":{"position":[[0,7]]},"975":{"position":[[0,7]]},"977":{"position":[[0,7]]}}}],["same",{"_index":135,"t":{"420":{"position":[[35,4]]},"762":{"position":[[46,4]]},"764":{"position":[[52,4]]}}}],["scenario",{"_index":351,"t":{"1245":{"position":[[0,8]]},"1271":{"position":[[8,9]]},"1292":{"position":[[8,9]]},"1320":{"position":[[8,9]]},"1343":{"position":[[8,9]]},"1366":{"position":[[8,9]]},"1386":{"position":[[0,8]]}}}],["sdk",{"_index":16,"t":{"25":{"position":[[0,3]]},"51":{"position":[[0,3]]},"71":{"position":[[0,3]]},"310":{"position":[[0,3]]},"334":{"position":[[0,3]]},"358":{"position":[[0,3]]}}}],["search",{"_index":251,"t":{"733":{"position":[[10,7]]},"735":{"position":[[53,7]]},"737":{"position":[[36,6]]}}}],["section",{"_index":119,"t":{"388":{"position":[[8,8]]},"412":{"position":[[8,8]]},"432":{"position":[[8,8]]},"440":{"position":[[8,8]]},"473":{"position":[[8,8]]},"487":{"position":[[8,8]]},"501":{"position":[[8,8]]},"515":{"position":[[8,8]]},"527":{"position":[[8,8]]},"539":{"position":[[8,8]]},"558":{"position":[[8,8]]},"596":{"position":[[8,8]]},"614":{"position":[[8,8]]},"640":{"position":[[8,8]]},"656":{"position":[[8,8]]},"669":{"position":[[8,8]]},"683":{"position":[[8,8]]},"700":{"position":[[8,8]]},"715":{"position":[[8,8]]},"766":{"position":[[8,8]]},"784":{"position":[[8,8]]},"795":{"position":[[8,8]]},"834":{"position":[[8,8]]},"848":{"position":[[8,8]]},"878":{"position":[[8,8]]},"919":{"position":[[8,8]]},"941":{"position":[[8,8]]},"961":{"position":[[8,8]]},"979":{"position":[[8,8]]},"989":{"position":[[8,8]]},"1031":{"position":[[8,8]]},"1047":{"position":[[8,8]]},"1064":{"position":[[8,8]]},"1086":{"position":[[8,8]]},"1138":{"position":[[8,8]]},"1156":{"position":[[8,8]]},"1176":{"position":[[8,8]]},"1203":{"position":[[8,8]]},"1219":{"position":[[8,8]]},"1237":{"position":[[8,8]]},"1259":{"position":[[8,8]]},"1331":{"position":[[8,8]]},"1402":{"position":[[8,8]]}}}],["secur",{"_index":60,"t":{"103":{"position":[[8,8]]},"213":{"position":[[0,8]]}}}],["securitycon",{"_index":63,"t":{"117":{"position":[[22,11]]},"165":{"position":[[22,11]]}}}],["see",{"_index":26,"t":{"35":{"position":[[0,3]]},"61":{"position":[[0,3]]},"79":{"position":[[0,3]]},"95":{"position":[[0,3]]},"109":{"position":[[0,3]]},"123":{"position":[[0,3]]},"141":{"position":[[0,3]]},"155":{"position":[[0,3]]},"171":{"position":[[0,3]]},"185":{"position":[[0,3]]},"201":{"position":[[0,3]]},"227":{"position":[[0,3]]},"300":{"position":[[0,3]]},"318":{"position":[[0,3]]},"344":{"position":[[0,3]]},"368":{"position":[[0,3]]},"1199":{"position":[[13,3]]}}}],["server",{"_index":190,"t":{"545":{"position":[[15,6]]},"550":{"position":[[32,6]]},"554":{"position":[[17,6]]}}}],["servic",{"_index":80,"t":{"223":{"position":[[8,7]]},"499":{"position":[[45,7]]},"1400":{"position":[[37,7]]}}}],["session",{"_index":30,"t":{"43":{"position":[[22,8]]},"326":{"position":[[22,8]]}}}],["setup",{"_index":172,"t":{"495":{"position":[[16,5]]}}}],["share",{"_index":212,"t":{"578":{"position":[[4,6]]},"608":{"position":[[4,6]]},"630":{"position":[[6,6]]},"1329":{"position":[[4,7]]}}}],["ship",{"_index":71,"t":{"145":{"position":[[5,7]]},"175":{"position":[[5,7]]},"191":{"position":[[5,7]]},"211":{"position":[[5,8]]}}}],["slack",{"_index":52,"t":{"77":{"position":[[37,5]]},"93":{"position":[[37,5]]},"107":{"position":[[37,5]]},"121":{"position":[[37,5]]},"139":{"position":[[37,5]]},"169":{"position":[[37,5]]},"263":{"position":[[0,5]]},"298":{"position":[[37,5]]},"316":{"position":[[37,5]]}}}],["solut",{"_index":309,"t":{"917":{"position":[[20,9]]},"1154":{"position":[[15,8]]}}}],["specif",{"_index":249,"t":{"727":{"position":[[22,8]]}}}],["specifi",{"_index":229,"t":{"638":{"position":[[7,7]]}}}],["sqlite",{"_index":210,"t":{"574":{"position":[[0,6]]},"606":{"position":[[6,6]]}}}],["start",{"_index":143,"t":{"436":{"position":[[11,5]]},"491":{"position":[[11,5]]},"505":{"position":[[11,5]]},"519":{"position":[[11,5]]},"644":{"position":[[11,5]]},"673":{"position":[[11,5]]},"687":{"position":[[11,5]]},"704":{"position":[[11,5]]},"719":{"position":[[11,5]]},"753":{"position":[[11,5]]},"772":{"position":[[11,5]]},"814":{"position":[[11,5]]},"838":{"position":[[11,5]]},"905":{"position":[[11,5]]},"923":{"position":[[11,5]]},"945":{"position":[[11,5]]},"983":{"position":[[11,5]]},"1035":{"position":[[11,5]]},"1051":{"position":[[11,5]]},"1068":{"position":[[11,5]]},"1090":{"position":[[11,5]]},"1142":{"position":[[11,5]]},"1160":{"position":[[11,5]]},"1180":{"position":[[11,5]]},"1207":{"position":[[11,5]]},"1223":{"position":[[11,5]]},"1241":{"position":[[11,5]]},"1263":{"position":[[11,5]]},"1284":{"position":[[11,5]]},"1312":{"position":[[11,5]]},"1335":{"position":[[11,5]]},"1358":{"position":[[11,5]]},"1382":{"position":[[11,5]]}}}],["step",{"_index":144,"t":{"438":{"position":[[0,4],[8,4]]},"444":{"position":[[0,4],[8,4]]},"493":{"position":[[0,4],[8,4]]},"507":{"position":[[0,4],[8,4]]},"521":{"position":[[0,4],[8,4]]},"600":{"position":[[0,4],[8,4]]},"646":{"position":[[0,4],[8,4]]},"675":{"position":[[0,4],[8,4]]},"693":{"position":[[0,4],[8,4]]},"710":{"position":[[0,4],[8,4]]},"721":{"position":[[0,4],[8,4]]},"761":{"position":[[0,4],[8,4]]},"778":{"position":[[0,4],[8,4]]},"824":{"position":[[0,4],[8,4]]},"842":{"position":[[0,4],[8,4]]},"913":{"position":[[0,4],[8,4]]},"929":{"position":[[0,4],[8,4]]},"951":{"position":[[0,4],[8,4]]},"1041":{"position":[[0,4],[8,4]]},"1059":{"position":[[0,4],[8,4]]},"1074":{"position":[[0,4],[8,4]]},"1148":{"position":[[0,4],[8,4]]},"1186":{"position":[[0,4],[8,4]]},"1209":{"position":[[0,4],[8,4]]},"1229":{"position":[[0,4],[8,4]]},"1249":{"position":[[0,4],[8,4]]},"1390":{"position":[[0,4],[8,4]]},"1400":{"position":[[12,4]]}}}],["storag",{"_index":207,"t":{"568":{"position":[[17,7]]}}}],["store",{"_index":129,"t":{"410":{"position":[[7,6]]},"547":{"position":[[30,5]]},"556":{"position":[[22,5]]},"636":{"position":[[7,5]]},"999":{"position":[[10,6]]}}}],["studio",{"_index":32,"t":{"45":{"position":[[7,6]]},"328":{"position":[[7,6]]}}}],["summari",{"_index":260,"t":{"741":{"position":[[0,7]]},"1136":{"position":[[0,7]]},"1257":{"position":[[0,7]]},"1280":{"position":[[0,7]]},"1306":{"position":[[0,7]]},"1354":{"position":[[0,7]]},"1376":{"position":[[0,7]]},"1398":{"position":[[0,7]]}}}],["super",{"_index":53,"t":{"83":{"position":[[24,5]]},"288":{"position":[[24,5]]}}}],["support",{"_index":148,"t":{"454":{"position":[[0,9]]},"456":{"position":[[0,9]]},"808":{"position":[[0,9]]},"933":{"position":[[66,7]]}}}],["system",{"_index":339,"t":{"1170":{"position":[[20,6]]},"1231":{"position":[[54,6]]}}}],["take",{"_index":352,"t":{"1253":{"position":[[0,4]]},"1394":{"position":[[0,4]]},"1400":{"position":[[0,6]]}}}],["target",{"_index":152,"t":{"464":{"position":[[7,6]]}}}],["team",{"_index":6,"t":{"15":{"position":[[0,4]]},"39":{"position":[[0,4]]},"322":{"position":[[0,4]]},"348":{"position":[[0,4]]},"380":{"position":[[17,4]]},"953":{"position":[[31,4]]},"955":{"position":[[32,4]]},"957":{"position":[[15,4]]},"1348":{"position":[[20,5]]},"1350":{"position":[[26,5]]}}}],["telemetri",{"_index":146,"t":{"448":{"position":[[9,9]]},"450":{"position":[[12,9]]},"588":{"position":[[0,9]]}}}],["test",{"_index":290,"t":{"874":{"position":[[4,4]]},"967":{"position":[[6,5]]},"969":{"position":[[12,5]]},"971":{"position":[[19,5]]},"973":{"position":[[17,5]]},"975":{"position":[[8,5]]},"977":{"position":[[8,5]]}}}],["those",{"_index":288,"t":{"870":{"position":[[23,5]]}}}],["tie",{"_index":280,"t":{"828":{"position":[[30,3]]}}}],["time",{"_index":370,"t":{"1394":{"position":[[5,4]]}}}],["togeth",{"_index":300,"t":{"899":{"position":[[15,8]]}}}],["token",{"_index":323,"t":{"985":{"position":[[27,7]]}}}],["trace",{"_index":150,"t":{"458":{"position":[[0,7]]},"592":{"position":[[0,7]]}}}],["track",{"_index":297,"t":{"893":{"position":[[6,8]]}}}],["transact",{"_index":262,"t":{"762":{"position":[[51,11]]},"764":{"position":[[57,11]]}}}],["transit",{"_index":49,"t":{"77":{"position":[[0,13]]},"93":{"position":[[0,13]]},"107":{"position":[[0,13]]},"121":{"position":[[0,13]]},"139":{"position":[[0,13]]},"169":{"position":[[0,13]]},"298":{"position":[[0,13]]},"316":{"position":[[0,13]]}}}],["trip",{"_index":349,"t":{"1231":{"position":[[41,4]]}}}],["tupl",{"_index":114,"t":{"370":{"position":[[25,6]]},"400":{"position":[[7,6]]},"408":{"position":[[7,6]]},"636":{"position":[[50,6]]},"679":{"position":[[46,6]]},"681":{"position":[[45,6]]},"762":{"position":[[32,6]]},"764":{"position":[[38,6]]},"802":{"position":[[33,6]]},"828":{"position":[[20,6]]},"830":{"position":[[21,6]]},"844":{"position":[[26,5]]},"935":{"position":[[30,5]]},"937":{"position":[[30,5]]},"965":{"position":[[21,6]]},"1013":{"position":[[23,6]]},"1015":{"position":[[35,6]]},"1027":{"position":[[20,7]]},"1043":{"position":[[26,5]]},"1078":{"position":[[24,6]]},"1080":{"position":[[24,6]]},"1189":{"position":[[28,6]]},"1197":{"position":[[24,6]]},"1213":{"position":[[30,5]]},"1215":{"position":[[38,6]]},"1255":{"position":[[15,6]]},"1274":{"position":[[62,6]]},"1276":{"position":[[32,6]]},"1298":{"position":[[32,6]]},"1396":{"position":[[15,6]]}}}],["twitter",{"_index":102,"t":{"267":{"position":[[12,8]]}}}],["type",{"_index":132,"t":{"418":{"position":[[20,4]]},"654":{"position":[[0,4]]},"725":{"position":[[31,5]]},"727":{"position":[[38,4]]},"808":{"position":[[20,5]]},"826":{"position":[[49,4]]},"854":{"position":[[9,4]]},"856":{"position":[[12,4]]},"858":{"position":[[12,4]]},"868":{"position":[[20,5]]},"870":{"position":[[29,5]]},"887":{"position":[[0,4]]},"933":{"position":[[47,4]]},"993":{"position":[[10,5]]},"995":{"position":[[10,4]]},"1009":{"position":[[32,5]]},"1029":{"position":[[8,4]]}}}],["understand",{"_index":347,"t":{"1231":{"position":[[4,10]]},"1251":{"position":[[0,10]]},"1392":{"position":[[0,10]]}}}],["union",{"_index":137,"t":{"424":{"position":[[4,5]]}}}],["up",{"_index":74,"t":{"193":{"position":[[7,2]]}}}],["upcom",{"_index":78,"t":{"219":{"position":[[0,8]]}}}],["updat",{"_index":278,"t":{"826":{"position":[[4,6]]},"931":{"position":[[4,6]]},"933":{"position":[[4,6]]},"1278":{"position":[[4,8]]},"1300":{"position":[[4,8]]},"1372":{"position":[[4,8]]},"1374":{"position":[[4,8]]}}}],["us",{"_index":0,"t":{"5":{"position":[[0,3]]},"7":{"position":[[7,3]]},"205":{"position":[[7,3]]},"231":{"position":[[7,3]]},"239":{"position":[[7,3]]},"280":{"position":[[7,3]]},"372":{"position":[[0,3]]},"374":{"position":[[7,3]]},"468":{"position":[[10,3]]},"552":{"position":[[45,3]]},"562":{"position":[[0,5]]},"564":{"position":[[0,5]]},"566":{"position":[[0,5]]},"602":{"position":[[0,5]]},"604":{"position":[[0,5]]},"606":{"position":[[0,5]]},"628":{"position":[[0,5]]},"630":{"position":[[0,5]]},"632":{"position":[[0,5]]},"663":{"position":[[8,3]]},"747":{"position":[[0,3]]},"830":{"position":[[4,3]]},"977":{"position":[[14,5]]},"1099":{"position":[[8,4]]},"1101":{"position":[[24,3]]},"1106":{"position":[[8,4]]},"1108":{"position":[[24,3]]},"1113":{"position":[[8,4]]},"1115":{"position":[[24,3]]},"1120":{"position":[[8,4]]},"1125":{"position":[[8,4]]},"1132":{"position":[[8,4]]},"1255":{"position":[[0,3]]},"1396":{"position":[[0,3]]}}}],["user",{"_index":175,"t":{"497":{"position":[[25,4]]},"650":{"position":[[17,5]]},"689":{"position":[[9,4]]},"774":{"position":[[9,4]]},"828":{"position":[[38,5]]},"955":{"position":[[8,5]]},"973":{"position":[[11,5]]},"985":{"position":[[0,4]]},"1003":{"position":[[10,5]]},"1009":{"position":[[27,4]]},"1025":{"position":[[15,5]]},"1053":{"position":[[9,4]]},"1078":{"position":[[37,4]]},"1082":{"position":[[15,4]]},"1144":{"position":[[9,4]]},"1150":{"position":[[24,5]]},"1152":{"position":[[24,5]]},"1182":{"position":[[9,4]]},"1235":{"position":[[10,4]]},"1304":{"position":[[37,5]]}}}],["userset",{"_index":232,"t":{"652":{"position":[[0,8]]},"787":{"position":[[10,8]]},"789":{"position":[[32,9]]},"791":{"position":[[33,9]]}}}],["v1.4",{"_index":15,"t":{"23":{"position":[[8,5]]},"356":{"position":[[8,5]]}}}],["v1.4.3",{"_index":36,"t":{"49":{"position":[[8,6]]},"332":{"position":[[8,6]]}}}],["valid",{"_index":329,"t":{"1062":{"position":[[4,10]]},"1082":{"position":[[4,10]]}}}],["variabl",{"_index":203,"t":{"564":{"position":[[18,9]]},"566":{"position":[[19,9]]}}}],["verifi",{"_index":282,"t":{"832":{"position":[[4,6]]},"917":{"position":[[4,6]]},"1154":{"position":[[4,6]]}}}],["version",{"_index":123,"t":{"398":{"position":[[30,8]]}}}],["view",{"_index":151,"t":{"462":{"position":[[0,7]]},"901":{"position":[[0,7]]}}}],["viewer",{"_index":267,"t":{"780":{"position":[[40,6]]},"782":{"position":[[27,7]]}}}],["visual",{"_index":31,"t":{"45":{"position":[[0,6]]},"328":{"position":[[0,6]]}}}],["vs",{"_index":19,"t":{"29":{"position":[[0,2]]},"362":{"position":[[0,2]]}}}],["want",{"_index":75,"t":{"207":{"position":[[3,4]]},"245":{"position":[[3,4]]},"552":{"position":[[29,4]]}}}],["what'",{"_index":39,"t":{"57":{"position":[[0,6]]},"105":{"position":[[0,6]]},"115":{"position":[[0,6]]},"233":{"position":[[0,6]]},"282":{"position":[[0,6]]},"340":{"position":[[0,6]]}}}],["what’",{"_index":2,"t":{"9":{"position":[[0,6]]},"376":{"position":[[0,6]]}}}],["whenev",{"_index":230,"t":{"638":{"position":[[38,8]]}}}],["wiki",{"_index":298,"t":{"895":{"position":[[0,4]]}}}],["within",{"_index":348,"t":{"1231":{"position":[[30,6]]}}}],["without",{"_index":341,"t":{"1199":{"position":[[38,7]]},"1251":{"position":[[25,7]]},"1392":{"position":[[25,7]]}}}],["work",{"_index":72,"t":{"159":{"position":[[12,7]]},"243":{"position":[[7,4]]},"398":{"position":[[0,4]]},"667":{"position":[[7,4]]},"789":{"position":[[22,4]]},"791":{"position":[[23,4]]},"832":{"position":[[40,5]]},"917":{"position":[[30,4]]},"1154":{"position":[[24,5]]},"1231":{"position":[[25,4]]}}}],["workspac",{"_index":367,"t":{"1368":{"position":[[9,10]]},"1372":{"position":[[17,9]]}}}],["write",{"_index":240,"t":{"679":{"position":[[12,5]]},"681":{"position":[[12,5]]},"802":{"position":[[0,7]]},"967":{"position":[[0,5]]},"969":{"position":[[0,5]]},"971":{"position":[[0,5]]},"973":{"position":[[0,5]]},"1296":{"position":[[4,7]]}}}],["writer",{"_index":305,"t":{"915":{"position":[[42,7]]}}}],["x",{"_index":100,"t":{"267":{"position":[[0,1]]}}}],["yaml",{"_index":125,"t":{"402":{"position":[[0,4]]}}}],["youtub",{"_index":103,"t":{"269":{"position":[[0,7]]}}}],["zanzibar",{"_index":98,"t":{"260":{"position":[[8,9]]},"430":{"position":[[11,8]]}}}]],"pipeline":["stemmer"]}},{"documents":[{"i":1,"t":"Archive","s":"","u":"/pr-preview/pr-921/blog/archive","p":1},{"i":3,"t":"Conditional Relationship Tuples for OpenFGA","s":"Conditional Relationship Tuples for OpenFGA","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","p":3},{"i":13,"t":"Fine Grained News","s":"Fine Grained News - December 2023","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","p":13},{"i":37,"t":"Fine Grained News","s":"Fine Grained News - January 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","p":37},{"i":63,"t":"Fine Grained News","s":"Fine Grained News - February 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","p":63},{"i":81,"t":"Fine Grained News","s":"Fine Grained News - March 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","p":81},{"i":97,"t":"Fine Grained News","s":"Fine Grained News - April 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","p":97},{"i":111,"t":"Fine Grained News","s":"Fine Grained News - May 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","p":111},{"i":125,"t":"Fine Grained News","s":"Fine Grained News - July 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","p":125},{"i":143,"t":"Fine Grained News","s":"Fine Grained News - September 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","p":143},{"i":157,"t":"Fine Grained News","s":"Fine Grained News - June 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","p":157},{"i":173,"t":"Fine Grained News","s":"Fine Grained News - October 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","p":173},{"i":187,"t":"OpenFGA at KubeCon","s":"Join the OpenFGA team at KubeCon NA 2023","u":"/pr-preview/pr-921/blog/kubecon-na-2023","p":187},{"i":189,"t":"Fine Grained News","s":"Fine Grained News - November 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","p":189},{"i":203,"t":"List Users API","s":"List Users API","u":"/pr-preview/pr-921/blog/list-users-announcement","p":203},{"i":209,"t":"Fine Grained News","s":"Fine Grained News - August 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","p":209},{"i":229,"t":"Modular Models","s":"Modular Models","u":"/pr-preview/pr-921/blog/modular-models-announcement","p":229},{"i":237,"t":"Query Consistency Options in OpenFGA","s":"Query Consistency Options in OpenFGA","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","p":237},{"i":247,"t":"Introduction to Authorization","s":"Authorization Concepts","u":"/pr-preview/pr-921/docs/authorization-concepts","p":247},{"i":262,"t":"Learn how to engage with the OpenFGA Community","s":"OpenFGA Community","u":"/pr-preview/pr-921/docs/community","p":262},{"i":277,"t":"Blog","s":"","u":"/pr-preview/pr-921/blog/page/2","p":277},{"i":382,"t":"Introduction to FGA","s":"Introduction to OpenFGA","u":"/pr-preview/pr-921/docs/fga","p":382},{"i":390,"t":"The following will provide a step-by-step guide on how to get started with .","s":"Content","u":"/pr-preview/pr-921/docs/getting-started","p":390},{"i":392,"t":"Use the FGA CLI","s":"Use the FGA CLI","u":"/pr-preview/pr-921/docs/getting-started/cli","p":392},{"i":414,"t":"Learning about the FGA configuration language and using it to build a representation of a system's authorization model","s":"Configuration Language","u":"/pr-preview/pr-921/docs/configuration-language","p":414},{"i":434,"t":"Configuring authorization model for a store","s":"Configure Authorization Model for a Store","u":"/pr-preview/pr-921/docs/getting-started/configure-model","p":434},{"i":442,"t":"Creating a store","s":"Create a Store","u":"/pr-preview/pr-921/docs/getting-started/create-store","p":442},{"i":446,"t":"How to configure your SDK Client to collect telemetry using OpenTelemetry.","s":"Configure SDK Client Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","p":446},{"i":460,"t":"Learn how to take advantage of the immutable properties of Authorization Models","s":"Immutable Authorization Models","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","p":460},{"i":475,"t":"Installing SDK client","s":"Install SDK Client","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","p":475},{"i":489,"t":"Integrating FGA within a framework, such as Fastify or Fiber","s":"Integrate Within a Framework","u":"/pr-preview/pr-921/docs/getting-started/framework","p":489},{"i":503,"t":"Checking if a user is authorized to perform an action on a resource","s":"Perform a Check","u":"/pr-preview/pr-921/docs/getting-started/perform-check","p":503},{"i":517,"t":"List all objects a user is authorized to perform a specified action for a given resource type","s":"Perform a list objects call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","p":517},{"i":529,"t":"Best Practices of Running OpenFGA in a Production Environment","s":"Running OpenFGA in Production","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","p":529},{"i":541,"t":"How to enable and setup the built-in access control OpenFGA server (experimental)","s":"🛡️Setup Access Control","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","p":541},{"i":560,"t":"Configuring an OpenFGA Server","s":"Configuring OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","p":560},{"i":598,"t":"Setting up an OpenFGA server with Docker","s":"🐳 Setup OpenFGA with Docker","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","p":598},{"i":616,"t":"Setting up an OpenFGA server with Kubernetes","s":"☸️ Setup OpenFGA with Kubernetes","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/kubernetes","p":616},{"i":618,"t":"Setting up an OpenFGA server","s":"Setup OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/overview","p":618},{"i":620,"t":"Setting up an OpenFGA server","s":"Using the OpenFGA Playground","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/playground","p":620},{"i":626,"t":"Setting up an OpenFGA SDK client","s":"Setup SDK Client for Store","u":"/pr-preview/pr-921/docs/getting-started/setup-sdk-client","p":626},{"i":634,"t":"Best Practices of Managing Tuples and Invoking APIs","s":"Best Practices of Managing Tuples and Invoking APIs","u":"/pr-preview/pr-921/docs/getting-started/tuples-api-best-practices","p":634},{"i":642,"t":"List all users that have a certain relation with a particular object","s":"Perform a List Users call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","p":642},{"i":658,"t":"Programmatically writing authorization related data and interact with the API","s":"Content","u":"/pr-preview/pr-921/docs/interacting","p":658},{"i":660,"t":"Query Consistency Modes","s":"Query Consistency Modes","u":"/pr-preview/pr-921/docs/interacting/consistency","p":660},{"i":671,"t":"Updating system state by writing and deleting relationship tuples","s":"Update Relationship Tuples","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","p":671},{"i":685,"t":"Granting a group of users access to a particular object","s":"Managing Group Access","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","p":685},{"i":702,"t":"Granting a user access to a particular object","s":"Managing User Access","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","p":702},{"i":717,"t":"Getting tuple changes","s":"How to get tuple changes","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","p":717},{"i":729,"t":"Integrating FGA into your search","s":"Search With Permissions","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","p":729},{"i":743,"t":"This section has guides, concepts and examples that help you define an authorization model.","s":"Content","u":"/pr-preview/pr-921/docs/modeling","p":743},{"i":745,"t":"Advanced use cases and patterns for authorization modeling","s":"Advanced Use-Cases","u":"/pr-preview/pr-921/docs/modeling/advanced","p":745},{"i":751,"t":"Updating multiple relationship tuples in a single transaction","s":"Transactional Writes","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","p":751},{"i":768,"t":"This section has guides that on the building blocks of authorization model.","s":"Content","u":"/pr-preview/pr-921/docs/modeling/building-blocks","p":768},{"i":770,"t":"Modeling Concepts: Concentric Relationships","s":"Concentric Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","p":770},{"i":786,"t":"Modeling with userset","s":"Usersets","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","p":786},{"i":797,"t":"Modeling relationships with Conditions","s":"Conditions","u":"/pr-preview/pr-921/docs/modeling/conditions","p":797},{"i":812,"t":"Modeling custom and dynamically changing roles in your system","s":"Custom Roles","u":"/pr-preview/pr-921/docs/modeling/custom-roles","p":812},{"i":836,"t":"Granting a user access to an object","s":"Direct Access","u":"/pr-preview/pr-921/docs/modeling/direct-access","p":836},{"i":850,"t":"This section has guides that focus on migrating models and relations.","s":"Content","u":"/pr-preview/pr-921/docs/modeling/migrating","p":850},{"i":852,"t":"You can think of model migrations for in the same way as you think about relational database migrations. You can perform migrations with or without downtime for both, and for some changes, doing them without downtime is harder.","s":"Model Migrations","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-models","p":852},{"i":860,"t":"An introduction to modeling","s":"Get Started with Modeling","u":"/pr-preview/pr-921/docs/modeling/getting-started","p":860},{"i":880,"t":"Modular Models","s":"Modular Models","u":"/pr-preview/pr-921/docs/modeling/modular-models","p":880},{"i":903,"t":"Modeling system that requires multiple authorizations before allowing users to perform actions on particular objects","s":"Multiple Restrictions","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","p":903},{"i":921,"t":"Indicate relationships between objects, and how users' relationships to one object can affect their relationship with another","s":"Parent-Child Objects","u":"/pr-preview/pr-921/docs/modeling/parent-child","p":921},{"i":943,"t":"Adding users to groups and granting group members access to an object","s":"User Groups","u":"/pr-preview/pr-921/docs/modeling/user-groups","p":943},{"i":963,"t":"Testing Models","s":"Testing Models","u":"/pr-preview/pr-921/docs/modeling/testing","p":963},{"i":981,"t":"Using identity token claims to define contextual relations","s":"Use Token Claims As Contextual Tuples","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","p":981},{"i":991,"t":"Learning about FGA concepts","s":"Concepts","u":"/pr-preview/pr-921/docs/concepts","p":991},{"i":1033,"t":"Granting public access to an object","s":"Public Access","u":"/pr-preview/pr-921/docs/modeling/public-access","p":1033},{"i":1049,"t":"Updating a user's membership to a group by adding and removing them from it","s":"Managing Group Membership","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","p":1049},{"i":1066,"t":"Granting a user access to a particular object through a relationship with another object","s":"Managing Relationships Between Objects","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","p":1066},{"i":1088,"t":"An overview of how to use the Check, Read, Expand, and ListObject APIs","s":"Relationship Queries: Check, Read, Expand, ListObjects and ListUsers","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","p":1088},{"i":1140,"t":"Preventing certain users from accessing objects","s":"Blocklists","u":"/pr-preview/pr-921/docs/modeling/blocklists","p":1140},{"i":1158,"t":"Modeling Concepts: Direct Relationships","s":"Direct Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","p":1158},{"i":1178,"t":"Modeling relationships between objects (e.g. folder parent of a document)","s":"Object to Object Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","p":1178},{"i":1205,"t":"Migrating relations","s":"Migrating Relations","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","p":1205},{"i":1221,"t":"Modeling basic roles and permissions","s":"Roles and Permissions","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","p":1221},{"i":1239,"t":"Modeling authorization through organization context","s":"Authorization Through Organization Context","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","p":1239},{"i":1261,"t":"Modeling entitlements for a system","s":"Modeling Entitlements for a System with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","p":1261},{"i":1282,"t":"Modeling fine grained authorization for an IoT security camera system","s":"Modeling Authorization for an IoT Security System with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","p":1282},{"i":1310,"t":"Modeling Google Drive permissions","s":"Modeling Google Drive permissions with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","p":1310},{"i":1333,"t":"Modeling GitHub permissions","s":"Modeling GitHub permissions with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/github","p":1333},{"i":1356,"t":"Modeling authorization for Slack","s":"Modeling Authorization for Slack with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","p":1356},{"i":1380,"t":"Checking relations that depends on certain dynamic or contextual data (such as time, location, ip address, weather) that have not been written","s":"Contextual and Time-Based Authorization","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","p":1380}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/1",[0,6.008]],["t/3",[1,3.834,2,2.387,3,2.979,4,2.09]],["t/13",[5,2.205,6,2.205,7,2.296]],["t/37",[5,2.205,6,2.205,7,2.296]],["t/63",[5,2.205,6,2.205,7,2.296]],["t/81",[5,2.205,6,2.205,7,2.296]],["t/97",[5,2.205,6,2.205,7,2.296]],["t/111",[5,2.205,6,2.205,7,2.296]],["t/125",[5,2.205,6,2.205,7,2.296]],["t/143",[5,2.205,6,2.205,7,2.296]],["t/157",[5,2.205,6,2.205,7,2.296]],["t/173",[5,2.205,6,2.205,7,2.296]],["t/187",[4,2.548,8,5.349]],["t/189",[5,2.205,6,2.205,7,2.296]],["t/203",[9,3.812,10,2.296,11,3.513]],["t/209",[5,2.205,6,2.205,7,2.296]],["t/229",[12,4.674,13,1.555]],["t/237",[4,2.09,14,3.834,15,3.834,16,4.387]],["t/247",[17,4.23,18,2.352]],["t/262",[4,2.09,19,3.197,20,4.387,21,4.387]],["t/277",[22,6.008]],["t/382",[17,4.23,23,3.412]],["t/390",[24,3.455,25,3.455,26,4.979,27,2.518,28,3.455,29,3.455]],["t/392",[23,3.075,30,3.075,31,4.821]],["t/414",[13,0.829,18,1.253,19,2.076,23,1.818,30,1.818,32,2.076,33,2.85,34,2.49,35,2.85,36,2.85]],["t/434",[13,1.276,18,1.929,32,3.197,37,3.834]],["t/442",[37,4.674,38,5.349]],["t/446",[30,2.204,32,2.518,39,2.732,40,2.732,41,3.455,42,3.455,43,3.455]],["t/460",[13,1.005,18,1.519,19,2.518,44,3.455,45,3.455,46,3.455,47,3.455]],["t/475",[39,3.812,40,3.812,48,4.821]],["t/489",[23,2.204,49,3.019,50,3.455,51,3.455,52,3.019,53,3.455,54,3.455]],["t/503",[10,1.771,18,1.635,55,2.94,56,2.71,57,2.94,58,3.249]],["t/517",[9,2.253,10,1.357,18,1.253,56,2.076,57,2.253,58,2.49,59,1.357,60,2.85,61,2.85,62,2.85]],["t/529",[4,1.771,63,3.249,64,3.249,65,3.719,66,3.719,67,3.719]],["t/541",[4,1.537,68,3.227,69,3.227,70,3.227,71,1.844,72,3.227,73,2.058,74,3.227]],["t/560",[4,2.296,32,3.513,73,3.075]],["t/598",[4,1.917,73,2.568,75,2.734,76,2.734,77,4.025]],["t/616",[4,1.917,73,2.568,75,2.734,76,2.734,78,4.025]],["t/618",[4,2.09,73,2.798,75,2.979,76,2.979]],["t/620",[4,2.09,73,2.798,75,2.979,76,2.979]],["t/626",[4,1.917,39,3.183,40,3.183,75,2.734,76,2.734]],["t/634",[3,2.525,11,2.71,63,3.249,64,3.249,79,3.719,80,3.719]],["t/642",[9,2.94,10,1.771,59,1.771,81,2.94,82,2.24,83,2.525]],["t/658",[11,2.518,18,1.519,82,2.082,84,3.455,85,3.019,86,3.019,87,3.455]],["t/660",[14,4.213,15,4.213,88,4.821]],["t/671",[2,1.88,3,2.346,85,3.019,89,2.732,90,2.346,91,3.455,92,3.455]],["t/685",[10,1.771,59,1.771,71,2.125,83,2.525,93,2.372,94,2.94]],["t/702",[10,1.917,59,1.917,71,2.301,83,2.734,93,2.568]],["t/717",[3,3.274,95,4.821,96,3.812]],["t/729",[23,3.075,49,4.213,97,4.821]],["t/743",[13,0.938,18,1.419,27,2.351,98,2.551,99,2.351,100,3.227,101,3.227,102,2.82]],["t/745",[13,1.081,18,1.635,30,2.372,103,3.719,104,3.719,105,3.719]],["t/751",[2,2.023,3,2.525,89,2.94,106,3.249,107,3.719,108,3.719]],["t/768",[13,1.081,18,1.635,27,2.71,34,3.249,98,2.94,109,3.719]],["t/770",[2,2.387,13,1.276,99,3.197,110,4.387]],["t/786",[13,1.555,111,5.349]],["t/797",[1,4.213,2,2.623,13,1.402]],["t/812",[13,1.081,90,2.525,96,2.94,112,3.719,113,3.249,114,3.249]],["t/836",[10,2.09,59,2.09,71,2.508,93,2.798]],["t/850",[13,1.081,27,2.71,82,2.24,98,2.94,115,3.719,116,2.94]],["t/852",[13,0.543,56,1.361,82,1.125,96,1.477,116,3.122,117,3.088,118,1.868,119,1.868,120,1.868,121,3.088,122,3.088,123,1.868,124,1.868,125,1.868]],["t/860",[13,1.555,17,4.23]],["t/880",[12,4.674,13,1.555]],["t/903",[10,1.215,13,0.742,18,1.122,56,1.859,57,2.018,59,1.215,83,1.733,90,1.733,106,2.23,126,2.552,127,2.552,128,2.552]],["t/921",[2,2.739,10,1.282,59,1.97,129,2.692,130,2.353,131,2.692,132,2.692,133,2.353]],["t/943",[10,1.537,59,1.537,71,1.844,93,2.058,94,3.746,134,2.82,135,3.227]],["t/963",[13,1.555,136,5.349]],["t/981",[30,2.204,82,2.082,102,3.019,137,3.455,138,3.455,139,3.455,140,3.019]],["t/991",[19,3.513,23,3.075,99,3.513]],["t/1033",[59,2.09,71,2.508,93,2.798,141,4.387]],["t/1049",[89,2.94,94,2.94,134,3.249,142,3.719,143,3.719,144,3.719]],["t/1066",[2,1.647,10,1.442,59,2.152,71,1.73,83,2.055,93,1.93,133,2.645,145,2.645]],["t/1088",[11,2.518,30,2.204,55,2.732,146,3.455,147,3.455,148,3.455,149,3.455]],["t/1140",[10,1.917,59,1.917,71,2.301,81,3.183,150,4.025]],["t/1158",[2,2.387,13,1.276,99,3.197,151,4.387]],["t/1178",[2,1.756,13,0.938,59,1.537,130,2.82,152,3.227,153,3.227,154,3.227,155,3.227]],["t/1205",[82,3.223,116,4.23]],["t/1221",[13,1.276,114,3.834,156,4.387,157,3.469]],["t/1239",[13,1.17,18,1.77,145,3.517,158,4.025,159,4.025]],["t/1261",[13,1.402,90,3.274,160,4.821]],["t/1282",[5,1.476,6,1.476,13,0.938,18,1.419,90,2.191,161,3.227,162,3.227,163,3.227]],["t/1310",[13,1.276,157,3.469,164,4.387,165,4.387]],["t/1333",[13,1.402,157,3.812,166,4.821]],["t/1356",[13,1.402,18,2.12,167,4.821]],["t/1380",[52,2.019,55,1.827,81,1.827,82,1.392,86,2.019,113,2.019,140,2.019,168,2.31,169,2.31,170,2.31,171,2.31,172,2.31,173,2.31,174,2.31]]],"invertedIndex":[["",{"_index":29,"t":{"390":{"position":[[75,1]]}}}],["access",{"_index":71,"t":{"541":{"position":[[37,6]]},"685":{"position":[[26,6]]},"702":{"position":[[16,6]]},"836":{"position":[[16,6]]},"943":{"position":[[50,6]]},"1033":{"position":[[16,6]]},"1066":{"position":[[16,6]]},"1140":{"position":[[30,9]]}}}],["action",{"_index":57,"t":{"503":{"position":[[47,6]]},"517":{"position":[[61,6]]},"903":{"position":[[87,7]]}}}],["ad",{"_index":134,"t":{"943":{"position":[[0,6]]},"1049":{"position":[[43,6]]}}}],["address",{"_index":172,"t":{"1380":{"position":[[98,8]]}}}],["advanc",{"_index":103,"t":{"745":{"position":[[0,8]]}}}],["advantag",{"_index":45,"t":{"460":{"position":[[18,9]]}}}],["affect",{"_index":132,"t":{"921":{"position":[[87,6]]}}}],["allow",{"_index":128,"t":{"903":{"position":[[61,8]]}}}],["anoth",{"_index":133,"t":{"921":{"position":[[118,7]]},"1066":{"position":[[74,7]]}}}],["api",{"_index":11,"t":{"203":{"position":[[11,3]]},"634":{"position":[[47,4]]},"658":{"position":[[74,3]]},"1088":{"position":[[66,4]]}}}],["archiv",{"_index":0,"t":{"1":{"position":[[0,7]]}}}],["author",{"_index":18,"t":{"247":{"position":[[16,13]]},"414":{"position":[[99,13]]},"434":{"position":[[12,13]]},"460":{"position":[[59,13]]},"503":{"position":[[22,10]]},"517":{"position":[[27,10]]},"658":{"position":[[25,13]]},"743":{"position":[[71,13]]},"745":{"position":[[36,13]]},"768":{"position":[[55,13]]},"903":{"position":[[39,14]]},"1239":{"position":[[9,13]]},"1282":{"position":[[22,13]]},"1356":{"position":[[9,13]]}}}],["basic",{"_index":156,"t":{"1221":{"position":[[9,5]]}}}],["befor",{"_index":127,"t":{"903":{"position":[[54,6]]}}}],["best",{"_index":63,"t":{"529":{"position":[[0,4]]},"634":{"position":[[0,4]]}}}],["between",{"_index":130,"t":{"921":{"position":[[23,7]]},"1178":{"position":[[23,7]]}}}],["block",{"_index":109,"t":{"768":{"position":[[45,6]]}}}],["blog",{"_index":22,"t":{"277":{"position":[[0,4]]}}}],["both",{"_index":123,"t":{"852":{"position":[[162,5]]}}}],["build",{"_index":34,"t":{"414":{"position":[[62,5]]},"768":{"position":[[36,8]]}}}],["built",{"_index":70,"t":{"541":{"position":[[28,5]]}}}],["camera",{"_index":163,"t":{"1282":{"position":[[56,6]]}}}],["case",{"_index":104,"t":{"745":{"position":[[13,5]]}}}],["certain",{"_index":81,"t":{"642":{"position":[[27,7]]},"1140":{"position":[[11,7]]},"1380":{"position":[[35,7]]}}}],["chang",{"_index":96,"t":{"717":{"position":[[14,7]]},"812":{"position":[[32,8]]},"852":{"position":[[181,8]]}}}],["check",{"_index":55,"t":{"503":{"position":[[0,8]]},"1088":{"position":[[30,6]]},"1380":{"position":[[0,8]]}}}],["claim",{"_index":139,"t":{"981":{"position":[[21,6]]}}}],["cli",{"_index":31,"t":{"392":{"position":[[12,3]]}}}],["client",{"_index":40,"t":{"446":{"position":[[26,6]]},"475":{"position":[[15,6]]},"626":{"position":[[26,6]]}}}],["collect",{"_index":41,"t":{"446":{"position":[[36,7]]}}}],["commun",{"_index":21,"t":{"262":{"position":[[37,9]]}}}],["concentr",{"_index":110,"t":{"770":{"position":[[19,10]]}}}],["concept",{"_index":99,"t":{"743":{"position":[[25,8]]},"770":{"position":[[9,9]]},"991":{"position":[[19,8]]},"1158":{"position":[[9,9]]}}}],["condit",{"_index":1,"t":{"3":{"position":[[0,11]]},"797":{"position":[[28,10]]}}}],["configur",{"_index":32,"t":{"414":{"position":[[23,13]]},"434":{"position":[[0,11]]},"446":{"position":[[7,9]]},"560":{"position":[[0,11]]}}}],["consist",{"_index":15,"t":{"237":{"position":[[6,11]]},"660":{"position":[[6,11]]}}}],["context",{"_index":159,"t":{"1239":{"position":[[44,7]]}}}],["contextu",{"_index":140,"t":{"981":{"position":[[38,10]]},"1380":{"position":[[54,10]]}}}],["control",{"_index":72,"t":{"541":{"position":[[44,7]]}}}],["creat",{"_index":38,"t":{"442":{"position":[[0,8]]}}}],["custom",{"_index":112,"t":{"812":{"position":[[9,6]]}}}],["data",{"_index":86,"t":{"658":{"position":[[47,4]]},"1380":{"position":[[65,4]]}}}],["databas",{"_index":120,"t":{"852":{"position":[[85,8]]}}}],["defin",{"_index":102,"t":{"743":{"position":[[61,6]]},"981":{"position":[[31,6]]}}}],["delet",{"_index":92,"t":{"671":{"position":[[37,8]]}}}],["depend",{"_index":168,"t":{"1380":{"position":[[24,7]]}}}],["direct",{"_index":151,"t":{"1158":{"position":[[19,6]]}}}],["do",{"_index":124,"t":{"852":{"position":[[190,5]]}}}],["docker",{"_index":77,"t":{"598":{"position":[[34,6]]}}}],["document",{"_index":155,"t":{"1178":{"position":[[64,9]]}}}],["downtim",{"_index":122,"t":{"852":{"position":[[149,8],[209,8]]}}}],["drive",{"_index":165,"t":{"1310":{"position":[[16,5]]}}}],["dynam",{"_index":113,"t":{"812":{"position":[[20,11]]},"1380":{"position":[[43,7]]}}}],["e.g",{"_index":152,"t":{"1178":{"position":[[39,5]]}}}],["enabl",{"_index":68,"t":{"541":{"position":[[7,6]]}}}],["engag",{"_index":20,"t":{"262":{"position":[[13,6]]}}}],["entitl",{"_index":160,"t":{"1261":{"position":[[9,12]]}}}],["environ",{"_index":67,"t":{"529":{"position":[[50,11]]}}}],["exampl",{"_index":100,"t":{"743":{"position":[[38,8]]}}}],["expand",{"_index":148,"t":{"1088":{"position":[[43,7]]}}}],["experiment",{"_index":74,"t":{"541":{"position":[[67,14]]}}}],["fastifi",{"_index":53,"t":{"489":{"position":[[44,7]]}}}],["fga",{"_index":23,"t":{"382":{"position":[[16,3]]},"392":{"position":[[8,3]]},"414":{"position":[[19,3]]},"489":{"position":[[12,3]]},"729":{"position":[[12,3]]},"991":{"position":[[15,3]]}}}],["fiber",{"_index":54,"t":{"489":{"position":[[55,5]]}}}],["fine",{"_index":5,"t":{"13":{"position":[[0,4]]},"37":{"position":[[0,4]]},"63":{"position":[[0,4]]},"81":{"position":[[0,4]]},"97":{"position":[[0,4]]},"111":{"position":[[0,4]]},"125":{"position":[[0,4]]},"143":{"position":[[0,4]]},"157":{"position":[[0,4]]},"173":{"position":[[0,4]]},"189":{"position":[[0,4]]},"209":{"position":[[0,4]]},"1282":{"position":[[9,4]]}}}],["focu",{"_index":115,"t":{"850":{"position":[[29,5]]}}}],["folder",{"_index":153,"t":{"1178":{"position":[[45,6]]}}}],["follow",{"_index":24,"t":{"390":{"position":[[4,9]]}}}],["framework",{"_index":51,"t":{"489":{"position":[[25,10]]}}}],["get",{"_index":95,"t":{"717":{"position":[[0,7]]}}}],["github",{"_index":166,"t":{"1333":{"position":[[9,6]]}}}],["given",{"_index":61,"t":{"517":{"position":[[74,5]]}}}],["googl",{"_index":164,"t":{"1310":{"position":[[9,6]]}}}],["grain",{"_index":6,"t":{"13":{"position":[[5,7]]},"37":{"position":[[5,7]]},"63":{"position":[[5,7]]},"81":{"position":[[5,7]]},"97":{"position":[[5,7]]},"111":{"position":[[5,7]]},"125":{"position":[[5,7]]},"143":{"position":[[5,7]]},"157":{"position":[[5,7]]},"173":{"position":[[5,7]]},"189":{"position":[[5,7]]},"209":{"position":[[5,7]]},"1282":{"position":[[14,7]]}}}],["grant",{"_index":93,"t":{"685":{"position":[[0,8]]},"702":{"position":[[0,8]]},"836":{"position":[[0,8]]},"943":{"position":[[27,8]]},"1033":{"position":[[0,8]]},"1066":{"position":[[0,8]]}}}],["group",{"_index":94,"t":{"685":{"position":[[11,5]]},"943":{"position":[[16,6],[36,5]]},"1049":{"position":[[34,5]]}}}],["guid",{"_index":27,"t":{"390":{"position":[[42,5]]},"743":{"position":[[17,7]]},"768":{"position":[[17,6]]},"850":{"position":[[17,6]]}}}],["harder",{"_index":125,"t":{"852":{"position":[[221,7]]}}}],["help",{"_index":101,"t":{"743":{"position":[[52,4]]}}}],["ident",{"_index":137,"t":{"981":{"position":[[6,8]]}}}],["immut",{"_index":46,"t":{"460":{"position":[[35,9]]}}}],["indic",{"_index":129,"t":{"921":{"position":[[0,8]]}}}],["instal",{"_index":48,"t":{"475":{"position":[[0,10]]}}}],["integr",{"_index":49,"t":{"489":{"position":[[0,11]]},"729":{"position":[[0,11]]}}}],["interact",{"_index":87,"t":{"658":{"position":[[56,8]]}}}],["introduct",{"_index":17,"t":{"247":{"position":[[0,12]]},"382":{"position":[[0,12]]},"860":{"position":[[3,12]]}}}],["invok",{"_index":80,"t":{"634":{"position":[[38,8]]}}}],["iot",{"_index":161,"t":{"1282":{"position":[[43,3]]}}}],["ip",{"_index":171,"t":{"1380":{"position":[[95,2]]}}}],["kubecon",{"_index":8,"t":{"187":{"position":[[11,7]]}}}],["kubernet",{"_index":78,"t":{"616":{"position":[[34,10]]}}}],["languag",{"_index":33,"t":{"414":{"position":[[37,8]]}}}],["learn",{"_index":19,"t":{"262":{"position":[[0,5]]},"414":{"position":[[0,8]]},"460":{"position":[[0,5]]},"991":{"position":[[0,8]]}}}],["list",{"_index":9,"t":{"203":{"position":[[0,4]]},"517":{"position":[[0,4]]},"642":{"position":[[0,4]]}}}],["listobject",{"_index":149,"t":{"1088":{"position":[[55,10]]}}}],["locat",{"_index":170,"t":{"1380":{"position":[[85,9]]}}}],["manag",{"_index":79,"t":{"634":{"position":[[18,8]]}}}],["member",{"_index":135,"t":{"943":{"position":[[42,7]]}}}],["membership",{"_index":143,"t":{"1049":{"position":[[18,10]]}}}],["migrat",{"_index":116,"t":{"850":{"position":[[38,9]]},"852":{"position":[[23,10],[94,11],[122,10]]},"1205":{"position":[[0,9]]}}}],["mode",{"_index":88,"t":{"660":{"position":[[18,5]]}}}],["model",{"_index":13,"t":{"229":{"position":[[8,6]]},"414":{"position":[[113,5]]},"434":{"position":[[26,5]]},"460":{"position":[[73,6]]},"743":{"position":[[85,6]]},"745":{"position":[[50,8]]},"768":{"position":[[69,6]]},"770":{"position":[[0,8]]},"786":{"position":[[0,8]]},"797":{"position":[[0,8]]},"812":{"position":[[0,8]]},"850":{"position":[[48,6]]},"852":{"position":[[17,5]]},"860":{"position":[[19,8]]},"880":{"position":[[8,6]]},"903":{"position":[[0,8]]},"963":{"position":[[8,6]]},"1158":{"position":[[0,8]]},"1178":{"position":[[0,8]]},"1221":{"position":[[0,8]]},"1239":{"position":[[0,8]]},"1261":{"position":[[0,8]]},"1282":{"position":[[0,8]]},"1310":{"position":[[0,8]]},"1333":{"position":[[0,8]]},"1356":{"position":[[0,8]]}}}],["modular",{"_index":12,"t":{"229":{"position":[[0,7]]},"880":{"position":[[0,7]]}}}],["multipl",{"_index":106,"t":{"751":{"position":[[9,8]]},"903":{"position":[[30,8]]}}}],["new",{"_index":7,"t":{"13":{"position":[[13,4]]},"37":{"position":[[13,4]]},"63":{"position":[[13,4]]},"81":{"position":[[13,4]]},"97":{"position":[[13,4]]},"111":{"position":[[13,4]]},"125":{"position":[[13,4]]},"143":{"position":[[13,4]]},"157":{"position":[[13,4]]},"173":{"position":[[13,4]]},"189":{"position":[[13,4]]},"209":{"position":[[13,4]]}}}],["object",{"_index":59,"t":{"517":{"position":[[9,7]]},"642":{"position":[[62,6]]},"685":{"position":[[49,6]]},"702":{"position":[[39,6]]},"836":{"position":[[29,6]]},"903":{"position":[[109,7]]},"921":{"position":[[31,8],[76,6]]},"943":{"position":[[63,6]]},"1033":{"position":[[29,6]]},"1066":{"position":[[39,6],[82,6]]},"1140":{"position":[[40,7]]},"1178":{"position":[[31,7]]}}}],["on",{"_index":131,"t":{"921":{"position":[[72,3]]}}}],["openfga",{"_index":4,"t":{"3":{"position":[[36,7]]},"187":{"position":[[0,7]]},"237":{"position":[[29,7]]},"262":{"position":[[29,7]]},"529":{"position":[[26,7]]},"541":{"position":[[52,7]]},"560":{"position":[[15,7]]},"598":{"position":[[14,7]]},"616":{"position":[[14,7]]},"618":{"position":[[14,7]]},"620":{"position":[[14,7]]},"626":{"position":[[14,7]]}}}],["opentelemetri",{"_index":43,"t":{"446":{"position":[[60,14]]}}}],["option",{"_index":16,"t":{"237":{"position":[[18,7]]}}}],["organ",{"_index":158,"t":{"1239":{"position":[[31,12]]}}}],["overview",{"_index":146,"t":{"1088":{"position":[[3,8]]}}}],["parent",{"_index":154,"t":{"1178":{"position":[[52,6]]}}}],["particular",{"_index":83,"t":{"642":{"position":[[51,10]]},"685":{"position":[[38,10]]},"702":{"position":[[28,10]]},"903":{"position":[[98,10]]},"1066":{"position":[[28,10]]}}}],["pattern",{"_index":105,"t":{"745":{"position":[[23,8]]}}}],["perform",{"_index":56,"t":{"503":{"position":[[36,7]]},"517":{"position":[[41,7]]},"852":{"position":[[114,7]]},"903":{"position":[[79,7]]}}}],["permiss",{"_index":157,"t":{"1221":{"position":[[25,11]]},"1310":{"position":[[22,11]]},"1333":{"position":[[16,11]]}}}],["practic",{"_index":64,"t":{"529":{"position":[[5,9]]},"634":{"position":[[5,9]]}}}],["prevent",{"_index":150,"t":{"1140":{"position":[[0,10]]}}}],["product",{"_index":66,"t":{"529":{"position":[[39,10]]}}}],["programmat",{"_index":84,"t":{"658":{"position":[[0,16]]}}}],["properti",{"_index":47,"t":{"460":{"position":[[45,10]]}}}],["provid",{"_index":25,"t":{"390":{"position":[[19,7]]}}}],["public",{"_index":141,"t":{"1033":{"position":[[9,6]]}}}],["queri",{"_index":14,"t":{"237":{"position":[[0,5]]},"660":{"position":[[0,5]]}}}],["read",{"_index":147,"t":{"1088":{"position":[[37,5]]}}}],["relat",{"_index":82,"t":{"642":{"position":[[35,8]]},"658":{"position":[[39,7]]},"850":{"position":[[59,10]]},"852":{"position":[[74,10]]},"981":{"position":[[49,9]]},"1205":{"position":[[10,9]]},"1380":{"position":[[9,9]]}}}],["relationship",{"_index":2,"t":{"3":{"position":[[12,12]]},"671":{"position":[[46,12]]},"751":{"position":[[18,12]]},"770":{"position":[[30,13]]},"797":{"position":[[9,13]]},"921":{"position":[[9,13],[55,13],[100,12]]},"1066":{"position":[[56,12]]},"1158":{"position":[[26,13]]},"1178":{"position":[[9,13]]}}}],["remov",{"_index":144,"t":{"1049":{"position":[[54,8]]}}}],["represent",{"_index":35,"t":{"414":{"position":[[70,14]]}}}],["requir",{"_index":126,"t":{"903":{"position":[[21,8]]}}}],["resourc",{"_index":58,"t":{"503":{"position":[[59,8]]},"517":{"position":[[80,8]]}}}],["role",{"_index":114,"t":{"812":{"position":[[41,5]]},"1221":{"position":[[15,5]]}}}],["run",{"_index":65,"t":{"529":{"position":[[18,7]]}}}],["same",{"_index":118,"t":{"852":{"position":[[46,4]]}}}],["sdk",{"_index":39,"t":{"446":{"position":[[22,3]]},"475":{"position":[[11,3]]},"626":{"position":[[22,3]]}}}],["search",{"_index":97,"t":{"729":{"position":[[26,6]]}}}],["section",{"_index":98,"t":{"743":{"position":[[5,7]]},"768":{"position":[[5,7]]},"850":{"position":[[5,7]]}}}],["secur",{"_index":162,"t":{"1282":{"position":[[47,8]]}}}],["server",{"_index":73,"t":{"541":{"position":[[60,6]]},"560":{"position":[[23,6]]},"598":{"position":[[22,6]]},"616":{"position":[[22,6]]},"618":{"position":[[22,6]]},"620":{"position":[[22,6]]}}}],["set",{"_index":75,"t":{"598":{"position":[[0,7]]},"616":{"position":[[0,7]]},"618":{"position":[[0,7]]},"620":{"position":[[0,7]]},"626":{"position":[[0,7]]}}}],["setup",{"_index":69,"t":{"541":{"position":[[18,5]]}}}],["singl",{"_index":107,"t":{"751":{"position":[[43,6]]}}}],["slack",{"_index":167,"t":{"1356":{"position":[[27,5]]}}}],["specifi",{"_index":60,"t":{"517":{"position":[[51,9]]}}}],["start",{"_index":28,"t":{"390":{"position":[[62,7]]}}}],["state",{"_index":91,"t":{"671":{"position":[[16,5]]}}}],["step",{"_index":26,"t":{"390":{"position":[[29,4],[37,4]]}}}],["store",{"_index":37,"t":{"434":{"position":[[38,5]]},"442":{"position":[[11,5]]}}}],["such",{"_index":52,"t":{"489":{"position":[[36,4]]},"1380":{"position":[[70,5]]}}}],["system",{"_index":90,"t":{"671":{"position":[[9,6]]},"812":{"position":[[55,6]]},"903":{"position":[[9,6]]},"1261":{"position":[[28,6]]},"1282":{"position":[[63,6]]}}}],["system'",{"_index":36,"t":{"414":{"position":[[90,8]]}}}],["take",{"_index":44,"t":{"460":{"position":[[13,4]]}}}],["telemetri",{"_index":42,"t":{"446":{"position":[[44,9]]}}}],["test",{"_index":136,"t":{"963":{"position":[[0,7]]}}}],["think",{"_index":117,"t":{"852":{"position":[[8,5],[62,5]]}}}],["through",{"_index":145,"t":{"1066":{"position":[[46,7]]},"1239":{"position":[[23,7]]}}}],["time",{"_index":169,"t":{"1380":{"position":[[79,5]]}}}],["token",{"_index":138,"t":{"981":{"position":[[15,5]]}}}],["transact",{"_index":108,"t":{"751":{"position":[[50,11]]}}}],["tupl",{"_index":3,"t":{"3":{"position":[[25,6]]},"634":{"position":[[27,6]]},"671":{"position":[[59,6]]},"717":{"position":[[8,5]]},"751":{"position":[[31,6]]}}}],["type",{"_index":62,"t":{"517":{"position":[[89,4]]}}}],["up",{"_index":76,"t":{"598":{"position":[[8,2]]},"616":{"position":[[8,2]]},"618":{"position":[[8,2]]},"620":{"position":[[8,2]]},"626":{"position":[[8,2]]}}}],["updat",{"_index":89,"t":{"671":{"position":[[0,8]]},"751":{"position":[[0,8]]},"1049":{"position":[[0,8]]}}}],["us",{"_index":30,"t":{"392":{"position":[[0,3]]},"414":{"position":[[50,5]]},"446":{"position":[[54,5]]},"745":{"position":[[9,3]]},"981":{"position":[[0,5]]},"1088":{"position":[[22,3]]}}}],["user",{"_index":10,"t":{"203":{"position":[[5,5]]},"503":{"position":[[14,4]]},"517":{"position":[[19,4]]},"642":{"position":[[9,5]]},"685":{"position":[[20,5]]},"702":{"position":[[11,4]]},"836":{"position":[[11,4]]},"903":{"position":[[70,5]]},"921":{"position":[[48,6]]},"943":{"position":[[7,5]]},"1066":{"position":[[11,4]]},"1140":{"position":[[19,5]]}}}],["user'",{"_index":142,"t":{"1049":{"position":[[11,6]]}}}],["userset",{"_index":111,"t":{"786":{"position":[[14,7]]}}}],["way",{"_index":119,"t":{"852":{"position":[[51,3]]}}}],["weather",{"_index":173,"t":{"1380":{"position":[[107,8]]}}}],["within",{"_index":50,"t":{"489":{"position":[[16,6]]}}}],["without",{"_index":121,"t":{"852":{"position":[[141,7],[201,7]]}}}],["write",{"_index":85,"t":{"658":{"position":[[17,7]]},"671":{"position":[[25,7]]}}}],["written",{"_index":174,"t":{"1380":{"position":[[135,7]]}}}]],"pipeline":["stemmer"]}},{"documents":[{"i":1,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"","u":"/pr-preview/pr-921/blog/archive","p":1},{"i":2,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"","u":"/pr-preview/pr-921/blog/authors","p":2},{"i":3,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Conditional Relationship Tuples for OpenFGA","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","p":3},{"i":13,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - December 2023","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","p":13},{"i":37,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - January 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","p":37},{"i":63,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - February 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","p":63},{"i":81,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - March 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","p":81},{"i":97,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - April 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","p":97},{"i":111,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - May 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","p":111},{"i":125,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - July 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","p":125},{"i":143,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - September 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","p":143},{"i":157,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - June 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","p":157},{"i":173,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - October 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","p":173},{"i":187,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Join the OpenFGA team at KubeCon NA 2023","u":"/pr-preview/pr-921/blog/kubecon-na-2023","p":187},{"i":189,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - November 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","p":189},{"i":203,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"List Users API","u":"/pr-preview/pr-921/blog/list-users-announcement","p":203},{"i":209,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Fine Grained News - August 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","p":209},{"i":229,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modular Models","u":"/pr-preview/pr-921/blog/modular-models-announcement","p":229},{"i":237,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Query Consistency Options in OpenFGA","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","p":237},{"i":247,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Authorization Concepts","u":"/pr-preview/pr-921/docs/authorization-concepts","p":247},{"i":262,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"OpenFGA Community","u":"/pr-preview/pr-921/docs/community","p":262},{"i":277,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"","u":"/pr-preview/pr-921/blog/page/2","p":277},{"i":382,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Introduction to OpenFGA","u":"/pr-preview/pr-921/docs/fga","p":382},{"i":390,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Content","u":"/pr-preview/pr-921/docs/getting-started","p":390},{"i":392,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Use the FGA CLI","u":"/pr-preview/pr-921/docs/getting-started/cli","p":392},{"i":414,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Configuration Language","u":"/pr-preview/pr-921/docs/configuration-language","p":414},{"i":434,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Configure Authorization Model for a Store","u":"/pr-preview/pr-921/docs/getting-started/configure-model","p":434},{"i":442,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Create a Store","u":"/pr-preview/pr-921/docs/getting-started/create-store","p":442},{"i":446,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Configure SDK Client Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","p":446},{"i":460,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Immutable Authorization Models","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","p":460},{"i":475,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Install SDK Client","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","p":475},{"i":489,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Integrate Within a Framework","u":"/pr-preview/pr-921/docs/getting-started/framework","p":489},{"i":503,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Perform a Check","u":"/pr-preview/pr-921/docs/getting-started/perform-check","p":503},{"i":517,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Perform a list objects call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","p":517},{"i":529,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Running OpenFGA in Production","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","p":529},{"i":541,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"🛡️Setup Access Control","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","p":541},{"i":560,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Configuring OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","p":560},{"i":598,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"🐳 Setup OpenFGA with Docker","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","p":598},{"i":616,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"☸️ Setup OpenFGA with Kubernetes","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/kubernetes","p":616},{"i":618,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Setup OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/overview","p":618},{"i":620,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Using the OpenFGA Playground","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/playground","p":620},{"i":626,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Setup SDK Client for Store","u":"/pr-preview/pr-921/docs/getting-started/setup-sdk-client","p":626},{"i":634,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Best Practices of Managing Tuples and Invoking APIs","u":"/pr-preview/pr-921/docs/getting-started/tuples-api-best-practices","p":634},{"i":642,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Perform a List Users call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-users","p":642},{"i":658,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Content","u":"/pr-preview/pr-921/docs/interacting","p":658},{"i":660,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Query Consistency Modes","u":"/pr-preview/pr-921/docs/interacting/consistency","p":660},{"i":671,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Update Relationship Tuples","u":"/pr-preview/pr-921/docs/getting-started/update-tuples","p":671},{"i":685,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Managing Group Access","u":"/pr-preview/pr-921/docs/interacting/managing-group-access","p":685},{"i":702,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Managing User Access","u":"/pr-preview/pr-921/docs/interacting/managing-user-access","p":702},{"i":717,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"How to get tuple changes","u":"/pr-preview/pr-921/docs/interacting/read-tuple-changes","p":717},{"i":729,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Search With Permissions","u":"/pr-preview/pr-921/docs/interacting/search-with-permissions","p":729},{"i":743,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Content","u":"/pr-preview/pr-921/docs/modeling","p":743},{"i":745,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Advanced Use-Cases","u":"/pr-preview/pr-921/docs/modeling/advanced","p":745},{"i":751,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Transactional Writes","u":"/pr-preview/pr-921/docs/interacting/transactional-writes","p":751},{"i":768,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Content","u":"/pr-preview/pr-921/docs/modeling/building-blocks","p":768},{"i":770,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Concentric Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/concentric-relationships","p":770},{"i":786,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Usersets","u":"/pr-preview/pr-921/docs/modeling/building-blocks/usersets","p":786},{"i":797,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Conditions","u":"/pr-preview/pr-921/docs/modeling/conditions","p":797},{"i":812,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Custom Roles","u":"/pr-preview/pr-921/docs/modeling/custom-roles","p":812},{"i":836,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Direct Access","u":"/pr-preview/pr-921/docs/modeling/direct-access","p":836},{"i":850,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Content","u":"/pr-preview/pr-921/docs/modeling/migrating","p":850},{"i":852,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Model Migrations","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-models","p":852},{"i":860,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Get Started with Modeling","u":"/pr-preview/pr-921/docs/modeling/getting-started","p":860},{"i":880,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modular Models","u":"/pr-preview/pr-921/docs/modeling/modular-models","p":880},{"i":903,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Multiple Restrictions","u":"/pr-preview/pr-921/docs/modeling/multiple-restrictions","p":903},{"i":921,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Parent-Child Objects","u":"/pr-preview/pr-921/docs/modeling/parent-child","p":921},{"i":943,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"User Groups","u":"/pr-preview/pr-921/docs/modeling/user-groups","p":943},{"i":963,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Testing Models","u":"/pr-preview/pr-921/docs/modeling/testing","p":963},{"i":981,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Use Token Claims As Contextual Tuples","u":"/pr-preview/pr-921/docs/modeling/token-claims-contextual-tuples","p":981},{"i":991,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Concepts","u":"/pr-preview/pr-921/docs/concepts","p":991},{"i":1033,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Public Access","u":"/pr-preview/pr-921/docs/modeling/public-access","p":1033},{"i":1049,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Managing Group Membership","u":"/pr-preview/pr-921/docs/interacting/managing-group-membership","p":1049},{"i":1066,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Managing Relationships Between Objects","u":"/pr-preview/pr-921/docs/interacting/managing-relationships-between-objects","p":1066},{"i":1088,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Relationship Queries: Check, Read, Expand, ListObjects and ListUsers","u":"/pr-preview/pr-921/docs/interacting/relationship-queries","p":1088},{"i":1140,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Blocklists","u":"/pr-preview/pr-921/docs/modeling/blocklists","p":1140},{"i":1158,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Direct Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/direct-relationships","p":1158},{"i":1178,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Object to Object Relationships","u":"/pr-preview/pr-921/docs/modeling/building-blocks/object-to-object-relationships","p":1178},{"i":1205,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Migrating Relations","u":"/pr-preview/pr-921/docs/modeling/migrating/migrating-relations","p":1205},{"i":1221,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Roles and Permissions","u":"/pr-preview/pr-921/docs/modeling/roles-and-permissions","p":1221},{"i":1239,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Authorization Through Organization Context","u":"/pr-preview/pr-921/docs/modeling/organization-context-authorization","p":1239},{"i":1261,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modeling Entitlements for a System with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/entitlements","p":1261},{"i":1282,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modeling Authorization for an IoT Security System with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/iot","p":1282},{"i":1310,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modeling Google Drive permissions with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/gdrive","p":1310},{"i":1333,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modeling GitHub permissions with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/github","p":1333},{"i":1356,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Modeling Authorization for Slack with OpenFGA","u":"/pr-preview/pr-921/docs/modeling/advanced/slack","p":1356},{"i":1380,"t":"OpenFGA, open source, fine-grained-authorization, fine grained authorization, Zanzibar","s":"Contextual and Time-Based Authorization","u":"/pr-preview/pr-921/docs/modeling/contextual-time-based-authorization","p":1380}],"index":{"version":"2.3.9","fields":["t"],"fieldVectors":[["t/1",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/2",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/3",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/13",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/37",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/63",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/81",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/97",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/111",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/125",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/143",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/157",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/173",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/187",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/189",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/203",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/209",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/229",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/237",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/247",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/262",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/277",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/382",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/390",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/392",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/414",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/434",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/442",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/446",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/460",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/475",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/489",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/503",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/517",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/529",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/541",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/560",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/598",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/616",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/618",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/620",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/626",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/634",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/642",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/658",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/660",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/671",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/685",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/702",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/717",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/729",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/743",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/745",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/751",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/768",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/770",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/786",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/797",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/812",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/836",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/850",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/852",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/860",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/880",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/903",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/921",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/943",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/963",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/981",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/991",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1033",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1049",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1066",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1088",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1140",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1158",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1178",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1205",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1221",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1239",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1261",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1282",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1310",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1333",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1356",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]],["t/1380",[0,0.006,1,0.006,2,0.006,3,0.008,4,0.008,5,0.008,6,0.006]]],"invertedIndex":[["author",{"_index":5,"t":{"1":{"position":[[35,14],[63,14]]},"2":{"position":[[35,14],[63,14]]},"3":{"position":[[35,14],[63,14]]},"13":{"position":[[35,14],[63,14]]},"37":{"position":[[35,14],[63,14]]},"63":{"position":[[35,14],[63,14]]},"81":{"position":[[35,14],[63,14]]},"97":{"position":[[35,14],[63,14]]},"111":{"position":[[35,14],[63,14]]},"125":{"position":[[35,14],[63,14]]},"143":{"position":[[35,14],[63,14]]},"157":{"position":[[35,14],[63,14]]},"173":{"position":[[35,14],[63,14]]},"187":{"position":[[35,14],[63,14]]},"189":{"position":[[35,14],[63,14]]},"203":{"position":[[35,14],[63,14]]},"209":{"position":[[35,14],[63,14]]},"229":{"position":[[35,14],[63,14]]},"237":{"position":[[35,14],[63,14]]},"247":{"position":[[35,14],[63,14]]},"262":{"position":[[35,14],[63,14]]},"277":{"position":[[35,14],[63,14]]},"382":{"position":[[35,14],[63,14]]},"390":{"position":[[35,14],[63,14]]},"392":{"position":[[35,14],[63,14]]},"414":{"position":[[35,14],[63,14]]},"434":{"position":[[35,14],[63,14]]},"442":{"position":[[35,14],[63,14]]},"446":{"position":[[35,14],[63,14]]},"460":{"position":[[35,14],[63,14]]},"475":{"position":[[35,14],[63,14]]},"489":{"position":[[35,14],[63,14]]},"503":{"position":[[35,14],[63,14]]},"517":{"position":[[35,14],[63,14]]},"529":{"position":[[35,14],[63,14]]},"541":{"position":[[35,14],[63,14]]},"560":{"position":[[35,14],[63,14]]},"598":{"position":[[35,14],[63,14]]},"616":{"position":[[35,14],[63,14]]},"618":{"position":[[35,14],[63,14]]},"620":{"position":[[35,14],[63,14]]},"626":{"position":[[35,14],[63,14]]},"634":{"position":[[35,14],[63,14]]},"642":{"position":[[35,14],[63,14]]},"658":{"position":[[35,14],[63,14]]},"660":{"position":[[35,14],[63,14]]},"671":{"position":[[35,14],[63,14]]},"685":{"position":[[35,14],[63,14]]},"702":{"position":[[35,14],[63,14]]},"717":{"position":[[35,14],[63,14]]},"729":{"position":[[35,14],[63,14]]},"743":{"position":[[35,14],[63,14]]},"745":{"position":[[35,14],[63,14]]},"751":{"position":[[35,14],[63,14]]},"768":{"position":[[35,14],[63,14]]},"770":{"position":[[35,14],[63,14]]},"786":{"position":[[35,14],[63,14]]},"797":{"position":[[35,14],[63,14]]},"812":{"position":[[35,14],[63,14]]},"836":{"position":[[35,14],[63,14]]},"850":{"position":[[35,14],[63,14]]},"852":{"position":[[35,14],[63,14]]},"860":{"position":[[35,14],[63,14]]},"880":{"position":[[35,14],[63,14]]},"903":{"position":[[35,14],[63,14]]},"921":{"position":[[35,14],[63,14]]},"943":{"position":[[35,14],[63,14]]},"963":{"position":[[35,14],[63,14]]},"981":{"position":[[35,14],[63,14]]},"991":{"position":[[35,14],[63,14]]},"1033":{"position":[[35,14],[63,14]]},"1049":{"position":[[35,14],[63,14]]},"1066":{"position":[[35,14],[63,14]]},"1088":{"position":[[35,14],[63,14]]},"1140":{"position":[[35,14],[63,14]]},"1158":{"position":[[35,14],[63,14]]},"1178":{"position":[[35,14],[63,14]]},"1205":{"position":[[35,14],[63,14]]},"1221":{"position":[[35,14],[63,14]]},"1239":{"position":[[35,14],[63,14]]},"1261":{"position":[[35,14],[63,14]]},"1282":{"position":[[35,14],[63,14]]},"1310":{"position":[[35,14],[63,14]]},"1333":{"position":[[35,14],[63,14]]},"1356":{"position":[[35,14],[63,14]]},"1380":{"position":[[35,14],[63,14]]}}}],["fine",{"_index":3,"t":{"1":{"position":[[22,4],[50,4]]},"2":{"position":[[22,4],[50,4]]},"3":{"position":[[22,4],[50,4]]},"13":{"position":[[22,4],[50,4]]},"37":{"position":[[22,4],[50,4]]},"63":{"position":[[22,4],[50,4]]},"81":{"position":[[22,4],[50,4]]},"97":{"position":[[22,4],[50,4]]},"111":{"position":[[22,4],[50,4]]},"125":{"position":[[22,4],[50,4]]},"143":{"position":[[22,4],[50,4]]},"157":{"position":[[22,4],[50,4]]},"173":{"position":[[22,4],[50,4]]},"187":{"position":[[22,4],[50,4]]},"189":{"position":[[22,4],[50,4]]},"203":{"position":[[22,4],[50,4]]},"209":{"position":[[22,4],[50,4]]},"229":{"position":[[22,4],[50,4]]},"237":{"position":[[22,4],[50,4]]},"247":{"position":[[22,4],[50,4]]},"262":{"position":[[22,4],[50,4]]},"277":{"position":[[22,4],[50,4]]},"382":{"position":[[22,4],[50,4]]},"390":{"position":[[22,4],[50,4]]},"392":{"position":[[22,4],[50,4]]},"414":{"position":[[22,4],[50,4]]},"434":{"position":[[22,4],[50,4]]},"442":{"position":[[22,4],[50,4]]},"446":{"position":[[22,4],[50,4]]},"460":{"position":[[22,4],[50,4]]},"475":{"position":[[22,4],[50,4]]},"489":{"position":[[22,4],[50,4]]},"503":{"position":[[22,4],[50,4]]},"517":{"position":[[22,4],[50,4]]},"529":{"position":[[22,4],[50,4]]},"541":{"position":[[22,4],[50,4]]},"560":{"position":[[22,4],[50,4]]},"598":{"position":[[22,4],[50,4]]},"616":{"position":[[22,4],[50,4]]},"618":{"position":[[22,4],[50,4]]},"620":{"position":[[22,4],[50,4]]},"626":{"position":[[22,4],[50,4]]},"634":{"position":[[22,4],[50,4]]},"642":{"position":[[22,4],[50,4]]},"658":{"position":[[22,4],[50,4]]},"660":{"position":[[22,4],[50,4]]},"671":{"position":[[22,4],[50,4]]},"685":{"position":[[22,4],[50,4]]},"702":{"position":[[22,4],[50,4]]},"717":{"position":[[22,4],[50,4]]},"729":{"position":[[22,4],[50,4]]},"743":{"position":[[22,4],[50,4]]},"745":{"position":[[22,4],[50,4]]},"751":{"position":[[22,4],[50,4]]},"768":{"position":[[22,4],[50,4]]},"770":{"position":[[22,4],[50,4]]},"786":{"position":[[22,4],[50,4]]},"797":{"position":[[22,4],[50,4]]},"812":{"position":[[22,4],[50,4]]},"836":{"position":[[22,4],[50,4]]},"850":{"position":[[22,4],[50,4]]},"852":{"position":[[22,4],[50,4]]},"860":{"position":[[22,4],[50,4]]},"880":{"position":[[22,4],[50,4]]},"903":{"position":[[22,4],[50,4]]},"921":{"position":[[22,4],[50,4]]},"943":{"position":[[22,4],[50,4]]},"963":{"position":[[22,4],[50,4]]},"981":{"position":[[22,4],[50,4]]},"991":{"position":[[22,4],[50,4]]},"1033":{"position":[[22,4],[50,4]]},"1049":{"position":[[22,4],[50,4]]},"1066":{"position":[[22,4],[50,4]]},"1088":{"position":[[22,4],[50,4]]},"1140":{"position":[[22,4],[50,4]]},"1158":{"position":[[22,4],[50,4]]},"1178":{"position":[[22,4],[50,4]]},"1205":{"position":[[22,4],[50,4]]},"1221":{"position":[[22,4],[50,4]]},"1239":{"position":[[22,4],[50,4]]},"1261":{"position":[[22,4],[50,4]]},"1282":{"position":[[22,4],[50,4]]},"1310":{"position":[[22,4],[50,4]]},"1333":{"position":[[22,4],[50,4]]},"1356":{"position":[[22,4],[50,4]]},"1380":{"position":[[22,4],[50,4]]}}}],["grain",{"_index":4,"t":{"1":{"position":[[27,7],[55,7]]},"2":{"position":[[27,7],[55,7]]},"3":{"position":[[27,7],[55,7]]},"13":{"position":[[27,7],[55,7]]},"37":{"position":[[27,7],[55,7]]},"63":{"position":[[27,7],[55,7]]},"81":{"position":[[27,7],[55,7]]},"97":{"position":[[27,7],[55,7]]},"111":{"position":[[27,7],[55,7]]},"125":{"position":[[27,7],[55,7]]},"143":{"position":[[27,7],[55,7]]},"157":{"position":[[27,7],[55,7]]},"173":{"position":[[27,7],[55,7]]},"187":{"position":[[27,7],[55,7]]},"189":{"position":[[27,7],[55,7]]},"203":{"position":[[27,7],[55,7]]},"209":{"position":[[27,7],[55,7]]},"229":{"position":[[27,7],[55,7]]},"237":{"position":[[27,7],[55,7]]},"247":{"position":[[27,7],[55,7]]},"262":{"position":[[27,7],[55,7]]},"277":{"position":[[27,7],[55,7]]},"382":{"position":[[27,7],[55,7]]},"390":{"position":[[27,7],[55,7]]},"392":{"position":[[27,7],[55,7]]},"414":{"position":[[27,7],[55,7]]},"434":{"position":[[27,7],[55,7]]},"442":{"position":[[27,7],[55,7]]},"446":{"position":[[27,7],[55,7]]},"460":{"position":[[27,7],[55,7]]},"475":{"position":[[27,7],[55,7]]},"489":{"position":[[27,7],[55,7]]},"503":{"position":[[27,7],[55,7]]},"517":{"position":[[27,7],[55,7]]},"529":{"position":[[27,7],[55,7]]},"541":{"position":[[27,7],[55,7]]},"560":{"position":[[27,7],[55,7]]},"598":{"position":[[27,7],[55,7]]},"616":{"position":[[27,7],[55,7]]},"618":{"position":[[27,7],[55,7]]},"620":{"position":[[27,7],[55,7]]},"626":{"position":[[27,7],[55,7]]},"634":{"position":[[27,7],[55,7]]},"642":{"position":[[27,7],[55,7]]},"658":{"position":[[27,7],[55,7]]},"660":{"position":[[27,7],[55,7]]},"671":{"position":[[27,7],[55,7]]},"685":{"position":[[27,7],[55,7]]},"702":{"position":[[27,7],[55,7]]},"717":{"position":[[27,7],[55,7]]},"729":{"position":[[27,7],[55,7]]},"743":{"position":[[27,7],[55,7]]},"745":{"position":[[27,7],[55,7]]},"751":{"position":[[27,7],[55,7]]},"768":{"position":[[27,7],[55,7]]},"770":{"position":[[27,7],[55,7]]},"786":{"position":[[27,7],[55,7]]},"797":{"position":[[27,7],[55,7]]},"812":{"position":[[27,7],[55,7]]},"836":{"position":[[27,7],[55,7]]},"850":{"position":[[27,7],[55,7]]},"852":{"position":[[27,7],[55,7]]},"860":{"position":[[27,7],[55,7]]},"880":{"position":[[27,7],[55,7]]},"903":{"position":[[27,7],[55,7]]},"921":{"position":[[27,7],[55,7]]},"943":{"position":[[27,7],[55,7]]},"963":{"position":[[27,7],[55,7]]},"981":{"position":[[27,7],[55,7]]},"991":{"position":[[27,7],[55,7]]},"1033":{"position":[[27,7],[55,7]]},"1049":{"position":[[27,7],[55,7]]},"1066":{"position":[[27,7],[55,7]]},"1088":{"position":[[27,7],[55,7]]},"1140":{"position":[[27,7],[55,7]]},"1158":{"position":[[27,7],[55,7]]},"1178":{"position":[[27,7],[55,7]]},"1205":{"position":[[27,7],[55,7]]},"1221":{"position":[[27,7],[55,7]]},"1239":{"position":[[27,7],[55,7]]},"1261":{"position":[[27,7],[55,7]]},"1282":{"position":[[27,7],[55,7]]},"1310":{"position":[[27,7],[55,7]]},"1333":{"position":[[27,7],[55,7]]},"1356":{"position":[[27,7],[55,7]]},"1380":{"position":[[27,7],[55,7]]}}}],["open",{"_index":1,"t":{"1":{"position":[[9,4]]},"2":{"position":[[9,4]]},"3":{"position":[[9,4]]},"13":{"position":[[9,4]]},"37":{"position":[[9,4]]},"63":{"position":[[9,4]]},"81":{"position":[[9,4]]},"97":{"position":[[9,4]]},"111":{"position":[[9,4]]},"125":{"position":[[9,4]]},"143":{"position":[[9,4]]},"157":{"position":[[9,4]]},"173":{"position":[[9,4]]},"187":{"position":[[9,4]]},"189":{"position":[[9,4]]},"203":{"position":[[9,4]]},"209":{"position":[[9,4]]},"229":{"position":[[9,4]]},"237":{"position":[[9,4]]},"247":{"position":[[9,4]]},"262":{"position":[[9,4]]},"277":{"position":[[9,4]]},"382":{"position":[[9,4]]},"390":{"position":[[9,4]]},"392":{"position":[[9,4]]},"414":{"position":[[9,4]]},"434":{"position":[[9,4]]},"442":{"position":[[9,4]]},"446":{"position":[[9,4]]},"460":{"position":[[9,4]]},"475":{"position":[[9,4]]},"489":{"position":[[9,4]]},"503":{"position":[[9,4]]},"517":{"position":[[9,4]]},"529":{"position":[[9,4]]},"541":{"position":[[9,4]]},"560":{"position":[[9,4]]},"598":{"position":[[9,4]]},"616":{"position":[[9,4]]},"618":{"position":[[9,4]]},"620":{"position":[[9,4]]},"626":{"position":[[9,4]]},"634":{"position":[[9,4]]},"642":{"position":[[9,4]]},"658":{"position":[[9,4]]},"660":{"position":[[9,4]]},"671":{"position":[[9,4]]},"685":{"position":[[9,4]]},"702":{"position":[[9,4]]},"717":{"position":[[9,4]]},"729":{"position":[[9,4]]},"743":{"position":[[9,4]]},"745":{"position":[[9,4]]},"751":{"position":[[9,4]]},"768":{"position":[[9,4]]},"770":{"position":[[9,4]]},"786":{"position":[[9,4]]},"797":{"position":[[9,4]]},"812":{"position":[[9,4]]},"836":{"position":[[9,4]]},"850":{"position":[[9,4]]},"852":{"position":[[9,4]]},"860":{"position":[[9,4]]},"880":{"position":[[9,4]]},"903":{"position":[[9,4]]},"921":{"position":[[9,4]]},"943":{"position":[[9,4]]},"963":{"position":[[9,4]]},"981":{"position":[[9,4]]},"991":{"position":[[9,4]]},"1033":{"position":[[9,4]]},"1049":{"position":[[9,4]]},"1066":{"position":[[9,4]]},"1088":{"position":[[9,4]]},"1140":{"position":[[9,4]]},"1158":{"position":[[9,4]]},"1178":{"position":[[9,4]]},"1205":{"position":[[9,4]]},"1221":{"position":[[9,4]]},"1239":{"position":[[9,4]]},"1261":{"position":[[9,4]]},"1282":{"position":[[9,4]]},"1310":{"position":[[9,4]]},"1333":{"position":[[9,4]]},"1356":{"position":[[9,4]]},"1380":{"position":[[9,4]]}}}],["openfga",{"_index":0,"t":{"1":{"position":[[0,8]]},"2":{"position":[[0,8]]},"3":{"position":[[0,8]]},"13":{"position":[[0,8]]},"37":{"position":[[0,8]]},"63":{"position":[[0,8]]},"81":{"position":[[0,8]]},"97":{"position":[[0,8]]},"111":{"position":[[0,8]]},"125":{"position":[[0,8]]},"143":{"position":[[0,8]]},"157":{"position":[[0,8]]},"173":{"position":[[0,8]]},"187":{"position":[[0,8]]},"189":{"position":[[0,8]]},"203":{"position":[[0,8]]},"209":{"position":[[0,8]]},"229":{"position":[[0,8]]},"237":{"position":[[0,8]]},"247":{"position":[[0,8]]},"262":{"position":[[0,8]]},"277":{"position":[[0,8]]},"382":{"position":[[0,8]]},"390":{"position":[[0,8]]},"392":{"position":[[0,8]]},"414":{"position":[[0,8]]},"434":{"position":[[0,8]]},"442":{"position":[[0,8]]},"446":{"position":[[0,8]]},"460":{"position":[[0,8]]},"475":{"position":[[0,8]]},"489":{"position":[[0,8]]},"503":{"position":[[0,8]]},"517":{"position":[[0,8]]},"529":{"position":[[0,8]]},"541":{"position":[[0,8]]},"560":{"position":[[0,8]]},"598":{"position":[[0,8]]},"616":{"position":[[0,8]]},"618":{"position":[[0,8]]},"620":{"position":[[0,8]]},"626":{"position":[[0,8]]},"634":{"position":[[0,8]]},"642":{"position":[[0,8]]},"658":{"position":[[0,8]]},"660":{"position":[[0,8]]},"671":{"position":[[0,8]]},"685":{"position":[[0,8]]},"702":{"position":[[0,8]]},"717":{"position":[[0,8]]},"729":{"position":[[0,8]]},"743":{"position":[[0,8]]},"745":{"position":[[0,8]]},"751":{"position":[[0,8]]},"768":{"position":[[0,8]]},"770":{"position":[[0,8]]},"786":{"position":[[0,8]]},"797":{"position":[[0,8]]},"812":{"position":[[0,8]]},"836":{"position":[[0,8]]},"850":{"position":[[0,8]]},"852":{"position":[[0,8]]},"860":{"position":[[0,8]]},"880":{"position":[[0,8]]},"903":{"position":[[0,8]]},"921":{"position":[[0,8]]},"943":{"position":[[0,8]]},"963":{"position":[[0,8]]},"981":{"position":[[0,8]]},"991":{"position":[[0,8]]},"1033":{"position":[[0,8]]},"1049":{"position":[[0,8]]},"1066":{"position":[[0,8]]},"1088":{"position":[[0,8]]},"1140":{"position":[[0,8]]},"1158":{"position":[[0,8]]},"1178":{"position":[[0,8]]},"1205":{"position":[[0,8]]},"1221":{"position":[[0,8]]},"1239":{"position":[[0,8]]},"1261":{"position":[[0,8]]},"1282":{"position":[[0,8]]},"1310":{"position":[[0,8]]},"1333":{"position":[[0,8]]},"1356":{"position":[[0,8]]},"1380":{"position":[[0,8]]}}}],["sourc",{"_index":2,"t":{"1":{"position":[[14,7]]},"2":{"position":[[14,7]]},"3":{"position":[[14,7]]},"13":{"position":[[14,7]]},"37":{"position":[[14,7]]},"63":{"position":[[14,7]]},"81":{"position":[[14,7]]},"97":{"position":[[14,7]]},"111":{"position":[[14,7]]},"125":{"position":[[14,7]]},"143":{"position":[[14,7]]},"157":{"position":[[14,7]]},"173":{"position":[[14,7]]},"187":{"position":[[14,7]]},"189":{"position":[[14,7]]},"203":{"position":[[14,7]]},"209":{"position":[[14,7]]},"229":{"position":[[14,7]]},"237":{"position":[[14,7]]},"247":{"position":[[14,7]]},"262":{"position":[[14,7]]},"277":{"position":[[14,7]]},"382":{"position":[[14,7]]},"390":{"position":[[14,7]]},"392":{"position":[[14,7]]},"414":{"position":[[14,7]]},"434":{"position":[[14,7]]},"442":{"position":[[14,7]]},"446":{"position":[[14,7]]},"460":{"position":[[14,7]]},"475":{"position":[[14,7]]},"489":{"position":[[14,7]]},"503":{"position":[[14,7]]},"517":{"position":[[14,7]]},"529":{"position":[[14,7]]},"541":{"position":[[14,7]]},"560":{"position":[[14,7]]},"598":{"position":[[14,7]]},"616":{"position":[[14,7]]},"618":{"position":[[14,7]]},"620":{"position":[[14,7]]},"626":{"position":[[14,7]]},"634":{"position":[[14,7]]},"642":{"position":[[14,7]]},"658":{"position":[[14,7]]},"660":{"position":[[14,7]]},"671":{"position":[[14,7]]},"685":{"position":[[14,7]]},"702":{"position":[[14,7]]},"717":{"position":[[14,7]]},"729":{"position":[[14,7]]},"743":{"position":[[14,7]]},"745":{"position":[[14,7]]},"751":{"position":[[14,7]]},"768":{"position":[[14,7]]},"770":{"position":[[14,7]]},"786":{"position":[[14,7]]},"797":{"position":[[14,7]]},"812":{"position":[[14,7]]},"836":{"position":[[14,7]]},"850":{"position":[[14,7]]},"852":{"position":[[14,7]]},"860":{"position":[[14,7]]},"880":{"position":[[14,7]]},"903":{"position":[[14,7]]},"921":{"position":[[14,7]]},"943":{"position":[[14,7]]},"963":{"position":[[14,7]]},"981":{"position":[[14,7]]},"991":{"position":[[14,7]]},"1033":{"position":[[14,7]]},"1049":{"position":[[14,7]]},"1066":{"position":[[14,7]]},"1088":{"position":[[14,7]]},"1140":{"position":[[14,7]]},"1158":{"position":[[14,7]]},"1178":{"position":[[14,7]]},"1205":{"position":[[14,7]]},"1221":{"position":[[14,7]]},"1239":{"position":[[14,7]]},"1261":{"position":[[14,7]]},"1282":{"position":[[14,7]]},"1310":{"position":[[14,7]]},"1333":{"position":[[14,7]]},"1356":{"position":[[14,7]]},"1380":{"position":[[14,7]]}}}],["zanzibar",{"_index":6,"t":{"1":{"position":[[78,8]]},"2":{"position":[[78,8]]},"3":{"position":[[78,8]]},"13":{"position":[[78,8]]},"37":{"position":[[78,8]]},"63":{"position":[[78,8]]},"81":{"position":[[78,8]]},"97":{"position":[[78,8]]},"111":{"position":[[78,8]]},"125":{"position":[[78,8]]},"143":{"position":[[78,8]]},"157":{"position":[[78,8]]},"173":{"position":[[78,8]]},"187":{"position":[[78,8]]},"189":{"position":[[78,8]]},"203":{"position":[[78,8]]},"209":{"position":[[78,8]]},"229":{"position":[[78,8]]},"237":{"position":[[78,8]]},"247":{"position":[[78,8]]},"262":{"position":[[78,8]]},"277":{"position":[[78,8]]},"382":{"position":[[78,8]]},"390":{"position":[[78,8]]},"392":{"position":[[78,8]]},"414":{"position":[[78,8]]},"434":{"position":[[78,8]]},"442":{"position":[[78,8]]},"446":{"position":[[78,8]]},"460":{"position":[[78,8]]},"475":{"position":[[78,8]]},"489":{"position":[[78,8]]},"503":{"position":[[78,8]]},"517":{"position":[[78,8]]},"529":{"position":[[78,8]]},"541":{"position":[[78,8]]},"560":{"position":[[78,8]]},"598":{"position":[[78,8]]},"616":{"position":[[78,8]]},"618":{"position":[[78,8]]},"620":{"position":[[78,8]]},"626":{"position":[[78,8]]},"634":{"position":[[78,8]]},"642":{"position":[[78,8]]},"658":{"position":[[78,8]]},"660":{"position":[[78,8]]},"671":{"position":[[78,8]]},"685":{"position":[[78,8]]},"702":{"position":[[78,8]]},"717":{"position":[[78,8]]},"729":{"position":[[78,8]]},"743":{"position":[[78,8]]},"745":{"position":[[78,8]]},"751":{"position":[[78,8]]},"768":{"position":[[78,8]]},"770":{"position":[[78,8]]},"786":{"position":[[78,8]]},"797":{"position":[[78,8]]},"812":{"position":[[78,8]]},"836":{"position":[[78,8]]},"850":{"position":[[78,8]]},"852":{"position":[[78,8]]},"860":{"position":[[78,8]]},"880":{"position":[[78,8]]},"903":{"position":[[78,8]]},"921":{"position":[[78,8]]},"943":{"position":[[78,8]]},"963":{"position":[[78,8]]},"981":{"position":[[78,8]]},"991":{"position":[[78,8]]},"1033":{"position":[[78,8]]},"1049":{"position":[[78,8]]},"1066":{"position":[[78,8]]},"1088":{"position":[[78,8]]},"1140":{"position":[[78,8]]},"1158":{"position":[[78,8]]},"1178":{"position":[[78,8]]},"1205":{"position":[[78,8]]},"1221":{"position":[[78,8]]},"1239":{"position":[[78,8]]},"1261":{"position":[[78,8]]},"1282":{"position":[[78,8]]},"1310":{"position":[[78,8]]},"1333":{"position":[[78,8]]},"1356":{"position":[[78,8]]},"1380":{"position":[[78,8]]}}}]],"pipeline":["stemmer"]}},{"documents":[{"i":4,"t":"Relationship Tuples are the facts that the OpenFGA evaluates to determine whether a user is permitted to access a resource. The way tuples are considered when making authorization decisions in OpenFGA is guided by an authorization model, which employs concepts from Relationship-Based Access Control (ReBAC) to establish authorization policies. For instance, you might declare that users are allowed to view a document if they have permission to view its parent folder. Although ReBAC offers a highly flexible method for structuring permissions, it encounters difficulties with defining permissions based on attributes that are not easily represented as relationships. Attributes such as “parent folder,” “department,” “region,” and “country” can be conceptualized as relationships between two entities. However, attributes like “IP address,” “time of day,” “team size limit,” or “maximum amount for a bank transfer” cannot be easily handled. In our ongoing efforts to expand OpenFGA’s capacity for articulating a broader range of authorization policies, we are introducing Conditional Relationship Tuples. These allow for the specification of conditions under which a particular tuple is relevant when evaluating an authorization query. Consider the following example, where we utilize Conditional Tuples to grant access for a user over a specified time duration. We stipulate that a user may be granted either unconditional access or access constrained to a certain time period: model schema 1.1 type user type document relations define viewer: [user, user with non_expired_grant] condition non_expired_grant(current_time: timestamp, grant_time: timestamp, grant_duration: duration) { current_time < grant_time + grant_duration } If we write the following tuples: user relation object condition user:bob viewer document:1 user:anne viewer document:1 name : non_expired_grant, context : { grant_time : 2023-01-01T00:00:00Z, grant_duration : 1h } You'll get the following results for the Check operations below: user relation object context result user:bob viewer document:1 allowed : true user:anne viewer document:1 current_time : 2023-01-01T00:10:00Z allowed : true user:anne viewer document:1 current_time : 2023-01-01T02:00:00Z allowed : false user:anne viewer document:1 error : \"failed to evaluate relationship condition 'non_expired_grant': context is missing parameters '[current_time]' You'll get the following results for the ListObjects operations below: user relation object context result user:anne viewer document:1 current_time : 2023-01-01T00:10:00Z objects: [ \"document:1\"] user:anne viewer document:1 error: \"failed to evaluate relationship condition 'non_expired_grant': tuple 'document:1#viewer@user:anne' is missing context parameters '[current_time]' Note that: user:bob will always get allowed:true as we have assigned as viewer unconditionally. user:anne will get allowed:true if the current_time is before the grant_time + grant_duration and allowed:false otherwise. If you don't provide the current_time in the context, the Check and ListObjects operations will fail.","s":"Conditional Relationship Tuples for OpenFGA","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"","p":3},{"i":6,"t":"The OpenFGA Sample Stores repository has several examples that take advantage of this new feature: Granting access during a specific period of time (the use case explained above). Allow access based on the user’s IP Address. Granting access based on group membership and resource attributes. Allow access to specific features based on usage. Determine if a user can make a bank transfer based .on the transaction amount. Data types and operations supported in conditions.","s":"Use Cases","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#use-cases","p":3},{"i":8,"t":"Conditional Relationship Tuples are included in OpenFGA 1.4.0-rc1 version. You can run it by pulling it from docker: docker pull openfga/openfga:v1.4.0-rc1 docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 openfga/openfga:v1.4.0-rc1 run` OpenFGA has a rich ecosystem of developer tools. The following have been updated to support Conditional Relationship Tuples: Visual Studio Code integration which provides syntax highlighting and model validations for conditions. Beta versions of the Javascript SDK and the Go SDK, which allows using the additional parameters. The OpenFGA CLI allows validating models and runing tests that use conditional tuples. You can use it to test the new features by pointing to a “.fga.yaml” file that defines the tests you want to run, without having to deploy OpenFGA.","s":"How to use it?","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#how-to-use-it","p":3},{"i":10,"t":"We’ll address some limitations of the current implementation: The Expand API does not consider conditions. The Visual Studio Code integration is not validating the expressions in conditions. The Playground does not let you add context for tuples and assertions. You should use the VS Code Extension + the FGA CLI to test your models for now. We'll also improve ListObjects scenarios when it's called with missing context. For example, consider the following model that enables access only to documents with a specific status: model schema 1.1 type user type document relations define can_access: [user with docs_in_draft_status] condition docs_in_draft_status(status: string) { status == \"draft\" } If you want to list all the documents a user can view, you'll need to know the status of all of those documents. Given you don't know the documents the user has access too, you can't send the status of those as a parameter to ListObjects. Our goal is to return a structure that you can use to filter documents on your side, similar to: (document.id = ‘1’ and document.status = ‘draft’) or (document.id = ‘2’ and.status = draft) This won’t scale to a large number of documents, but would be useful in some scenarios.","s":"What’s Next?","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#whats-next","p":3},{"i":12,"t":"We want to learn how you use this feature and how we can improve it! Please reach out through our community channels with any questions or feedback.","s":"Reach out!","u":"/pr-preview/pr-921/blog/conditional-tuples-announcement","h":"#reach-out","p":3},{"i":14,"t":"Hi Everyone! We've been publishing a monthly internal newsletter we called Fine Grained News since the beginning on 2023, and we just thought it would be a good idea to share it with the community. Yeah, we are slow thinkers! You can expect to find here a summary of what we've been up to, what we are planning to do, and some other random stuff we think you might find interesting.","s":"Fine Grained News - December 2023","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"","p":13},{"i":16,"t":"We always start our Monthly Community Meetings presenting the team. If you attended the last one, you've seen that the size of the team has grown quite a bit! We are pretty excited about the impact it will have in OpenFGA and the authorization space in general.","s":"Team News","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#team-news","p":13},{"i":18,"t":"In our last Community Meeting, the Agicap team (Pauline and Yann) demoed how they are using OpenFGA to implement Behavior Driven Development (BDD) in their authorization system. The screenshot below might be enough to understand what they are doing, but if you want to know more, you can watch the full presentation here.","s":"Behavior Driven Development with OpenFGA","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#behavior-driven-development-with-openfga","p":13},{"i":20,"t":"GoDaddy has been working with OpenFGA for a few months. They just published a document explaining why they picked OpenFGA, and how they used to address the authorization challenges they were facing. Some interesting tidbits: They implemented their own DynamoDB Storage Adapter, as they were heavy Dynamo DB users and liked the eventual consistency model it provided. They needed Contextual Tuples to fully support their use case. Read the full article here.","s":"GoDaddy & OpenFGA","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#godaddy--openfga","p":13},{"i":22,"t":"Canonical has also been working with OpenFGA for a while, and it's adding OpenFGA to different layers in their stack. They just announced that OpenFGA support is included in LXD and MicroCloud. Pretty soon, if you are using Ubuntu Pro, you will be using OpenFGA :).","s":"Canonical & OpenFGA","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#canonical--openfga","p":13},{"i":24,"t":"Last week we released OpenFGA v1.4! This release includes our support for Conditional Relationship Tuples, which helps implementing additional Attribute-Based Access Control scenarios like temporal access, IP based access, bank transfer limits, SaaS application plans, and much more! You can read more about it here.","s":"OpenFGA v1.4!","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#openfga-v14","p":13},{"i":26,"t":"The Java SDK has now feature parity with the rest of the our SDKs. It can be used from any language for the Java VM. You can see examples on Kotlin, Groovy and Scala here. The Python SDK was updated to support synchronous clients, support custom SSL certificates, and better performance in batch checks.","s":"SDK Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#sdk-improvements","p":13},{"i":28,"t":"We've been working on the OpenFGA language with some long-due improvements. Soon, you'll be able to use parentheses to group expressions when defining relations: The syntax is still not supported in the FGA CLI, but we are pretty close. Daniel demoed it in our latest community meeting, you can see the full demo here.","s":"Language Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#language-improvements","p":13},{"i":30,"t":"We have also been improving tuple validation when writing fga.yaml files, and it's pretty cool! Works on Daniel's machine for now :). Daniel also demoed it in our latest community meeting, watch it here.","s":"VS Code Extension Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#vs-code-extension-improvements","p":13},{"i":32,"t":"We are getting ready for KubeCon Europe 2024, in Paris. We'll have a Project Kiosk, and we have submitted a few talks. We'll keep you posted!","s":"KubeCon EU 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#kubecon-eu-2024","p":13},{"i":34,"t":"We have a very welcoming community, and we'd love to have you there! You can join us in different ways: Join our community meetings, the second Thursday of every month. All the recordings are here. Join our community channels in Slack or GitHub. Stay up to date by following us on X. Ask questions, submit ideas, or just say hi in our GitHub Discussions.","s":"OpenFGA Community","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#openfga-community","p":13},{"i":36,"t":"We'll keep publishing our Fine Grained News each month, after the OpenFGA community meeting. If you have any feedback, you want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2023-12","h":"#see-you-next-month","p":13},{"i":38,"t":"Welcome to the 2nd edition of Fine Grained News!","s":"Fine Grained News - January 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"","p":37},{"i":40,"t":"The OpenFGA team got bigger, and we met in person in Toronto for the first time! We got to know each other better, helped new team members to get familiar with the project, hacked some code, had some fun with ax throwing, and loved Toronto's weather!","s":"Team News","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#team-news","p":37},{"i":42,"t":"We got two presentations accepted in KubeCon Europe! Jonathan Whitaker from Okta will talk about Federated IAM for Kubernetes with OpenFGA Pauline Jamin from Agicap and Andres Aguiar from Okta will present on Implementing Modern Cloud Native Authorization Using OpenFGA We'll also have a Project Kiosk, so if you plan to attend let us know and we can schedule some time together!","s":"KubeCon Europe 2024!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#kubecon-europe-2024","p":37},{"i":44,"t":"Our own Raghd Hamzeh will join Whitney Lee in a Tanzu ⚡️Enlightning session on February 8th at 9am PT. Join their Youtube stream here.","s":"OpenFGA ⚡️Enlightning Session!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#openfga-️enlightning-session","p":37},{"i":46,"t":"We keep investing in improving our VS Code experience. The video below shows how, in addition to validating the model, we can validate the tuple content and the tests. We are identifying: Invalid object types, user types, and relations when defining tuples. Invalid object types, user types, and relations when defining tests. User id or object id that was not included in any tuple in check tests. This helps authoring/testing models, making the whole process less error prone and more fun!","s":"Visual Studio Code Integration Enhancements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#visual-studio-code-integration-enhancements","p":37},{"i":48,"t":"We love the FGA CLI and we keep making it even better. We had a few of contributions from new team members and the community :). You can now import tuples from a CSV file. We supported JSON/YAML, but if you are exporting data from a database, producing to CSV is way simpler. You can take a .fga.yaml file with a model and tuples, and get it imported in OpenFGA. Added support for specifying an external tuple_file in .fga.yaml files. Added support for specifying a continuation_token when calling fga tuple changes. Support for configuring OAuth scopes to authenticate to OIDC servers. Check the updated documentation in our CLI repository Thanks to Yann D'Isanto for all your help on this!","s":"CLI improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#cli-improvements","p":37},{"i":50,"t":"We just shipped OpenFGA v1.4.3, with performance improvements and one security issue fixed. We recommend everyone to upgrade to the latest release.","s":"OpenFGA v1.4.3","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#openfga-v143","p":37},{"i":52,"t":"New releases with bug fixes and improvements: Java SDK v0.3.2. If you are using the Java SDK please upgrade to this version. Go SDK v0.3.4 Python SDK v0.4.0, which has breaking changes. Thanks again to Yann D'Isanto for your help on the Java SDK!","s":"SDK Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#sdk-improvements","p":37},{"i":54,"t":"The DSL language now has better support for comments and mixed operator support, where you can use parentheses to group expressions when defining relations: It's available in the VS Code extension, the CLI and the Playground.","s":"Language Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#language-improvements","p":37},{"i":56,"t":"We shipped a couple of Github Actions that help you deploy FGA models, and run model tests as part of your CI/CD build. Find them here.","s":"Github Actions","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#github-actions","p":37},{"i":58,"t":"We've been discussing with the OpenFGA community a couple of RFCs that we are planning to implement in the next few weeks: Support for modular models. ListUsers API. Please take a look at them and let us know what you think!","s":"What's Next? Check our RFCs!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#whats-next-check-our-rfcs","p":37},{"i":60,"t":"We have a very welcoming community, and we'd love to have you there! You can join us in different ways: Join our community meetings, the second Thursday of every month. All the recordings are here. Stay up to date by following us on X. Join our community channels in Slack or GitHub.","s":"OpenFGA Community","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#openfga-community","p":37},{"i":62,"t":"Fine Grained News are published every month, after the OpenFGA community meeting. If you have any feedback, you want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-01","h":"#see-you-next-month","p":37},{"i":64,"t":"Welcome to the 3rd edition of Fine Grained News!","s":"Fine Grained News - February 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"","p":63},{"i":66,"t":"We'll be pretty busy during KubeCon Europe 2024: Jonathan Whitaker from Okta will talk about Federated IAM for Kubernetes with OpenFGA Pauline Jamin from Agicap and Andres Aguiar from Okta will present on Implementing Modern Cloud Native Authorization Using OpenFGA OpenFGA will be present in Canonical's Operator's day, co-located at KubeCon EU. Andres Aguiar and Massimilano Gori from Canonical, will talk about how Canonical adopted OpenFGA for implementing authorization in Juju. Andres Aguiar will also be delivering a Lightning Talk titled OpenFGA - The Cloud Native way to implement Fine Grained Authorization (link not available yet :) ). We'll also have a kiosk in the CNCF Project Pavilion, so if you plan to attend let us know and we can schedule some time together!","s":"KubeCon Europe 2024 is getting closer!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#kubecon-europe-2024-is-getting-closer","p":63},{"i":68,"t":"We keep improving our documentation, and added a few new documents that you might find interesting: Learn how to use the FGA CLI to perform every possible operation on OpenFGA and simplify most common workflows. Learn how you can test FGA models as part of your development flow or CI/CD pipelines, without the need to run an OpenFGA server. Learn how you can include identity token claims contextual tuples to model ABAC-like scenarios or simplify data integrations with OpenFGA.","s":"Documentation Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#documentation-improvements","p":63},{"i":70,"t":"OpenFGA is getting bigger on the Java world! We are working with the Spring Security team to build an Spring Security integration for OpenFGA. You can check the ideas we are exploring in this repository. Also, the Testcontainers team added an OpenFGA integration for Java to make it simple to write integration tests for applications using OpenFGA. We'd love to hear your feedback!","s":"OpenFGA in the Java Ecosystem","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#openfga-in-the-java-ecosystem","p":63},{"i":72,"t":"New releases with bug fixes and improvements: Javascript SDK 0.3.3. Go SDK v0.3.5 Python SDK v0.4.1","s":"SDK Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#sdk-improvements","p":63},{"i":74,"t":"We wrapped up the RFC for Modular Models, which will enable multiple teams to work on different parts of the model independently and we are now working on the implementation. We'd love feedback on the RFC. Wait for a demo on our next Community Meeting!","s":"Modular Models","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#modular-models","p":63},{"i":76,"t":"Learn how stacklok is using OpenFGA to implement authorization in Minder, an open source project that makes it easier to apply and automate the enforcement of security checks and policies across multiple GitHub repositories. Check this OpenFGA tutorial by Alberto Coronado (in Spanish!). Raghd Hamzeh joined Whitney Lee in an in-depth Tanzu ⚡️Enlightning session about OpenFGA.","s":"Community News","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#community-news","p":63},{"i":78,"t":"As you may know, we've been using Discord for the OpenFGA community. We’ll transition it to the CNCF OpenFGA Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#transitioning-from-discord-to-cncfs-slack","p":63},{"i":80,"t":"Fine Grained News are published every month, after the OpenFGA community meeting. If you have any feedback, you want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-02","h":"#see-you-next-month","p":63},{"i":82,"t":"Welcome to Fine Grained News, KubeCon Edition!","s":"Fine Grained News - March 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"","p":81},{"i":84,"t":"You can now watch online: An AppDeveloperCon session about Implementing Modern Cloud Native Authorization Using OpenFGA where Pauline Jamin and Andres Aguiar go over how OpenFGA is helping Agicap to implement fine-grained authorization. A 7-min Lightning Talk about OpenFGA: The Cloud Native way to implement Fine Grained Authorization. Jonathan Whitaker's talk about Federated IAM for Kubernetes with OpenFGA, demoing how to use OpenFGA and KeyCloak to implement fine-grained authorization in a Kubernetes cluster, in ways it's not possible today, like giving access to a user for 90 seconds. We also participated in Canonical's Operator Day sharing how Canonical is using OpenFGA, but the presentation is not online yet. Also, thanks to everyone who stopped by the OpenFGA Kiosk in the Project Pavilion to share their feedback about the project or learn more about it!","s":"KubeCon Europe 2024 was super-busy!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#kubecon-europe-2024-was-super-busy","p":81},{"i":86,"t":"As you may know, the CNCF has three stages for projects: Sandbox, Incubation, and Graduation. OpenFGA is currently a Sandbox project. We are very happy to announce that we just applied for Incubation! We are excited about this step and will keep you posted on the progress.","s":"CNCF incubation","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#cncf-incubation","p":81},{"i":88,"t":"The OpenFGA community maintains a list of products/projects/companies that are using OpenFGA in production. We'd like to thank thank the following adopters for adding themselves to the list in the last month: Instill AI Zuplo OpenObserve Datum If you are using OpenFGA in production, please consider adding your company/project to the list.","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#new-adopters","p":81},{"i":90,"t":"Raghd Hamzeh represented OpenFGA in an episode on Authorizing Access within a series called \"You Choose - Choose Your Own Adventure: The Treacherous Trek to Security”. This episode was comparing OpenFGA with Hexa and Paralus. OpenFGA was the project viewers voted for as most interested in being featured in a demo. Sam Bellen published a Google Drive example using OpenFGA. It's a Next.js project, written in TypeScript and ready to deploy on Vercel. Philipp Wagner is working on a .NET example inspired by the Github model. Pauline Jamin and Geoffroy Braun will present about Infuser du métier dans les autorisations avec ReBAC at Devoxx France 2024 in April 17th.","s":"Community News","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#community-news","p":81},{"i":92,"t":"We just shipped a release candidate of Modular Models, that makes it easy for multiple teams to collaborate in a single OpenFGA model. It requires the following components: OpenFGA v.1.5.1 CLI v0.3.0 Visual Studio Code Extension v0.2.20 We also shipped new version of our SDKs with several fixes: Javascript SDK 0.3.5. Go SDK v0.3.5 Java SDK v0.4.0","s":"New Releases","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#new-releases","p":81},{"i":94,"t":"As we mentioned in the last edition, we transitioned out from Discord for OpenFGA and are now using the CNCF #openfga Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#transitioning-from-discord-to-cncfs-slack","p":81},{"i":96,"t":"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-03","h":"#see-you-next-month","p":81},{"i":98,"t":"Welcome to Fine Grained News, April edition!","s":"Fine Grained News - April 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"","p":97},{"i":100,"t":"Modular Models is now part of the OpenFGA core, making it easy for multiple teams to collaborate on a single OpenFGA model. Check it out, we love the feature! :) Thanks to the help provided by the Spring Security team there's now a Spring Boot Starter for OpenFGA! We shipped an OpenFGA Release Candidate with a new ListUsers API, that can be enabled with an experimental flag. ListUsers allows you to retrieve all the users that have a specific relation with a resource, for example, all users that can view a document.","s":"New Releases!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#new-releases","p":97},{"i":102,"t":"A few weeks ago we hosted a Hackathon where multiple team members experimented new ideas around OpenFGA. You'll need to wait until the next community meeting to learn more :).","s":"OpenFGA Hackathon","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#openfga-hackathon","p":97},{"i":104,"t":"We are working with the CNCF Tag-Security team on a joint security assessment, which is a step required to get accepted as a CNCF Incubation project.","s":"OpenFGA Security Assessment","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#openfga-security-assessment","p":97},{"i":106,"t":"In collaboration with Yann D'Isanto we are building a plugin for JetBrain's IDEs to allow syntax coloring and validation of OpenFGA models. Together with the Visual Studio Code integration and the Tree sitter grammar from Matouš Dzivjak OpenFGA will get great coverage for major IDEs and editors. We'll be instrumenting our SDKs to provide metrics / tracing and logging through OpenTelemetry APIs. We'll be adding additional consistency options for OpenFGA query APIs. We'll be working on adding authorization for OpenFGA APIs. Please check the items above and let us know if you have any feedback or idea.","s":"What's Next","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#whats-next","p":97},{"i":108,"t":"As we mentioned in the last edition, we transitioned out from Discord for OpenFGA and are now using the CNCF #openfga Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#transitioning-from-discord-to-cncfs-slack","p":97},{"i":110,"t":"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-04","h":"#see-you-next-month","p":97},{"i":112,"t":"Welcome to Fine Grained News, May edition!","s":"Fine Grained News - May 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"","p":111},{"i":114,"t":"We shipped the a ListUsers API. ListUsers allows you to retrieve all the users that have a specific relation with a resource (e.g. all users that can view a document). In collaboration with Yann D'Isanto we shipped a plugin for JetBrain's IDEs to allow syntax coloring and validation of OpenFGA models. Together with the Visual Studio Code integration and the Tree sitter grammar from Matouš Dzivjak, OpenFGA has get great coverage for major IDEs and editors.","s":"New Releases!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#new-releases","p":111},{"i":116,"t":"We've identified a few areas where we can improve performance and we are actively working on them. We'll be instrumenting our SDKs to provide metrics / tracing and logging through OpenTelemetry APIs. We'll be adding additional consistency options for OpenFGA query APIs. We'll be working on adding authorization for OpenFGA APIs. Please check the items above and let us know if you have any feedback or idea.","s":"What's Next","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#whats-next","p":111},{"i":118,"t":"OpenFGA will be present in CloudNative SecurityCon North America! Maria Ines Parnisari from the OpenFGA team and Evan Anderson from Stacklok will be presenting on Implementing a Multi-Tenant, Relationship-Based Authorization Model with OpenFGA. We hope to see you there!","s":"OpenFGA @ CloudNative SecurityCon","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#openfga--cloudnative-securitycon","p":111},{"i":120,"t":"In case you missed them, here are some of the latest major features we've added to OpenFGA: Conditional Tuples allows you to define tuples that are only valid under certain conditions. Modular Models makes it easy for multiple teams to collaborate on a single OpenFGA model. List Users API allowing you to retrieve all the users that have a specific relation with a resource. Spring Boot Starter for OpenFGA simplifies integrating OpenFGA with Spring Security applications. JetBrain's IDEs plugin to allow syntax coloring and validation of OpenFGA models.","s":"Latest Features","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#latest-features","p":111},{"i":122,"t":"As we mentioned before, we transitioned out from Discord for OpenFGA and are now using the CNCF #openfga Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first. Checkout https://openfga.dev/community for all the places to find us.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#transitioning-from-discord-to-cncfs-slack","p":111},{"i":124,"t":"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-05","h":"#see-you-next-month","p":111},{"i":126,"t":"Welcome to the July 2024 edition of Fine Grained News! We are thrilled to bring you the latest updates, features, and community highlights from OpenFGA. This month has included releases, performance improvements, and insights shared through our community meetings and presentations. We value your feedback and invite you to participate in our 2024 OpenFGA Community Survey. Your insights help us understand your needs better and improve our offerings. Please take a few minutes to complete the survey and let your voice be heard.","s":"Fine Grained News - July 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"","p":125},{"i":128,"t":"Latest Features We’ve introduced consistency options for query requests. This new, experimental, feature provides more flexibility and control over how queries are executed, enhancing the accuracy and reliability of query results. Learn more about this update. We’re now publishing images to ghcr.io/openfga/openfga as an alternative to DockerHub, thanks to the contribution from @JAORMX. This provides an additional option for accessing and deploying our containers. Read more. Performance Improvements We've improved our Check latency up to 20X in some scenarios in OpenFGA v1.5.7 and v1.5.6. If you have any feedback, or want to try a feature early, or are interested to learn more, please reach out!","s":"Improvements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#improvements","p":125},{"i":130,"t":"Several breaking changes related to the storage interface have been introduced. These changes should not impact your usage of OpenFGA unless you are implementing a custom storage adapter for OpenFGA.","s":"Breaking Changes","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#breaking-changes","p":125},{"i":132,"t":"Additional Consistency Options for OpenFGA queries: We've just shipped the first iteration of this feature, we're working on adding support for it in more SDKs. We’ll also be working on adding a consistency token in the future. Telemetry for SDKs: We shipped OpenTelemetry Metrics support for Python and Javascript. We’ll be adding metrics support to the rest of the SDKs and then add support for tracing and logging. If you have feedback regarding our OpenTelemetry support, please do reach out on any of our community channels. We’ll keep working on Performance Improvements for Check, List Objects and List Users APIs. We’ll be adding additional authorization options for OpenFGA to restrict API credentials to performing specific actions in OpenFGA stores. We collaborated with members of the CNCF TAG-Security team for a few weeks to get it wrapped up (thanks Krishna Krishna and Eddie for your help).","s":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#in-progress","p":125},{"i":134,"t":"Check out July’s Community Meeting! It's a great opportunity to stay updated with the latest developments, ask questions, and engage with the OpenFGA community. Maria Ines Parnisari from the OpenFGA team and Evan Anderson from Stacklok presented on Implementing a Multi-Tenant, Relationship-Based Authorization Model with OpenFGA at CloudNative SecurityCon North America. If you didn’t attend the conference in June, the presentation recording is now live. This month, Andres Aguiar and Damian Schenkelman appeared in the Identerati Office Hours livestream for an in-depth exploration of OpenFGA. This video covers advanced topics and provides valuable insights into the capabilities and implementation of OpenFGA. Whether you're a seasoned user or new to OpenFGA, this deep dive is packed with information that will enhance your understanding and usage of the platform. Andres Aguiar sat down with Open at Intel host Katherine Druckman during KubeCon Europe to discuss OpenFGA. You can hear that podcast here.","s":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#community-highlights","p":125},{"i":136,"t":"We’re happy to share that Bump is now an OpenFGA adopter! If you are using OpenFGA in production, please consider adding your company or project to our list. Your contribution will be greatly appreciated!","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#new-adopters","p":125},{"i":138,"t":"Join us for our monthly Community Meetings, held on the second Thursday of every month at 11am Eastern Time (US). Our next meeting is on Thursday, August 8, 2024. These meetings are a fantastic opportunity to stay updated with the latest developments, ask questions, and engage with the OpenFGA community. You can find the link to the meeting invite here. We look forward to seeing you there!","s":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#announcements","p":125},{"i":140,"t":"As a reminder, we transitioned out from Discord for OpenFGA and are now using the CNCF #openfga Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#transitioning-from-discord-to-cncfs-slack","p":125},{"i":142,"t":"Fine Grained News is published every month. If you have any feedback, want to share your OpenFGA story, or have a noteworthy update, please let us know on any of our community channels or at community@openfga.dev.","s":"See You Next Month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-07","h":"#see-you-next-month","p":125},{"i":144,"t":"Welcome to the September edition of Fine Grained News! As we transition into the fall season, we’re excited to bring you the latest updates on the progress of OpenFGA.","s":"Fine Grained News - September 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"","p":143},{"i":146,"t":"We shipped OpenFGA v1.6.1 with performance fixes, bug fixes, and a new SQLite storage adapter contributed by Grafana. Thanks @DanCech! This month we released improved OpenTelemetry metrics support for .NET SDK, Go SDK, Java SDK, and JavaScript SDK.","s":"Just Shipped","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#just-shipped","p":143},{"i":148,"t":"Authorization for OpenFGA: OpenFGA currently supports global pre-shared keys and OIDC for API authentication, but we’re exploring more granular authorization options, such as store-specific credentials and varying permissions for stores, modules, and types. Batch Check: OpenFGA SDKs currently implement BatchCheck by issuing multiple parallel request to the OpenFGA server. We'll be implementing a BatchCheck server endpoint to improve performance and reduce network overhead. Check out our roadmap to see what’s in the works. Feature requests and ideas can be shared in GitHub Discussions.","s":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#in-progress","p":143},{"i":150,"t":"OpenFGA at Open Source Summit Europe: José Carlos Chávez gave a talk on RBAC with OpenFGA at OSS Europe 2024 in Vienna, Austria this month. You can see the presentation deck here. OpenFGA at Open Source Strategy Forum 2024: Kiah Imani will present Role-Based Access Is So Yesterday: Revolutionizing Authorization with OpenFGA at OSSF on Wednesday, October 23, 2024. In this session, attendees will learn how OpenFGA addresses the limitations of RBAC, enhancing security, performance, and access management across various systems. OpenFGA at KubeCon: Andres Aguiar will participate in KubeCon/CloudNativeCon in November! OpenFGA will have a Kiosk in the Project Pavilion. He'll present a lightning talk on OpenFGA and participate in The Policy Engines Showdown. We added new authorization model examples for multi-tenant RBAC and how to define ABAC policies using ReBAC. Guide to Building Auth Systems: Level Up Coding offers a comprehensive guide to building authorization systems using RBAC, ReBAC, and ABAC models. The guide covers the differences between these approaches and when to use each. High Marks for OpenFGA Policy Languages: Trial Of Bits published a report comparing the security of the Cedar, OPA, and OpenFGA policy languages. OpenFGA was very well evaluated! September Community Meeting: Check out the September Community Meeting, which is posted on YouTube! In last month’s meeting, we reviewed recent updates, demos with Envoy, an OpenFGA Kubernetes Operator, fine-grained access for OpenFGA, and reviewed the results of the 2024 Community Survey.","s":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#community-highlights","p":143},{"i":152,"t":"If you or your company have implemented OpenFGA, we would love to hear about it! Please add your name as yourself as an adopter by updating the Adopters.md file and send us a PR. If you or your company provides implementation services for OpenFGA, we invite you to share your information with the community in our Implementation Services section of the Adopters.md file by sending us a PR! However, please note that the listed individuals and companies have not been evaluated or endorsed by the OpenFGA project, and inclusion on the list does not imply endorsement.","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#new-adopters","p":143},{"i":154,"t":"Hacktoberfest 2024: Hacktoberfest is a month long celebration of open source software which encourages new and experienced developers alike to contribute code to open source projects during the month of October. This makes October a great time to become an OpenFGA contributor! We have labeled a number of issues on GitHub with \"Hacktoberfest\" and \"Good First Issue\" labels making it easy to find a way to get involved and have your code included in OpenFGA. Monthly Community Meeting: Join us for our monthly Community Meetings, held on the second Thursday of every month at 11 AM Eastern Time (US). Our next meeting is on Thursday, October 10, 2024. Our community meetings are a great way to stay updated with the latest developments, ask questions, and engage with the OpenFGA community. If you would like to demo your implementation of OpenFGA, please reach out to us on any of our community channels or at community@openfga.dev. You can find the link to the meeting invite here. We look forward to seeing you there!","s":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#announcements","p":143},{"i":156,"t":"Fine Grained News is published every month. If you have any feedback, want to share your OpenFGA story, or have a noteworthy update, please let us know on any of our community channels or at community@openfga.dev.","s":"See You Next Month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-09","h":"#see-you-next-month","p":143},{"i":158,"t":"Welcome to Fine Grained News, June 2024 edition! This is where we share what has been going on in the OpenFGA community during the last 30 days :).","s":"Fine Grained News - June 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"","p":157},{"i":160,"t":"We started adding OpenTelemetry instrumentation to our SDKs. We just shipped metrics support for Python and Javascript. We'll continue with tracing and logging, and we'll be adding support for Java, Go and .NET next. We are close to ship a first iteration to add additional consistency options for OpenFGA. We are working with Krishna Kumar and Eddie Knight from the CNCF Tag-Security team on a joint security assessment for OpenFGA. We are pretty close to wrapping it up! You can follow the progress in this PR. We'll be working on adding authorization for OpenFGA APIs. We've identified a few areas where we can improve performance and we are actively working on them. If you have any feedback, or want to try a feature early, or are interested to learn more, please reach out!","s":"What are we working on?","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#what-are-we-working-on","p":157},{"i":162,"t":"We are thrilled to welcome Sourcegraph to the list of companies in our Adopters list! We are proud to be addressing their fine-grained authorization needs. If you are using OpenFGA in production, please consider adding your company/project to the list, it will be greatly appreciated!","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#new-adopters","p":157},{"i":164,"t":"Zuplo released an OpenFGA Authorization Inbound Policy that makes it super simple to add fine-grained authorization to your APIs. They are also using OpenFGA deployed globally in GCP for Zuplo itself. You can learn more about their OpenFGA integration journey in this webinar. Martin Besozzi built an APISIX plugin for OpenFGA. He also published a blog post about Mastering Access Control: Implementing Low-Code Authorization Based on ReBAC and Decoupling Pattern demonstrating how to use it. Andres Aguiar and Damian Schenkelman will do an OpenFGA Deep Dive in the July 17 episode of Identirati Office Hours.","s":"Community","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#community","p":157},{"i":166,"t":"OpenFGA was present in CloudNative SecurityCon North America! Maria Ines Parnisari from the OpenFGA team and Evan Anderson from Stacklok presented on Implementing a Multi-Tenant, Relationship-Based Authorization Model with OpenFGA. We also got a last-minute kiosk to showcase OpenFGA at the event: Thanks to everyone that stopped by!","s":"OpenFGA @ CloudNative SecurityCon","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#openfga--cloudnative-securitycon","p":157},{"i":168,"t":"In case you missed them, here are some of the latest major features we've added to OpenFGA: List Users API allows you to retrieve all the users that have a specific relation with a resource. Modular Models makes it easy for multiple teams to collaborate on a single OpenFGA model. JetBrain's IDEs plugin to allow syntax coloring and validation of OpenFGA models. Conditional Tuples allows you to define tuples that are only valid under certain conditions Spring Boot Starter for OpenFGA simplifies integrating OpenFGA with Spring Security applications.","s":"Latest Features","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#latest-features","p":157},{"i":170,"t":"As we mentioned before, we transitioned out from Discord for OpenFGA and are now using the CNCF #openfga Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first. Checkout https://openfga.dev/community for all the places to find us.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#transitioning-from-discord-to-cncfs-slack","p":157},{"i":172,"t":"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-06","h":"#see-you-next-month","p":157},{"i":174,"t":"Welcome to the October edition of Fine Grained News! As we approach the end of the year, we're excited to bring you the latest updates, improvements, and community contributions shaping the future of OpenFGA. As always, if you’re finding the OpenFGA project to be a valuable resource, we would greatly appreciate if you would star our repo on GitHub to show your support!⭐","s":"Fine Grained News - October 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"","p":173},{"i":176,"t":"OpenFGA v1.7.0: In our latest release, we’ve introduced Access Control. This experimental feature allows you to control access to your OpenFGA server, and of course, we built it using OpenFGA! We’ve updated our Docs to show you how to enable this feature; please share your feedback in the GitHub Discussions! This month, we’ve also added documentation of our OpenFGA release process. We’ve improved performance for checks involving nested tuple-to-userset relations. This is commonly used when implementing nested groups. Users can enable this with the experimental flag enable-check-optimizations. Following last month’s launch of OpenFGA SDK support for telemetry data using OpenTelemetry, we’ve also updated our Docs to guide users through configuration to collect tracing data and metrics.","s":"Just Shipped","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#just-shipped","p":173},{"i":178,"t":"Batch Check API Endpoint: We’re close to releasing a new feature to enable sending multiple check operations in a single network request. Check out our roadmap to see what’s in the works. Feature requests and ideas can be shared in GitHub Discussions.","s":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#in-progress","p":173},{"i":180,"t":"OpenFGA at Open Source Strategy Forum 2024: Kiah Imani presented “Role-Based Access Is So Yesterday: Revolutionizing Authorization with OpenFGA” at the OSSF 2024 earlier this month. The presentation is now available in Youtube OpenFGA at KubeCon: Andres Aguiar will participate in KubeCon/CloudNativeCon in November! OpenFGA will have a Kiosk in the Project Pavilion. He'll present a lightning talk on OpenFGA and participate in The Policy Engines Showdown. OpenFGA in Italy: Andrea Chiarelli will present Authorize in the Cloud with OpenFGA at Cloud Day 2024 in Milan on November 20, 2024. New Demp Flask App Added: To complement our OpenFGA examples and guides, we have published an example app demonstrating the integration of OpenFGA. This app utilizes several FGA features to provide a multi-user system for folder and text file sharing. Thanks to @ryanpq for your contribution! Monthly Community Meeting: Join us for our monthly Community Meetings, held on the second Thursday of every month at 11 AM Eastern Time (US). Our next meeting is on Thursday, November 14, 2024. Our community meetings are a great way to stay updated with the latest developments, ask questions, and engage with the OpenFGA community. If you can’t join the meetings live, our latest month's video will always be posted on our YouTube channel! As always, we welcome community members to demo their use cases. If you want to demo your implementation of OpenFGA, please contact any of the OpenFGA team on our community channels linked below.","s":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#community-highlights","p":173},{"i":182,"t":"This month, we welcome Gillion and Flex as OpenFGA adopters! If you or your company have implemented OpenFGA, we would love to hear about it! Please add your name as an adopter by updating the ADOPTERS.md file and sending us a PR. If you or your company provides implementation services for OpenFGA, we invite you to share your information with the community in our Implementation Services section of the ADOPTERS.md file by sending us a PR! However, please note that the OpenFGA project has not evaluated or endorsed the individuals and companies listed, and inclusion does not imply endorsement.","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#new-adopters","p":173},{"i":184,"t":"Hacktoberfest Highlights: This Hacktoberfest, we welcomed 13 new contributors making their first commit to OpenFGA! Thanks to the incredible community participation, we saw a 28% increase in pull requests compared to September and a remarkable 260% increase in PRs on the SDK Generator. A huge thanks to this community for your continued participation and contributions! OpenFGA Community Meeting Updates: We are adding chapters to our YouTube channel videos to simplify content navigation. We’ve begun with the most recent videos and will add chapters as time goes on. We have also begun releasing demos as individual videos for easier content consumption. You can catch this month’s demos on Modular Authorization and Client-Side Caching, with Materialize Integration coming soon!","s":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#announcements","p":173},{"i":186,"t":"Fine Grained News is published every month. If you have any feedback, want to share your OpenFGA story, or have a noteworthy update, please let us know on any of our community channels or at community@openfga.dev.","s":"See you Next Month","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-10","h":"#see-you-next-month","p":173},{"i":188,"t":"As you'd expect, the OpenFGA team will be at KubeCon NA 2023 in Chicago, IL! We'll have a packed agenda for the week: Jonathan Whitaker and Lucas Käldström will be presenting in Could_Native Rejects on how to use OpenFGA to manage and extend authorization in Kubernetes. Learn more here. Maria Ines Parnisari and Andres Aguiar will be presenting in AppDeveloperCon about modernizing authorization for cloud native applications using OpenFGA. Learn more here. We'll host a Project Meeting on Monday 9.30 AM in the Hudson room at the Hilton Garden Inn. We'll share how the product is being used, demo the latests features like our new CLI, the VS Code Extension, Conditional Relationships, the Java SDK... and more! We'll be in the CNCF Project Pavilion during the afternoons. We'll host our OpenFGA community meeting directly from KubeCon on Thursday 9th at 3PM UTC (8AM PST/11AM EST). If you want to meet with the team outside of these events, please pick any spot that works for you in our calendar. See you in Chicago!","s":"Join the OpenFGA team at KubeCon NA 2023","u":"/pr-preview/pr-921/blog/kubecon-na-2023","h":"","p":187},{"i":190,"t":"Welcome to the November edition of Fine Grained News! As we enter the final stretch of 2024, there are exciting developments in the OpenFGA to share. 🌟 We hit 3,000 stars on the OpenFGA repo!: 🌟 Because of this great community, we've just this incredible milestone! Thank you so much for all the support you've shown this project. Let's keep the momentum going! If you haven't yet, we'd greatly appreciate you starring the repo to help push us toward 4,000 stars and grow our amazing community!","s":"Fine Grained News - November 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"","p":189},{"i":192,"t":"v1.8.1: This release focuses on performance and monitoring enhancements. It introduces two new flags for better control over check operations, optimizes performance for TTU relationships with set operations, and expands metrics tracking with duration measurements. Additionally, deduplication logic has been added to the BatchCheck API, along with new logging fields for authz calls. Read more in the Read more in the Changelog... For more about the new OPENFGA_CHECK_ITERATOR_TTL and OPENFGA_CHECK_CACHE_LIMIT flags, run ./openfga run --help Batch Check API: Introduced in v1.8.0, the BatchCheck API significantly reduces network latency by batching authorization checks in a single request. With v1.8.1, deduplication logic increasing its efficiency further. v1.8.0 also added support for Contextual Tuples in the Expand API, time-based filtering in the ReadChanges API, and additional performance improvements. Read more in the Changelog or the BatchCheck API docs.","s":"Just Shipped","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#just-shipped","p":189},{"i":194,"t":"SDK Updates: We will be updating the SDKs next to take advantage of the new BatchCheck, starting with Python and JavaScript. If you want to see an SDK prioritized, let us know! Check out our roadmap to see what we're working on. Feature requests and ideas can be shared in GitHub Discussions.","s":"Coming Up","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#coming-up","p":189},{"i":196,"t":"OpenFGA at KubeCon: In November, Andres Aguiar represented OpenFGA at KubeCon/CloudNativeCon. OpenFGA had a kiosk in the Project Pavilion, where Andres delivered a lightning talk and participated in The Policy Engines Showdown with other authorization solution providers. Watch the panel discussion... Andres Aguiar representing OpenFGA at KubeCon OpenFGA in Italy: Andrea Chiarelli presented Authorize in the Cloud with OpenFGA at Cloud Day 2024 in Milan. Andrea Chiarelli presenting at Cloud Day 2024 OpenFGA Offsite: The team that works hard to bring you OpenFGA met in Chicago this November for a fun and productive offsite, diving deep into our vision, developer needs, and the roadmap ahead. The OpenFGA team in Chicago New Modeling Demos Available!: Learn how to model fine-grained authorization in OpenFGA's domain-specific language step-by-step with our new demo video series! Starting with the basics and gradually adding complexity, this playlist is your guide to mastering OpenFGA modeling. Monthly Community Meeting: Join our in depth monthly community discussions every second Thursday at 11 AM Eastern Time (US). Check out our meeting details for more information. November's highlights included: Sebastian Döll from ZEISS showcasing their Terraform/OpenFGA integration. Justin Cohen demonstrating the new Batch Check functionality. Can't make it? Catch up on our latest recording or browse previous sessions on our YouTube channel. Blogs and Videos for AuthZ Fans: Granting TTL based permissions in OpenFGA: Implement TTL-based permissions in OpenFGA for time-limited access control. Read more on Medium... Overcoming Security Challenges in Protecting Shared Generative AI Environments: Explore solutions for ensuring secure, scalable, and efficient multi-tenancy in generative AI environments. Read more on Medium... Fine-Grained Authorization for Backstage using OpenFGA: Learn how OpenFGA enables dynamic fine-grained authorization in Backstage through ReBAC models and seamless policy updates. See the webinar on YouTube...","s":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#community-highlights","p":189},{"i":198,"t":"Are you using OpenFGA in production? Join our growing community of adopters! Add your company to our ADOPTERS.md file with a quick PR. Do you offer OpenFGA implementation services? Get listed in our Implementation Services directory. Note: Listings are community-contributed and not officially endorsed by the OpenFGA project.","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#new-adopters","p":189},{"i":200,"t":"OpenFGA Ranked #5 in CNCF Project Contributions! Thanks to our amazing community, OpenFGA soared to become the 5th most active CNCF project during Hacktoberfest in October! Your contributions made this possible, and hope to continue the engagement! Ready to join our community of contributors? We have opportunities for every skill level: Start with our Good First Issues for beginner-friendly tasks. Take on more complex challenges in our Issue queue. Follow our Contribution Guide to get started. CNCF Projects Ranked by Commits during Hacktoberfest Follow OpenFGA on LinkedIn Connect with a growing community of fine-grained authorization enthusiasts and expand your professional network by following our new OpenFGA LinkedIn page!","s":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#announcements","p":189},{"i":202,"t":"Fine Grained News is published every month. If you have any feedback, want to share your OpenFGA story, or have a noteworthy update, please let us know on any of our community channels or at community@openfga.dev.","s":"See You Next Month:","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-11","h":"#see-you-next-month","p":189},{"i":204,"t":"Today we are launching a new API for OpenFGA: ListUsers. This API will answer the question \"what users have relation X with object Y?\". This will be useful, for example, in UIs that want to display the list of users that a resource has been shared with, e.g. the \"share\" dialog in Google Docs. You can read more about it in the API docs and the product documentation.","s":"List Users API","u":"/pr-preview/pr-921/blog/list-users-announcement","h":"","p":203},{"i":206,"t":"ListUsers is available in OpenFGA starting with v1.5.4. To be able to call this API, you must turn on this flag on the server: --experimentals enable-list-users. Be sure to also check out the various configuration flags that were added to control its behavior. The new functionality is available on the latest versions of the Java, .NET, Go and Javascript SDK, CLI and VS Code integration. We'll be releasing support for the Python SDK soon.","s":"How to use it?","u":"/pr-preview/pr-921/blog/list-users-announcement","h":"#how-to-use-it","p":203},{"i":208,"t":"We want to learn how you use this API and how we can improve it! Please reach out through our community channels with any questions or feedback.","s":"We want your feedback!","u":"/pr-preview/pr-921/blog/list-users-announcement","h":"#we-want-your-feedback","p":203},{"i":210,"t":"Welcome to the August 2024 edition of Fine Grained News! We are excited to bring you the latest updates, features, and community highlights from OpenFGA.","s":"Fine Grained News - August 2024","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"","p":209},{"i":212,"t":"OpenFGA v1.6.0: The latest OpenFGA release enables support for query consistency options and includes additional performance enhancements. Query Consistency Options in SDKs: All OpenFGA SDKs now support specifying a query consistency parameter for OpenFGA query endpoints. Make sure to update to the latest versions of the SDKs and OpenFGA to take advantage of this feature. Metrics Telemetry for SDKs: We already supported OpenTelemetry metrics in the Python and Javascript SDKs. We’ve just added support in the Java SDK, and the GO SDK.","s":"Just Shipped!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#just-shipped","p":209},{"i":214,"t":"We recently addressed a security issue, identified as GHSA-3f6g-m4hr-59h8, that was present in OpenFGA v1.5.7 and v1.5.8. This issue has been fixed starting v1.5.9, and we strongly recommend all users update to the latest version to ensure their systems remain secure. For more details, please refer to the security advisory on our GitHub page.","s":"Security Advisory","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#security-advisory","p":209},{"i":216,"t":"Support for OpenTelemetry tracing and logging Performance Improvements for OpenFGA queries Additional OpenFGA API Authorization Options SQLite Storage Adapter, thanks to Grafana for the contribution! Curious about what’s coming next for OpenFGA? Check out our roadmap to see what’s in store. We also welcome your feature requests and ideas in GitHub Discussions.","s":"In Progress","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#in-progress","p":209},{"i":218,"t":"CNCF Security TAG: This month, Andrés Aguiar presented OpenFGA to the CNCF Security Technical Advisory Group (TAG), where he discussed the project's current status and showcased various use cases. You can see the presentation deck here. It’s a great way to see how OpenFGA is being utilized and what’s on the horizon for the project. API Security: APISIX + OpenFGA: Check out this blog post by Kaan Kahraman on enhancing API security by integrating APISIX with OpenFGA.","s":"Community Highlights","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#community-highlights","p":209},{"i":220,"t":"Join Us at Open Source Summit Europe 2024: José Carlos Chávez will present at Open Source Summit Europe 2024 in Vienna, Austria on September 16, 2024! He will discuss Fine-Grained Policies: RBAC with OpenFGA. We look forward to seeing you there! OpenFGA at Open Source Strategy Forum 2024: Kiah Imani will present Role-Based Access Is So Yesterday: Revolutionizing Authorization with OpenFGA at OSSF on Wednesday, October 23, 2024. In this session, attendees will learn how OpenFGA addresses the limitations of RBAC, enhancing security, performance, and access management across various systems. We'll be participating of KubeCon / CloudNativeCon North America! OpenFGA will have a Kiosk in the Project Pavilion, we'll present a lightning talk on OpenFGA and participate in The Policy Engines Showdown.","s":"Upcoming Events","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#upcoming-events","p":209},{"i":222,"t":"We want to welcome Patika Global Technology as an OpenFGA adopter! If you're using OpenFGA in production, we encourage you to add your company or project to our Adopters list by opening a PR. Please include a short description of your use case in your submission. If you’ve previously added your company or project to the adopter's list, we would appreciate you updating it to include a short description. Your contributions help the community, and we greatly appreciate your support!","s":"New Adopters","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#new-adopters","p":209},{"i":224,"t":"We’ve added a new section within the Adopters list for those offering OpenFGA implementation services. If your organization wants help adopting OpenFGA, this resource can connect you with professionals specializing in our technology. If your company provides implementation services for OpenFGA, we invite you to add your details by sending us a PR! Please note that the listed companies have not been individually evaluated or endorsed by the OpenFGA project, and inclusion on the list does not imply endorsement.","s":"OpenFGA Service Providers","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#openfga-service-providers","p":209},{"i":226,"t":"OpenFGA Joins Docker-Sponsored Open Source Program: We’re excited to share that OpenFGA has been accepted into the Docker-Sponsored Open Source Program! This partnership allows us to distribute our container image more efficiently and securely, ensuring that our community can easily access and trust the latest versions of OpenFGA on Docker Hub with higher rate limits. 2024 Community Survey Participation: A huge thank you to everyone who participated in the 2024 Community Survey! Your insights are invaluable in helping us shape the future of OpenFGA. We truly appreciate the time and thought you put into sharing your experiences and suggestions. Remember, we always welcome feedback across our community channels — your input is what drives us forward. Monthly Community Meeting: Join us for our monthly Community Meetings, held on the second Thursday of every month at 11 AM Eastern Time (US). Our next meeting is on Thursday, September 12, 2024. These meetings are a fantastic opportunity to stay updated with the latest developments, ask questions, and engage with the OpenFGA community. You can find the link to the meeting invite here. We look forward to seeing you there!","s":"Announcements","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#announcements","p":209},{"i":228,"t":"Fine Grained News is published every month. Although we have transitioned from Discord to the CNCF Slack channel, we want to continue to hear from you! Whether you have questions or feedback or just want to connect with others using OpenFGA, our community channels are the best place to do so. You can reach us at: CNCF Slack: Join the conversation in the #openfga channel. Please note: If you are not currently part of the CNCF Slack channel, you will need to click here to join the channel first. GitHub Discussions: Share your feedback, ask questions, and engage with the community on GitHub Discussions. Twitter: Follow us @openfga for updates and news. Visit our community page for more details and to join these channels. We look forward to your contributions and conversations!","s":"See You Next Month!","u":"/pr-preview/pr-921/blog/fine-grained-news-2024-08","h":"#see-you-next-month","p":209},{"i":230,"t":"Modular models aims to improve the model authoring experience when multiple teams are maintaining a model, such as: A model can grow large and difficult to understand As more teams begin to contribute to a model, the ownership boundaries may not be clear and code review processes might not scale With modular models, a single model can be separated across multiple files allow grouping of types and conditions into modules. This means that a model can be organized more easily in terms of team or organizational structure. Used in conjunction with features such as GitHub, GitLab or Gitea's code owners, it should become easier to ensure the owners of a portion of your model are correctly assigned to review it.","s":"Modular Models","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"","p":229},{"i":232,"t":"Modular models is available in the latest version of OpenFGA. To use it you need to: Update to the v0.3.0 release of the CLI Update to v0.2.21 of the VS Code Extension Download v1.5.3 of OpenFGA Check out the modular models sample store in the sample-stores repo Review the documentation for this feature Check a demo video in Youtube","s":"How to use it?","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"#how-to-use-it","p":229},{"i":234,"t":"Looking beyond the near term, modular models allows us to implement additional API authorization options for OpenFGA.","s":"What's next?","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"#whats-next","p":229},{"i":236,"t":"We want to learn how you use this feature and how we can improve it! Please reach out through our community channels with any questions or feedback.","s":"Reach out!","u":"/pr-preview/pr-921/blog/modular-models-announcement","h":"#reach-out","p":229},{"i":238,"t":"OpenFGA query APIs now allow specifying the desired consistency of query results. By default, OpenFGA does not use a cache. However, when caching is enabled, it applies to all requests. This means that any changes in permissions won't be reflected in authorization checks during the cache TTL period. The community expressed the need for flexibility in using the cache on a per-request basis. In response, starting with OpenFGA v1.5.7, all query APIs can accept a consistency parameter with the following values: Name Description MINIMIZE_LATENCY (default) OpenFGA will try to minimize latency (e.g. by making use of the cache) HIGHER_CONSISTENCY OpenFGA will try to optimize for stronger consistency (e.g. by bypassing cache) When HIGHER_CONSISTENCY is specified, OpenFGA reads directly from the database, even when the cache is enabled.","s":"Query Consistency Options in OpenFGA","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"","p":237},{"i":240,"t":"The new consistency parameter is available in OpenFGA starting v1.5.7. The parameter is supported by all OpenFGA SDKs. For more information on enabling the cache and best practices for specifying consistency values, refer to the documentation.","s":"How to use it?","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#how-to-use-it","p":237},{"i":242,"t":"For those with a custom database adapter for a multi-region database, the behavior of the HIGHER_CONSISTENCY parameter can be defined according to your needs. With an eventually consistent database (e.g., Dynamo DB) in a multi-region setup, there will be replication lag even if the cache is bypassed. If the database supports strong reads, you can choose to perform those at an extra cost. Otherwise, you can perform an eventually consistent read without providing full consistency semantics to the caller. In some other databases where you have Read/Write replicas, you may choose to go to the Write replica when the HIGHER_CONSISTENCY preference is selected.","s":"Custom database adapter implementations","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#custom-database-adapter-implementations","p":237},{"i":244,"t":"Google Zanzibar features a consistency token called Zookies, returned from write operations. This token can be stored in a resource table and specified in subsequent query API calls. We are considering introducing a similar feature in future releases.","s":"Future work","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#future-work","p":237},{"i":246,"t":"We want to learn how you use this API and how we can improve it! Please reach out through our community channels with any questions or feedback.","s":"We want your feedback!","u":"/pr-preview/pr-921/blog/query-consistency-options-announcement","h":"#we-want-your-feedback","p":237},{"i":249,"t":"Authentication ensures a user's identity. Authorization determines if a user can perform a certain action on a particular resource. For example, when you log in to Google, Authentication is the process of verifying that your username and password are correct. Authorization is the process of ensuring that you can access a given Google service or feature.","s":"Authentication and Authorization","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#authentication-and-authorization","p":247},{"i":251,"t":"Fine-Grained Authorization (FGA) implies the ability to grant specific users permission to perform certain actions in specific resources. Well-designed FGA systems allow you to manage permissions for millions of objects and users. These permissions can change rapidly as a system continually adds objects and updates access permissions for its users. A notable example of FGA is Google Drive: access can be granted either to documents or to folders, as well as to individual users or users as a group, and access rights regularly change as new documents are created and shared with specific users or groups.","s":"What is Fine-Grained Authorization?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-fine-grained-authorization","p":247},{"i":253,"t":"In Role-Based Access Control (RBAC), permissions are assigned to users based on their role in a system. For example, a user needs the editor role to edit content. RBAC systems enable you to define users, groups, roles, and permissions, then store them in a centralized location. Applications access that information to make authorization decisions.","s":"What is Role-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-role-based-access-control","p":247},{"i":255,"t":"In Attribute-Based Access Control (ABAC), permissions are granted based on a set of attributes that a user or resource possesses. For example, a user assigned both marketing and manager attributes is entitled to publish and delete posts that have a marketing attribute. Applications implementing ABAC need to retrieve information stored in multiple data sources - like RBAC services, user directories, and application-specific data sources - to make authorization decisions.","s":"What is Attribute-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-attribute-based-access-control","p":247},{"i":257,"t":"Policy-Based Access Control (PBAC) is the ability to manage authorization policies in a centralized way that’s external to the application code. Most implementations of ABAC are also PBAC.","s":"What is Policy-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-policy-based-access-control","p":247},{"i":259,"t":"Relationship-Based Access Control (ReBAC) enables user access rules to be conditional on relations that a given user has with a given object and that object's relationship with other objects. For example, a given user can view a given document if the user has access to the document's parent folder. ReBAC is a superset of RBAC: you can fully implement RBAC with ReBAC. ReBAC also lets you natively solve for ABAC when attributes can be expressed in the form of relationships. For example ‘a user’s manager’, ‘the parent folder’, ‘the owner of a document’, ‘the user’s department’ can be defined as relationships. OpenFGA extends ReBAC by making it simpler to express additional ABAC scenarios using Conditions or Contextual Tuples. ReBAC can also be considered PBAC, as authorization policies are centralized.","s":"What is Relationship-Based Access Control?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-relationship-based-access-control","p":247},{"i":261,"t":"Zanzibar is Google's global authorization system across Google's product suite. It’s based on ReBAC and uses object-relation-user tuples to store relationship data, then checks those relations for a match between a user and an object. For more information, see Zanzibar Academy. ReBAC systems based on Zanzibar store the data necessary to make authorization decisions in a centralized database. Applications only need to call an API to make authorization decisions. OpenFGA is an example of a Zanzibar-based authorization system. Learn about OpenFGA. OpenFGA Concepts Learn about the OpenFGA Concepts More Modeling: Getting Started Learn about how to get started with modeling your permission system in OpenFGA. More","s":"What is Zanzibar?","u":"/pr-preview/pr-921/docs/authorization-concepts","h":"#what-is-zanzibar","p":247},{"i":264,"t":"The OpenFGA community has a channel in the CNCF Slack. If you don't have access to the CNCF Slack you can request an invitation here. You can join the community in the #openfga channel.","s":"Slack (CNCF Community)","u":"/pr-preview/pr-921/docs/community","h":"#slack-cncf-community","p":262},{"i":266,"t":"You can also use GitHub discussions to ask questions and submit product ideas.","s":"GitHub Discussions","u":"/pr-preview/pr-921/docs/community","h":"#github-discussions","p":262},{"i":268,"t":"Follow us on X to get the latest updates on all things OpenFGA. @OpenFGA.","s":"X (formerly Twitter)","u":"/pr-preview/pr-921/docs/community","h":"#x-formerly-twitter","p":262},{"i":270,"t":"Subscribe to the OpenFGA YouTube Channel to see our latest videos and recordings.","s":"YouTube","u":"/pr-preview/pr-921/docs/community","h":"#youtube","p":262},{"i":272,"t":"Follow us on LinkedIn for the latest updates, community highlights, and insights into fine-grained authorization.","s":"LinkedIn","u":"/pr-preview/pr-921/docs/community","h":"#linkedin","p":262},{"i":274,"t":"For the Fediverse fans among you, follow us on Mastodon at @openfga@mastodon.social!","s":"Mastodon","u":"/pr-preview/pr-921/docs/community","h":"#mastodon","p":262},{"i":276,"t":"We hold a monthly community meeting on the second Thursday of every month @ 11am Eastern Time (US). Agenda Zoom Link Recordings of Previous Meetings Web Link | ics file Read more details here","s":"Monthly Community Meetings","u":"/pr-preview/pr-921/docs/community","h":"#monthly-community-meetings","p":262},{"i":279,"t":"April 25, 2024 · 2 min read Ewan Harris","s":"Modular Models","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":281,"t":"Modular models is available in the latest version of OpenFGA. To use it you need to: Update to the v0.3.0 release of the CLI Update to v0.2.21 of the VS Code Extension Download v1.5.3 of OpenFGA Check out the modular models sample store in the sample-stores repo Review the documentation for this feature Check a demo video in Youtube","s":"How to use it?","u":"/pr-preview/pr-921/blog/page/2","h":"#how-to-use-it","p":277},{"i":283,"t":"Looking beyond the near term, modular models allows us to implement additional API authorization options for OpenFGA.","s":"What's next?","u":"/pr-preview/pr-921/blog/page/2","h":"#whats-next","p":277},{"i":285,"t":"We want to learn how you use this feature and how we can improve it! Please reach out through our community channels with any questions or feedback.","s":"Reach out!","u":"/pr-preview/pr-921/blog/page/2","h":"#reach-out","p":277},{"i":287,"t":"March 28, 2024 · 3 min read Andres Aguiar Product Manager","s":"Fine Grained News - March 2024","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":289,"t":"You can now watch online: An AppDeveloperCon session about Implementing Modern Cloud Native Authorization Using OpenFGA where Pauline Jamin and Andres Aguiar go over how OpenFGA is helping Agicap to implement fine-grained authorization. A 7-min Lightning Talk about OpenFGA: The Cloud Native way to implement Fine Grained Authorization. Jonathan Whitaker's talk about Federated IAM for Kubernetes with OpenFGA, demoing how to use OpenFGA and KeyCloak to implement fine-grained authorization in a Kubernetes cluster, in ways it's not possible today, like giving access to a user for 90 seconds. We also participated in Canonical's Operator Day sharing how Canonical is using OpenFGA, but the presentation is not online yet. Also, thanks to everyone who stopped by the OpenFGA Kiosk in the Project Pavilion to share their feedback about the project or learn more about it!","s":"KubeCon Europe 2024 was super-busy!","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-europe-2024-was-super-busy","p":277},{"i":291,"t":"As you may know, the CNCF has three stages for projects: Sandbox, Incubation, and Graduation. OpenFGA is currently a Sandbox project. We are very happy to announce that we just applied for Incubation! We are excited about this step and will keep you posted on the progress.","s":"CNCF incubation","u":"/pr-preview/pr-921/blog/page/2","h":"#cncf-incubation","p":277},{"i":293,"t":"The OpenFGA community maintains a list of products/projects/companies that are using OpenFGA in production. We'd like to thank thank the following adopters for adding themselves to the list in the last month: Instill AI Zuplo OpenObserve Datum If you are using OpenFGA in production, please consider adding your company/project to the list.","s":"New Adopters","u":"/pr-preview/pr-921/blog/page/2","h":"#new-adopters","p":277},{"i":295,"t":"Raghd Hamzeh represented OpenFGA in an episode on Authorizing Access within a series called \"You Choose - Choose Your Own Adventure: The Treacherous Trek to Security”. This episode was comparing OpenFGA with Hexa and Paralus. OpenFGA was the project viewers voted for as most interested in being featured in a demo. Sam Bellen published a Google Drive example using OpenFGA. It's a Next.js project, written in TypeScript and ready to deploy on Vercel. Philipp Wagner is working on a .NET example inspired by the Github model. Pauline Jamin and Geoffroy Braun will present about Infuser du métier dans les autorisations avec ReBAC at Devoxx France 2024 in April 17th.","s":"Community News","u":"/pr-preview/pr-921/blog/page/2","h":"#community-news","p":277},{"i":297,"t":"We just shipped a release candidate of Modular Models, that makes it easy for multiple teams to collaborate in a single OpenFGA model. It requires the following components: OpenFGA v.1.5.1 CLI v0.3.0 Visual Studio Code Extension v0.2.20 We also shipped new version of our SDKs with several fixes: Javascript SDK 0.3.5. Go SDK v0.3.5 Java SDK v0.4.0","s":"New Releases","u":"/pr-preview/pr-921/blog/page/2","h":"#new-releases","p":277},{"i":299,"t":"As we mentioned in the last edition, we transitioned out from Discord for OpenFGA and are now using the CNCF #openfga Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/page/2","h":"#transitioning-from-discord-to-cncfs-slack","p":277},{"i":301,"t":"Fine Grained News are published every month. If you have any feedback, want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":303,"t":"February 27, 2024 · 3 min read Andres Aguiar Product Manager","s":"Fine Grained News - February 2024","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":305,"t":"We'll be pretty busy during KubeCon Europe 2024: Jonathan Whitaker from Okta will talk about Federated IAM for Kubernetes with OpenFGA Pauline Jamin from Agicap and Andres Aguiar from Okta will present on Implementing Modern Cloud Native Authorization Using OpenFGA OpenFGA will be present in Canonical's Operator's day, co-located at KubeCon EU. Andres Aguiar and Massimilano Gori from Canonical, will talk about how Canonical adopted OpenFGA for implementing authorization in Juju. Andres Aguiar will also be delivering a Lightning Talk titled OpenFGA - The Cloud Native way to implement Fine Grained Authorization (link not available yet :) ). We'll also have a kiosk in the CNCF Project Pavilion, so if you plan to attend let us know and we can schedule some time together!","s":"KubeCon Europe 2024 is getting closer!","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-europe-2024-is-getting-closer","p":277},{"i":307,"t":"We keep improving our documentation, and added a few new documents that you might find interesting: Learn how to use the FGA CLI to perform every possible operation on OpenFGA and simplify most common workflows. Learn how you can test FGA models as part of your development flow or CI/CD pipelines, without the need to run an OpenFGA server. Learn how you can include identity token claims contextual tuples to model ABAC-like scenarios or simplify data integrations with OpenFGA.","s":"Documentation Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#documentation-improvements","p":277},{"i":309,"t":"OpenFGA is getting bigger on the Java world! We are working with the Spring Security team to build an Spring Security integration for OpenFGA. You can check the ideas we are exploring in this repository. Also, the Testcontainers team added an OpenFGA integration for Java to make it simple to write integration tests for applications using OpenFGA. We'd love to hear your feedback!","s":"OpenFGA in the Java Ecosystem","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-in-the-java-ecosystem","p":277},{"i":311,"t":"New releases with bug fixes and improvements: Javascript SDK 0.3.3. Go SDK v0.3.5 Python SDK v0.4.1","s":"SDK Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#sdk-improvements","p":277},{"i":313,"t":"We wrapped up the RFC for Modular Models, which will enable multiple teams to work on different parts of the model independently and we are now working on the implementation. We'd love feedback on the RFC. Wait for a demo on our next Community Meeting!","s":"Modular Models","u":"/pr-preview/pr-921/blog/page/2","h":"#modular-models","p":277},{"i":315,"t":"Learn how stacklok is using OpenFGA to implement authorization in Minder, an open source project that makes it easier to apply and automate the enforcement of security checks and policies across multiple GitHub repositories. Check this OpenFGA tutorial by Alberto Coronado (in Spanish!). Raghd Hamzeh joined Whitney Lee in an in-depth Tanzu ⚡️Enlightning session about OpenFGA.","s":"Community News","u":"/pr-preview/pr-921/blog/page/2","h":"#community-news","p":277},{"i":317,"t":"As you may know, we've been using Discord for the OpenFGA community. We’ll transition it to the CNCF OpenFGA Slack channel. If you are not part of the CNCF Slack workspace, you need to join the CNCF Slack first.","s":"Transitioning from Discord to CNCF's Slack","u":"/pr-preview/pr-921/blog/page/2","h":"#transitioning-from-discord-to-cncfs-slack","p":277},{"i":319,"t":"Fine Grained News are published every month, after the OpenFGA community meeting. If you have any feedback, you want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":321,"t":"January 29, 2024 · 4 min read Andres Aguiar Product Manager","s":"Fine Grained News - January 2024","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":323,"t":"The OpenFGA team got bigger, and we met in person in Toronto for the first time! We got to know each other better, helped new team members to get familiar with the project, hacked some code, had some fun with ax throwing, and loved Toronto's weather!","s":"Team News","u":"/pr-preview/pr-921/blog/page/2","h":"#team-news","p":277},{"i":325,"t":"We got two presentations accepted in KubeCon Europe! Jonathan Whitaker from Okta will talk about Federated IAM for Kubernetes with OpenFGA Pauline Jamin from Agicap and Andres Aguiar from Okta will present on Implementing Modern Cloud Native Authorization Using OpenFGA We'll also have a Project Kiosk, so if you plan to attend let us know and we can schedule some time together!","s":"KubeCon Europe 2024!","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-europe-2024","p":277},{"i":327,"t":"Our own Raghd Hamzeh will join Whitney Lee in a Tanzu ⚡️Enlightning session on February 8th at 9am PT. Join their Youtube stream here.","s":"OpenFGA ⚡️Enlightning Session!","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-️enlightning-session","p":277},{"i":329,"t":"We keep investing in improving our VS Code experience. The video below shows how, in addition to validating the model, we can validate the tuple content and the tests. We are identifying: Invalid object types, user types, and relations when defining tuples. Invalid object types, user types, and relations when defining tests. User id or object id that was not included in any tuple in check tests. This helps authoring/testing models, making the whole process less error prone and more fun!","s":"Visual Studio Code Integration Enhancements","u":"/pr-preview/pr-921/blog/page/2","h":"#visual-studio-code-integration-enhancements","p":277},{"i":331,"t":"We love the FGA CLI and we keep making it even better. We had a few of contributions from new team members and the community :). You can now import tuples from a CSV file. We supported JSON/YAML, but if you are exporting data from a database, producing to CSV is way simpler. You can take a .fga.yaml file with a model and tuples, and get it imported in OpenFGA. Added support for specifying an external tuple_file in .fga.yaml files. Added support for specifying a continuation_token when calling fga tuple changes. Support for configuring OAuth scopes to authenticate to OIDC servers. Check the updated documentation in our CLI repository Thanks to Yann D'Isanto for all your help on this!","s":"CLI improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#cli-improvements","p":277},{"i":333,"t":"We just shipped OpenFGA v1.4.3, with performance improvements and one security issue fixed. We recommend everyone to upgrade to the latest release.","s":"OpenFGA v1.4.3","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-v143","p":277},{"i":335,"t":"New releases with bug fixes and improvements: Java SDK v0.3.2. If you are using the Java SDK please upgrade to this version. Go SDK v0.3.4 Python SDK v0.4.0, which has breaking changes. Thanks again to Yann D'Isanto for your help on the Java SDK!","s":"SDK Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#sdk-improvements","p":277},{"i":337,"t":"The DSL language now has better support for comments and mixed operator support, where you can use parentheses to group expressions when defining relations: It's available in the VS Code extension, the CLI and the Playground.","s":"Language Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#language-improvements","p":277},{"i":339,"t":"We shipped a couple of Github Actions that help you deploy FGA models, and run model tests as part of your CI/CD build. Find them here.","s":"Github Actions","u":"/pr-preview/pr-921/blog/page/2","h":"#github-actions","p":277},{"i":341,"t":"We've been discussing with the OpenFGA community a couple of RFCs that we are planning to implement in the next few weeks: Support for modular models. ListUsers API. Please take a look at them and let us know what you think!","s":"What's Next? Check our RFCs!","u":"/pr-preview/pr-921/blog/page/2","h":"#whats-next-check-our-rfcs","p":277},{"i":343,"t":"We have a very welcoming community, and we'd love to have you there! You can join us in different ways: Join our community meetings, the second Thursday of every month. All the recordings are here. Stay up to date by following us on X. Join our community channels in Slack or GitHub.","s":"OpenFGA Community","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-community","p":277},{"i":345,"t":"Fine Grained News are published every month, after the OpenFGA community meeting. If you have any feedback, you want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":347,"t":"December 18, 2023 · 4 min read Andres Aguiar Product Manager","s":"Fine Grained News - December 2023","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":349,"t":"We always start our Monthly Community Meetings presenting the team. If you attended the last one, you've seen that the size of the team has grown quite a bit! We are pretty excited about the impact it will have in OpenFGA and the authorization space in general.","s":"Team News","u":"/pr-preview/pr-921/blog/page/2","h":"#team-news","p":277},{"i":351,"t":"In our last Community Meeting, the Agicap team (Pauline and Yann) demoed how they are using OpenFGA to implement Behavior Driven Development (BDD) in their authorization system. The screenshot below might be enough to understand what they are doing, but if you want to know more, you can watch the full presentation here.","s":"Behavior Driven Development with OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"#behavior-driven-development-with-openfga","p":277},{"i":353,"t":"GoDaddy has been working with OpenFGA for a few months. They just published a document explaining why they picked OpenFGA, and how they used to address the authorization challenges they were facing. Some interesting tidbits: They implemented their own DynamoDB Storage Adapter, as they were heavy Dynamo DB users and liked the eventual consistency model it provided. They needed Contextual Tuples to fully support their use case. Read the full article here.","s":"GoDaddy & OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"#godaddy--openfga","p":277},{"i":355,"t":"Canonical has also been working with OpenFGA for a while, and it's adding OpenFGA to different layers in their stack. They just announced that OpenFGA support is included in LXD and MicroCloud. Pretty soon, if you are using Ubuntu Pro, you will be using OpenFGA :).","s":"Canonical & OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"#canonical--openfga","p":277},{"i":357,"t":"Last week we released OpenFGA v1.4! This release includes our support for Conditional Relationship Tuples, which helps implementing additional Attribute-Based Access Control scenarios like temporal access, IP based access, bank transfer limits, SaaS application plans, and much more! You can read more about it here.","s":"OpenFGA v1.4!","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-v14","p":277},{"i":359,"t":"The Java SDK has now feature parity with the rest of the our SDKs. It can be used from any language for the Java VM. You can see examples on Kotlin, Groovy and Scala here. The Python SDK was updated to support synchronous clients, support custom SSL certificates, and better performance in batch checks.","s":"SDK Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#sdk-improvements","p":277},{"i":361,"t":"We've been working on the OpenFGA language with some long-due improvements. Soon, you'll be able to use parentheses to group expressions when defining relations: The syntax is still not supported in the FGA CLI, but we are pretty close. Daniel demoed it in our latest community meeting, you can see the full demo here.","s":"Language Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#language-improvements","p":277},{"i":363,"t":"We have also been improving tuple validation when writing fga.yaml files, and it's pretty cool! Works on Daniel's machine for now :). Daniel also demoed it in our latest community meeting, watch it here.","s":"VS Code Extension Improvements","u":"/pr-preview/pr-921/blog/page/2","h":"#vs-code-extension-improvements","p":277},{"i":365,"t":"We are getting ready for KubeCon Europe 2024, in Paris. We'll have a Project Kiosk, and we have submitted a few talks. We'll keep you posted!","s":"KubeCon EU 2024","u":"/pr-preview/pr-921/blog/page/2","h":"#kubecon-eu-2024","p":277},{"i":367,"t":"We have a very welcoming community, and we'd love to have you there! You can join us in different ways: Join our community meetings, the second Thursday of every month. All the recordings are here. Join our community channels in Slack or GitHub. Stay up to date by following us on X. Ask questions, submit ideas, or just say hi in our GitHub Discussions.","s":"OpenFGA Community","u":"/pr-preview/pr-921/blog/page/2","h":"#openfga-community","p":277},{"i":369,"t":"We'll keep publishing our Fine Grained News each month, after the OpenFGA community meeting. If you have any feedback, you want to share your OpenFGA story, or know about something that you think is worth mentioning, please let us know!","s":"See you next month!","u":"/pr-preview/pr-921/blog/page/2","h":"#see-you-next-month","p":277},{"i":371,"t":"November 6, 2023 · 5 min read Andres Aguiar Product Manager","s":"Conditional Relationship Tuples for OpenFGA","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":373,"t":"The OpenFGA Sample Stores repository has several examples that take advantage of this new feature: Granting access during a specific period of time (the use case explained above). Allow access based on the user’s IP Address. Granting access based on group membership and resource attributes. Allow access to specific features based on usage. Determine if a user can make a bank transfer based .on the transaction amount. Data types and operations supported in conditions.","s":"Use Cases","u":"/pr-preview/pr-921/blog/page/2","h":"#use-cases","p":277},{"i":375,"t":"Conditional Relationship Tuples are included in OpenFGA 1.4.0-rc1 version. You can run it by pulling it from docker: docker pull openfga/openfga:v1.4.0-rc1 docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 openfga/openfga:v1.4.0-rc1 run` OpenFGA has a rich ecosystem of developer tools. The following have been updated to support Conditional Relationship Tuples: Visual Studio Code integration which provides syntax highlighting and model validations for conditions. Beta versions of the Javascript SDK and the Go SDK, which allows using the additional parameters. The OpenFGA CLI allows validating models and runing tests that use conditional tuples. You can use it to test the new features by pointing to a “.fga.yaml” file that defines the tests you want to run, without having to deploy OpenFGA.","s":"How to use it?","u":"/pr-preview/pr-921/blog/page/2","h":"#how-to-use-it","p":277},{"i":377,"t":"We’ll address some limitations of the current implementation: The Expand API does not consider conditions. The Visual Studio Code integration is not validating the expressions in conditions. The Playground does not let you add context for tuples and assertions. You should use the VS Code Extension + the FGA CLI to test your models for now. We'll also improve ListObjects scenarios when it's called with missing context. For example, consider the following model that enables access only to documents with a specific status: model schema 1.1 type user type document relations define can_access: [user with docs_in_draft_status] condition docs_in_draft_status(status: string) { status == \"draft\" } If you want to list all the documents a user can view, you'll need to know the status of all of those documents. Given you don't know the documents the user has access too, you can't send the status of those as a parameter to ListObjects. Our goal is to return a structure that you can use to filter documents on your side, similar to: (document.id = ‘1’ and document.status = ‘draft’) or (document.id = ‘2’ and.status = draft) This won’t scale to a large number of documents, but would be useful in some scenarios.","s":"What’s Next?","u":"/pr-preview/pr-921/blog/page/2","h":"#whats-next","p":277},{"i":379,"t":"We want to learn how you use this feature and how we can improve it! Please reach out through our community channels with any questions or feedback.","s":"Reach out!","u":"/pr-preview/pr-921/blog/page/2","h":"#reach-out","p":277},{"i":381,"t":"October 12, 2023 · One min read Andres Aguiar Product Manager","s":"Join the OpenFGA team at KubeCon NA 2023","u":"/pr-preview/pr-921/blog/page/2","h":"","p":277},{"i":383,"t":"OpenFGA is a scalable open source authorization system for developers that allows implementing authorization for any kind of application and smoothly evolve as complexity increases over time. It is owned by the Cloud Native Computing Foundation. Inspired by Google’s Zanzibar, Google’s internal authorization system, OpenFGA relies on Relationship-Based Access Control, which allows developers to easily implement Role-Based Access Control and provides additional capabilities to implement Attribute-Based Access Control. You can learn more about different authorization concepts here.","s":"Introduction to OpenFGA","u":"/pr-preview/pr-921/docs/fga","h":"","p":382},{"i":385,"t":"OpenFGA provides developer the following benefits: Move authorization logic outside of application code, making it easier to write, change and audit. Increase velocity by standardizing on a single authorization solution. Centralize authorization decisions and audit logs making it simpler to comply with security and compliance requirements. Help their products to move faster because it is simpler to evolve authorization policies.","s":"Benefits","u":"/pr-preview/pr-921/docs/fga","h":"#benefits","p":382},{"i":387,"t":"OpenFGA helps developers achieve those benefits with features as: Support for multiple stores that allow authorization management in different environments (prod/testing/dev) and use cases (internal apps, external apps, infrastructure). Support for some ABAC scenarios with Contextual Tuples and Conditional Relationship Tuples. SDKs for Java, .NET, Javascript, Go, and Python. HTTP and gRPC APIs. Support for being run as a library, from with a Go based service. Support for using Postgres, MySQL or SQLite as the production datastore, as well as an in-memory datastore for non-production usage. A Command Line Interface tool for managing OpenFGA stores, test models, import/export models, and data. Github Actions for testing and deploying models. A Visual Studio Code Extension with syntax highlighting and validation of FGA models and tests. Helm Charts to easily deploy to Kubernetes. OpenTelemetry support to integrate it with your monitoring infrastructure.","s":"Features","u":"/pr-preview/pr-921/docs/fga","h":"#features","p":382},{"i":389,"t":"Check the following sections to learn more about OpenFGA. Authorization Concepts Learn about Authorization. More Product Concepts Learn about OpenFGA. More Modeling: Getting Started Learn about how to get started with modeling your permission system in OpenFGA. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/fga","h":"#related-sections","p":382},{"i":391,"t":"Setup OpenFGA How to setup an OpenFGA server. Click to navigate Install SDK Client Install the SDK for the language of your choice. Click to navigate Create a Store Creating an OpenFGA entity that owns an authorization model and relationship tuples. Click to navigate Setup SDK Client for Store Configure the SDK client for your store. Click to navigate Configure Authorization Model Programmatically configure authorization model for an OpenFGA store. Click to navigate Update Relationship Tuples Programmatically write authorization data to an OpenFGA store. Click to navigate Perform a Check Programmatically perform an authorization check against an OpenFGA store. Click to navigate Perform a List Objects Request Programmatically perform a list objects request against an OpenFGA store. Click to navigate Integrate Within a Framework Integrate authorization checks with a framework. Click to navigate Immutable Authorization Models Learn how to take advantage of the immutable properties of Authorization Models in OpenFGA. Click to navigate Production Best Practices Best Practices of Running OpenFGA in Production Environment. Click to navigate Implementation Best Practices Best Practices of Managing Tuples and Invoking OpenFGA APIs. Click to navigate","s":"Content","u":"/pr-preview/pr-921/docs/getting-started","h":"","p":390},{"i":393,"t":"The OpenFGA Command Line Interface (CLI) enables you to interact with an FGA store, where you can manage tasks, create stores, and update FGA models, among other actions. For more information on FGA stores, see What Is A Store. For instructions on installing it, visit the OpenFGA CLI Github repository.","s":"Use the FGA CLI","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"","p":392},{"i":395,"t":"The CLI is configured to use a specific FGA server in one of three ways: Using CLI flags. Using environment variables. Storing configuration values in a .fga.yaml located in the user’s root directory. The API Url setting needs to point to the OpenFGA server: Name Flag Environment ~/.fga.yaml Default Value API Url --api-url FGA_API_URL api-url http://localhost:8080 If you use pre-shared key authentication, configure the following parameters based on the OIDC server that’s used to issue tokens: Name Flag Environment ~/.fga.yaml Client ID --client-id FGA_CLIENT_ID client-id Client Secret --client-secret FGA_CLIENT_SECRET client-secret Scopes --api-scopes FGA_API_SCOPES api-scopes Token Issuer --api-token-issuer FGA_API_TOKEN_ISSUER api-token-issuer Token Audience --api-audience FGA_API_AUDIENCE api-audience A default store Id and authorization model Id can also be configured: Name Flag Environment ~/.fga.yaml Store ID --store-id FGA_STORE_ID store-id Authorization Model ID --model-id FGA_MODEL_ID model-id All of the examples in this document assume the CLI is properly configured and that the Store ID is set either in an environment variable or the ~/.fga.yaml file.","s":"Configuration","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#configuration","p":392},{"i":397,"t":"The CLI commands below show you how to create a store and run your application’s most common operations, including how to write a model and write/delete/read tuples, and run queries. # Create a store with a model $ fga store create --model docs.fga { \"store\": { \"created_at\":\"2024-02-09T23:20:28.637533296Z\", \"id\":\"01HP82R96XEJX1Q9YWA9XRQ4PM\", \"name\":\"docs\", \"updated_at\":\"2024-02-09T23:20:28.637533296Z\" }, \"model\": { \"authorization_model_id\":\"01HP82R97B448K89R45PW7NXD8\" } } # Keep the returned store id in an environment variable $ export FGA_STORE_ID=01HP82R96XEJX1Q9YWA9XRQ4PM # Get the latest model $ fga model get model schema 1.1 type user type organization relations define admin: [user with non_expired_grant] define member: [user] type document relations define editor: admin from organization define organization: [organization] define viewer: editor or member from organization condition non_expired_grant(current_time: timestamp, grant_duration: duration, grant_time: timestamp) { current_time < grant_time + grant_duration } # Write a tuple $ fga tuple write user:anne member organization:acme { \"successful\": [ { \"object\":\"organization:acme\", \"relation\":\"member\", \"user\":\"user:anne\" } ] } # Read all tuples. It returns the one added above $ fga tuple read { \"continuation_token\":\"\", \"tuples\": [ { \"key\": { \"object\":\"organization:acme\", \"relation\":\"member\", \"user\":\"user:anne\" }, \"timestamp\":\"2024-02-09T23:05:43.586Z\" } ] } # Write another tuple, adding a document for the acme organization $ fga tuple write organization:acme organization document:readme { \"successful\": [ { \"object\":\"document:readme\", \"relation\":\"organization\", \"user\":\"organization:acme\" } ] } # Check if anne can view the document. # Anne can view it as she's a member of organization:acme, which is the organization that owns the document $ fga query check user:anne viewer document:readme { \"allowed\":true, \"resolution\":\"\" } # List all the documents user:anne can view $ fga query list-objects user:anne viewer document { \"objects\": [ \"document:readme\" ] } # List all the relations that user:anne has with document:readme $ fga query list-relations user:anne document:readme { \"relations\": [ \"viewer\" ] } # Delete user:anne as a member of organization:acme $ fga tuple delete user:anne member organization:acme {} # Verify that user:anne is no longer a viewer of document:readme $ fga query check user:anne viewer document:readme { \"allowed\":false, \"resolution\":\"\" }","s":"Basic operations","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#basic-operations","p":392},{"i":399,"t":"OpenFGA models are immutable; each time a model is written to a store, a new version of the model is created. All OpenFGA API endpoints receive an optional authorization model ID that points to a specific version of the model and defaults to the latest model version. Always use a specific model ID and update it each time a new model version is used in production. The following CLI commands lists the model Ids and find the latest one: # List all the authorization models $ fga model list { \"authorization_models\": [ { \"id\":\"01HPJ8JZV091THNTDFE2SFYNNJ\", \"created_at\":\"2024-02-13T22:14:50Z\" }, { \"id\":\"01HPJ808Q8J56QMK4WNT7MG7P7\", \"created_at\":\"2024-02-13T22:04:37Z\" }, { \"id\":\"01HPJ7YKNV0QT0S6CFRJMK231P\", \"created_at\":\"2024-02-13T22:03:43Z\" } ] } # List the last model, displaying just the model ID $ fga model get --field id # Model ID: 01HPJ8JZV091THNTDFE2SFYNNJ # List the last model, displaying just the model ID, in JSON format, to make it simpler to parse $ fga model get --field id --format json { \"id\":\"01HPJ8JZV091THNTDFE2SFYNNJ\" } When using the CLI, the model ID can be specified as a --model-id parameter or as part of the configuration.","s":"Work with authorization model versions","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#work-with-authorization-model-versions","p":392},{"i":401,"t":"To import tuples, use thefga tuple write command. It has the following parameters: Parameter Description --file Specifies the file name json, yaml and csv files are supported --max-tuples-per-write (optional, default=1, max=40) Maximum number of tuples to send in a single write --max-parallel-requests (optional, default=4) Maximum number of requests to send in parallel. Make it larger if you want to import a large number of tuples faster The CLI returns a list of tuples that were successfully written and a list of tuples that were not, with details of the write failure. If you specify -max-tuples-per-write greater than one, an error in one of the tuples implies none of the tuples get written. $ fga tuple write --file tuples.yaml { \"successful\": [ { \"object\":\"organization:acme\", \"relation\":\"member\", \"user\":\"user:anne\" } ], \"failed\":null } $ fga tuple write --file tuples.yaml { \"successful\":null, \"failed\": [ { \"tuple_key\": { \"object\":\"organization:acme\", \"relation\":\"member\", \"user\":\"user:anne\" }, \"reason\":\"Write validation error for POST Write with body {\\\"code\\\":\\\"write_failed_due_to_invalid_input\\\",\\\"message\\\":\\\"cannot write a tuple which already exists: user: 'user:anne', relation: 'member', object: 'organization:acme': invalid write input\\\"}\\n with error code write_failed_due_to_invalid_input error message: cannot write a tuple which already exists: user: 'user:anne', relation: 'member', object: 'organization:acme': invalid write input\" } } Below are examples of the different file formats the CLI accepts when writing tuples:","s":"Import tuples","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#import-tuples","p":392},{"i":403,"t":"- user: user:peter relation: admin object: organization:acme condition: name: non_expired_grant context: grant_time : \"2024-02-01T00:00:00Z\" grant_duration : 1h - user: user:anne relation: member object: organization:acme","s":"yaml","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#yaml","p":392},{"i":405,"t":"[ { \"user\": \"user:peter\", \"relation\": \"admin\", \"object\": \"organization:acme\", \"condition\": { \"context\": { \"grant_duration\": \"1h\", \"grant_time\": \"2024-02-01T00:00:00Z\" }, \"name\": \"non_expired_grant\" } }, { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"organization:acme\" } ]","s":"JSON","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#json","p":392},{"i":407,"t":"user_type,user_id,user_relation,relation,object_type,object_id,condition_name,condition_context user,anne,member,,organization,acme,, user,peter1,admin,,organization,acme,non_expired_grant,\"{\"\"grant_duration\"\": \"\"1h\"\", \"\"grant_time\"\": \"\"2024-02-01T00:00:00Z\"\"}\" When using the CSV format, you can omit certain headers, and you don’t need to specify the value for those fields.","s":"CSV","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#csv","p":392},{"i":409,"t":"To delete a tuple, specify the user/relation/object you want to delete. To delete a group of tuples, specify a file that contains those tuples. $ fga tuple delete --file tuples.yaml { \"successful\": [ { \"object\":\"organization:acme\", \"relation\":\"admin\", \"user\":\"user:peter\" }, { \"object\":\"organization:acme\", \"relation\":\"member\", \"user\":\"user:anne\" } ], \"failed\":null } Delete all tuples from a store by reading all the tuples first and then deleting them: # Reads all the tuples and outputs them in a json format that can be used by 'fga tuple delete' and 'fga tuple write'. $ fga tuple read --output-format=simple-json --max-pages 0 > tuples.json $ fga tuple delete --file tuples.json","s":"Delete Tuples","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#delete-tuples","p":392},{"i":411,"t":"The CLI can import an FGA Test file in a store. It writes the model included and imports the tuples in the fga test file. Given the following .fga.yaml file: model: | model schema 1.1 type user type organization relations define member : [user] } tuples: # Anne is a member of the Acme organization - user: user:anne relation: member object: organization:acme The following command is used to import the file contents in a store: $ fga store import --file .fga.yaml Use the fga model get command is used to verify that the model was correctly written, and the fga tuple read command is used to verify that the tuples were properly imported.","s":"Import stores","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#import-stores","p":392},{"i":413,"t":"Check the following sections for more on how to learn how to write tests. Testing Models Learn how to test FGA models using the FGA CLI. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/cli","h":"#related-sections","p":392},{"i":415,"t":"OpenFGA's Configuration Language builds a representation of a system's authorization model, which informs OpenFGA's API on the object types in the system and how they relate to each other. The Configuration Language describes the relations possible for an object of a given type and lists the conditions under which one is related to that object. The Configuration Language can be presented in DSL or JSON syntax. The JSON syntax is accepted by the API and closely tracks the language in the Zanzibar paper. The DSL adds syntactic sugar on top of JSON for ease of use, but compiles down to JSON before being sent to OpenFGA's API. JSON syntax is used to call API directly or through the SDKs, while DSL is used to interact with OpenFGA in the Playground, and they can be switched between throughout this documentation. Please familiarize yourself with basic OpenFGA Concepts and How to get started on modeling before starting this guide.","s":"Configuration Language","u":"/pr-preview/pr-921/docs/configuration-language","h":"","p":414},{"i":417,"t":"Below is a sample authorization model. The next sections discuss the basics of the OpenFGA configuration language. DSL JSON model schema 1.1 type user type domain relations define member: [user] type folder relations define can_share: writer define owner: [user, domain#member] or owner from parent_folder define parent_folder: [folder] define viewer: [user, domain#member] or writer or viewer from parent_folder define writer: [user, domain#member] or owner or writer from parent_folder type document relations define can_share: writer define owner: [user, domain#member] or owner from parent_folder define parent_folder: [folder] define viewer: [user, domain#member] or writer or viewer from parent_folder define writer: [user, domain#member] or owner or writer from parent_folder { \"schema_version\": \"1.1\", \"type_definitions\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relations\": { \"member\": { \"this\": {} } }, \"metadata\": { \"relations\": { \"member\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } }, { \"type\": \"folder\", \"relations\": { \"can_share\": { \"computedUserset\": { \"object\": \"\", \"relation\": \"writer\" } }, \"owner\": { \"union\": { \"child\": [ { \"this\": {} }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"owner\" } } } ] } }, \"parent_folder\": { \"this\": {} }, \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"object\": \"\", \"relation\": \"writer\" } }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"viewer\" } } } ] } }, \"writer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"object\": \"\", \"relation\": \"owner\" } }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"writer\" } } } ] } } }, \"metadata\": { \"relations\": { \"owner\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relation\": \"member\" } ] }, \"parent_folder\": { \"directly_related_user_types\": [ { \"type\": \"folder\" } ] }, \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relation\": \"member\" } ] }, \"writer\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relation\": \"member\" } ] } } } }, { \"type\": \"document\", \"relations\": { \"can_share\": { \"computedUserset\": { \"object\": \"\", \"relation\": \"writer\" } }, \"owner\": { \"union\": { \"child\": [ { \"this\": {} }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"owner\" } } } ] } }, \"parent_folder\": { \"this\": {} }, \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"object\": \"\", \"relation\": \"writer\" } }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"viewer\" } } } ] } }, \"writer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"object\": \"\", \"relation\": \"owner\" } }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"writer\" } } } ] } } }, \"metadata\": { \"relations\": { \"owner\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relation\": \"member\" } ] }, \"parent_folder\": { \"directly_related_user_types\": [ { \"type\": \"folder\" } ] }, \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relation\": \"member\" } ] }, \"writer\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"domain\", \"relation\": \"member\" } ] } } } } ] } info The authorization model describes four types of objects: user, domain, folder and document. The domain type definition has a single relation called member that only allows direct relationships. The folder and document type definitions each have five relations: parent_folder, owner, writer, viewer and can_share.","s":"What Does The Configuration Language Look Like?","u":"/pr-preview/pr-921/docs/configuration-language","h":"#what-does-the-configuration-language-look-like","p":414},{"i":419,"t":"When used at the beginning of a relation definition, [, ...] allows direct relationships by the objects of these specified types. The strings can be in one of three formats: : indicates that tuples relating objects of those types as users can be written. For example, group:marketing can be related if group is in the type restrictions. : indicates that a tuple relating all objects of that type can be written. For example, user:* can be added if user:* is in the type restrictions. #: indicates tuples with sets of users related to an object of that type by that particular relation. For example, group:marketing#member can be added if group#member is in the type restrictions. If no direct relationship type restrictions are specified, direct relationships are disallowed and tuples cannot be written relating other objects of this particular relation with objects of this type. info [, , ...] in the OpenFGA DSL translates to this in the OpenFGA API syntax. For example, below is a snippet of the team type: DSL JSON type team relations define member: [user, user:*, team#member] { \"type\": \"team\", \"relations\": { \"member\": { \"this\": {} } }, \"metadata\": { \"relations\": { \"member\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"user:*\" }, { \"type\": \"team\", \"relation\": \"member\" } ] } } } } The team type definition above defines all the relations that users can have with an object of type team. In this example, the relation is member. Because of the [user, team#member] direct relationship type restrictions used, a user in the system can have a direct relationship with the team type as a member for objects of: type user the user type bound public access (user:*) usersets that have a team type and a member relation (e.g. team:product#member) In the type definition snippet above, anne is a member of team:product if any of the following relationship tuple sets exist: [// Anne is directly related to the product team as a member { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"team:product\", \"_description\": \"Anne is directly related to the product team as a member\" }] [// Everyone (`*`) is directly related to the product team as a member { \"user\": \"user:*\", \"relation\": \"member\", \"object\": \"team:product\", \"_description\": \"Everyone (`*`) is directly related to the product team as a member\" }] [// Members of the contoso team are members of the product team { \"user\": \"team:contoso#member\", \"relation\": \"member\", \"object\": \"team:product\", \"_description\": \"Members of the contoso team are members of the product team\" }// Anne is a member of the contoso team { \"user\": \"user:anne\", \"relation\": \"member\", \"object\": \"team:contoso\", \"_description\": \"Anne is a member of the contoso team\" }] For more examples, see Modeling Building Blocks: Direct Relationships.","s":"Direct Relationship Type Restrictions","u":"/pr-preview/pr-921/docs/configuration-language","h":"#direct-relationship-type-restrictions","p":414},{"i":421,"t":"The same object can also reference other relations. Below is a simplified document type definition: DSL JSON type document relations define editor: [user] define viewer: [user] or editor define can_rename: editor { \"type\": \"document\", \"relations\": { \"editor\": { \"this\": {} }, \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"relation\": \"editor\" } } ] } }, \"can_rename\": { \"computedUserset\": { \"relation\": \"editor\" } } }, \"metadata\": { \"relations\": { \"editor\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } Above, document type definition defines all the relations that users can have with an object of type document. In this case, the relations are editor, viewer and can_rename. The viewer and can_rename relation definitions both reference editor, which is another relation of the same type. info can_rename does not reference the direct relationship type restrictions, which means a user cannot be directly assigned this relation and it must be inherited when the editor relation is assigned. Conversely, the viewer relation allows both direct and indirect relationships using the Union Operator. In the type definition snippet above, anne is a viewer of document:new-roadmap if any one of the following relationship tuple sets exists: anne is an editor of document:new-roadmap [// Anne is an editor of the new-roadmap document { \"user\": \"user:anne\", \"relation\": \"editor\", \"object\": \"document:new-roadmap\", \"_description\": \"Anne is an editor of the new-roadmap document\" }] anne is a viewer of document:new-roadmap [// Anne is a viewer of the new-roadmap document { \"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\", \"_description\": \"Anne is a viewer of the new-roadmap document\" }] anne has a can_rename relationship with document:new-roadmap only if anne has an editor relationship with the document: anne is an editor of document:new-roadmap [// Anne is an editor of thew new-roadmap document { \"user\": \"user:anne\", \"relation\": \"editor\", \"object\": \"document:new-roadmap\", \"_description\": \"Anne is an editor of thew new-roadmap document\" }] For more examples, see Modeling Building Blocks: Concentric Relationships, Modeling: Roles and Permissions and Advanced Modeling: Google Drive.","s":"Referencing Other Relations On The Same Object","u":"/pr-preview/pr-921/docs/configuration-language","h":"#referencing-other-relations-on-the-same-object","p":414},{"i":423,"t":"Another set of indirect relationships are made possible by referencing relations to other objects. The syntax is X from Y and requires that: the other object is related to the current object as Y the user is related to another object as X See the authorization model below. DSL JSON model schema 1.1 type user type folder relations define viewer: [user, folder#viewer] type document relations define parent_folder: [folder] define viewer: [user] or viewer from parent_folder { \"schema_version\": \"1.1\", \"type_definitions\": [ { \"type\": \"user\" }, { \"type\": \"folder\", \"relations\": { \"viewer\": { \"this\": {} } }, \"metadata\": { \"relations\": { \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" }, { \"type\": \"folder\", \"relation\": \"viewer\" } ] } } } }, { \"type\": \"document\", \"relations\": { \"parent_folder\": { \"this\": {} }, \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"viewer\" } } } ] } } }, \"metadata\": { \"relations\": { \"parent_folder\": { \"directly_related_user_types\": [ { \"type\": \"folder\" } ] }, \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } The snippet below (taken from the authorization model above) states that viewers of a document are both (a) all users directly assigned the viewer relation and (b) all users who can view the document's parent folder. DSL JSON type document relations define viewer: [user] or viewer from parent_folder { \"type_definitions\": [ { \"type\": \"document\", \"relations\": { \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"tupleToUserset\": { \"tupleset\": { \"object\": \"\", \"relation\": \"parent_folder\" }, \"computedUserset\": { \"object\": \"\", \"relation\": \"viewer\" } } } ] } } }, \"metadata\": { \"relations\": { \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } In the authorization model above, user:anne is a viewer of document:new-roadmap if any one of the following relationship tuples sets exists: Anne is a viewer of the parent folder of the new-roadmap document [// planning folder is the parent folder of the new-roadmap document { \"user\": \"folder:planning\", \"relation\": \"parent_folder\", \"object\": \"document:new-roadmap\", \"_description\": \"planning folder is the parent folder of the new-roadmap document\" }// anne is a viewer of the planning folder { \"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"folder:planning\", \"_description\": \"anne is a viewer of the planning folder\" }] Anne is a viewer of the new-roadmap document (direct relationship) [// anne is a viewer of the new-roadmap document { \"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\", \"_description\": \"anne is a viewer of the new-roadmap document\" }] Referencing relations on related objects defines transitive implied relationship. If User A is related to Object B as a viewer, and Object B is related to Object C as parent, then User A is related to Object C as viewer. This can indicate that viewers of a folders are viewers of all documents in that folder. caution OpenFGA does not allow the referenced relation (the word after from, also called the tupleset) to reference another relation and does not allow non-concrete types (type bound public access (:*) or usersets (#)) in its type restrictions; adding them throws a validation error when calling WriteAuthorizationModel. For more examples, see Modeling: Parent-Child Objects, Advanced Modeling: Google Drive, Advanced Modeling: GitHub, and Advanced Modeling: Entitlements.","s":"Referencing Relations On Related Objects","u":"/pr-preview/pr-921/docs/configuration-language","h":"#referencing-relations-on-related-objects","p":414},{"i":425,"t":"The union operator (or in the DSL, union in the JSON syntax) indicates that a relationship exists if the user is in any of the sets of users (union). DSL JSON type document relations define viewer: [user] or editor { \"type_definitions\": [ { \"type\": \"document\", \"relations\": { \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"relation\": \"editor\" } } ] } } }, \"metadata\": { \"relations\": { \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } In the type definition snippet above, user:anne is a viewer of document:new-roadmap if any of the following conditions are satisfied: there exists a direct relationship with anne as editor of document:new-roadmap [{ \"user\": \"user:anne\", \"relation\": \"editor\", \"object\": \"document:new-roadmap\" }] anne is a viewer of document:new-roadmap [{ \"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\" }] info The above authorization model indicates that a user is related as a viewer if they are in any of the following: the userset of all users related to the object as \"viewer\", indicating that a user can be assigned a direct viewer relation the userset of all users related to the object as \"editor\", indicating that a user who is an editor is also implicitly a viewer If anne is in at least one of those usersets, meaning anne is either an editor or a viewer, the check on {\"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\"} returns {\"allowed\": true}. For more examples, see Modeling Building Blocks: Concentric Relationships, Modeling Roles and Permissions and Advanced Modeling: Modeling for IoT.","s":"The Union Operator","u":"/pr-preview/pr-921/docs/configuration-language","h":"#the-union-operator","p":414},{"i":427,"t":"The intersection operator (and in the DSL, intersection in the JSON syntax) indicates that a relationship exists if the user is in all the sets of users. DSL JSON type document relations define viewer: authorized_user and editor { \"type_definitions\": [ { \"type\": \"document\", \"relations\": { \"viewer\": { \"intersection\": { \"child\": [ { \"computedUserset\": { \"relation\": \"authorized_user\" } }, { \"computedUserset\": { \"relation\": \"editor\" } } ] } } }, \"metadata\": { \"relations\": { \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } In the type definition snippet above, user:anne is a viewer of document:new-roadmap if all of the following conditions are satisfied: anne is an editor of document:new-roadmap [{ \"user\": \"user:anne\", \"relation\": \"editor\", \"object\": \"document:new-roadmap\" }] AND anne is an authorized_user of document:new-roadmap: [{ \"user\": \"user:anne\", \"relation\": \"authorized_user\", \"object\": \"document:new-roadmap\" }] info The above authorization model indicates that a user is related as a viewer if they are in all of the following: the userset of all users related to the object as authorized_user the userset of all users related to the object as editor anne must be in the intersection of the usersets (meaning both an editor AND an authorized_user) for the check on {\"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\"} to return {\"allowed\": true}. anne is not a viewer for document:new-roadmap if either of the following is true: anne is not an editor to document:new-roadmap: no relationship tuple of {\"user\": \"user:anne\", \"relation\": \"editor\", \"object\": \"document:new-roadmap\"} anne is not an authorized_user on the document:new-roadmap: no relationship tuple of {\"user\": \"user:anne\", \"relation\": \"authorized_user\", \"object\": \"document:new-roadmap\"} For more examples, see Modeling with Multiple Restrictions.","s":"The Intersection Operator","u":"/pr-preview/pr-921/docs/configuration-language","h":"#the-intersection-operator","p":414},{"i":429,"t":"The exclusion operator (but not in the DSL, difference in the JSON syntax) indicates that a relationship exists if the user is in the base userset, but not in the excluded userset. It's helpful when modeling exclusion or block lists. DSL JSON type document relations define viewer: [user] but not blocked { \"type_definitions\": [ { \"type\": \"document\", \"relations\": { \"viewer\": { \"difference\": { \"base\": { \"this\": {} }, \"subtract\": { \"computedUserset\": { \"relation\": \"blocked\" } } } } }, \"metadata\": { \"relations\": { \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } In the type definition snippet above, user:anne is a viewer of document:new-roadmap if: anne has a direct relationship as viewer to document:new-roadmap [{ \"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\" }] AND anne is not blocked from document:new-roadmap; the following relation tuple does not exist: [{ \"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:new-roadmap\" }] For more information, see Modeling: Blocklists. info The authorization model above indicates that a user is related as a viewer if they are in: the userset of all users related to the object as viewer but not in: the userset of all users related to the object as blocked anne must be both a viewer and not blocked for the check on {\"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\"} to return {\"allowed\": true}. anne is not a viewer for document:new-roadmap if either of the following is true: anne is not assigned direct relationship as viewer to document:new-roadmap: no relationship tuple of {\"user\": \"user:anne\", \"relation\": \"viewer\", \"object\": \"document:new-roadmap\"} anne is blocked on the document:new-roadmap {\"user\": \"user:anne\", \"relation\": \"blocked\", \"object\": \"document:new-roadmap\"}","s":"The Exclusion Operator","u":"/pr-preview/pr-921/docs/configuration-language","h":"#the-exclusion-operator","p":414},{"i":431,"t":"The JSON syntax accepted by the OpenFGA API closely mirrors the syntax represented in the Zanzibar paper. The major modifications are a slight flattening and conversion of keys from snake_case to camelCase. Zanzibar OpenFGA JSON OpenFGA DSL this this [,] union union or intersection intersection and exclusion difference but not tuple_to_userset tupleToUserset x from y The Zanzibar paper presents this example: name: \"doc\" relation { name: \"owner\" } relation { name: \"editor\" userset_rewrite { union { child { _this {} } child { computed_userset { relation: \"owner\" } } }}} relation { name: \"viewer\" userset_rewrite { union { child { _this {} } child { computed_userset { relation: \"editor\" } } child { tuple_to_userset { tupleset { relation: \"parent\" } computed_userset { object: $TUPLE_USERSET_OBJECT # parent folder relation: \"viewer\" }}} }}} In the OpenFGA DSL, it becomes: model schema 1.1 type doc relations define owner: [user] define editor: [user] or owner define viewer: [user] or editor or viewer from parent In the OpenFGA JSON, it becomes: { \"schema_version\": \"1.1\", \"type_definitions\": [ { \"type\": \"doc\", \"relations\": { \"owner\": { \"this\": {} }, \"editor\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"relation\": \"owner\" } } ] } }, \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"relation\": \"editor\" } }, { \"tupleToUserset\": { \"tupleset\": { \"relation\": \"parent\" }, \"computedUserset\": { \"relation\": \"viewer\" } } } ] } } }, \"metadata\": { \"relations\": { \"owner\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"editor\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } The following snippet: DSL JSON model schema 1.1 type doc relations define viewer: [user] or editor or viewer from parent { \"schema_version\": \"1.1\", \"type_definitions\": [ { \"type\": \"doc\", \"relations\": { \"viewer\": { \"union\": { \"child\": [ { \"this\": {} }, { \"computedUserset\": { \"relation\": \"editor\" } }, { \"tupleToUserset\": { \"tupleset\": { \"relation\": \"parent\" }, \"computedUserset\": { \"relation\": \"viewer\" } } } ] } } }, \"metadata\": { \"relations\": { \"viewer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } Results in the following outcome: The users with a viewer relationship to a certain doc are any of: the set of users who are directly related with this doc as viewer the set of users who are related to this doc as editor the set of users who are related to any object OBJ_1 as viewer, where object OBJ_1 is any object related to this doc as parent (e.g. viewers of this doc's parent folder, where the parent folder is OBJ_1) Learn more about Zanzibar at the Zanzibar Academy.","s":"Equivalent Zanzibar Concepts","u":"/pr-preview/pr-921/docs/configuration-language","h":"#equivalent-zanzibar-concepts","p":414},{"i":433,"t":"Check the following sections for more on how to use the configuration language in modeling authorization. OpenFGA Concepts Learn about the OpenFGA Concepts. More Modeling: Getting Started Learn about how to get started with modeling your permission system in OpenFGA. More Direct Access Learn about modeling user access to an object. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/configuration-language","h":"#related-sections","p":414},{"i":435,"t":"This article explains how to configure an authorization model for a store in an OpenFGA server.","s":"Configure Authorization Model for a Store","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"","p":434},{"i":437,"t":"Node.js Go .NET Python Java CLI curl Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK, created the store and setup the SDK client. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK, created the store and setup the SDK client. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK, created the store and setup the SDK client. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK, created the store and setup the SDK client. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK, created the store and setup the SDK client. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the CLI, created the store and setup your environment variables. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have created the store and have loaded FGA_STORE_ID and FGA_API_URL as environment variables.","s":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"#before-you-start","p":434},{"i":439,"t":"Assume that you want to configure your store with the following model. DSL JSON model schema 1.1 type user type document relations define reader: [user] define writer: [user] define owner: [user] { \"schema_version\": \"1.1\", \"type_definitions\": [ { \"type\": \"user\" }, { \"type\": \"document\", \"relations\": { \"reader\": { \"this\": {} }, \"writer\": { \"this\": {} }, \"owner\": { \"this\": {} } }, \"metadata\": { \"relations\": { \"reader\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"writer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"owner\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] } To configure authorization model, we can invoke the write authorization models API. Node.js Go .NET Python Java CLI curl Initialize the SDK // ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional. // import the SDK const { OpenFgaClient } = require('@openfga/sdk'); // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example storeId: process.env.FGA_STORE_ID, authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request }); const { authorization_model_id: id } = await fgaClient.writeAuthorizationModel({ \"schema_version\": \"1.1\", \"type_definitions\": [ { \"type\": \"user\" }, { \"type\": \"document\", \"relations\": { \"reader\": { \"this\": {} }, \"writer\": { \"this\": {} }, \"owner\": { \"this\": {} } }, \"metadata\": { \"relations\": { \"reader\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"writer\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] }, \"owner\": { \"directly_related_user_types\": [ { \"type\": \"user\" } ] } } } } ] }); // id = \"01HVMMBCMGZNT3SED4Z17ECXCA\" Initialize the SDK // ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional. import ( \"os\" . \"github.com/openfga/go-sdk\" . \"github.com/openfga/go-sdk/client\" ) func main() { // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options fgaClient, err := NewSdkClient(&ClientConfiguration{ ApiUrl: os.Getenv(\"FGA_API_URL\"), // required, e.g. https://api.fga.example StoreId: os.Getenv(\"FGA_STORE_ID\"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods AuthorizationModelId: os.Getenv(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }) if err != nil { // .. Handle error } } var writeAuthorizationModelRequestString = \"{\\\"schema_version\\\":\\\"1.1\\\",\\\"type_definitions\\\":[{\\\"type\\\":\\\"user\\\"},{\\\"type\\\":\\\"document\\\",\\\"relations\\\":{\\\"reader\\\":{\\\"this\\\":{}},\\\"writer\\\":{\\\"this\\\":{}},\\\"owner\\\":{\\\"this\\\":{}}},\\\"metadata\\\":{\\\"relations\\\":{\\\"reader\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"writer\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"owner\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]}}}}]}\" var body WriteAuthorizationModelRequest if err := json.Unmarshal([]byte(writeAuthorizationModelRequestString), &body); err != nil { // .. Handle error return } data, err := fgaClient.WriteAuthorizationModel(context.Background()). Body(body). Execute() if err != nil { // .. Handle error } // data.AuthorizationModelId = \"01HVMMBCMGZNT3SED4Z17ECXCA\" Initialize the SDK // ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional. // import the SDK using OpenFga.Sdk.Client; using OpenFga.Sdk.Client.Model; using OpenFga.Sdk.Model; using Environment = System.Environment; namespace Example; class Example { public static async Task Main() { // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options var configuration = new ClientConfiguration() { ApiUrl = Environment.GetEnvironmentVariable(\"FGA_API_URL\"), ?? \"http://localhost:8080\", // required, e.g. https://api.fga.example StoreId = Environment.GetEnvironmentVariable(\"FGA_STORE_ID\"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods AuthorizationModelId = Environment.GetEnvironmentVariable(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }; var fgaClient = new OpenFgaClient(configuration); } } var modelJson = \"{\\\"schema_version\\\":\\\"1.1\\\",\\\"type_definitions\\\":[{\\\"type\\\":\\\"user\\\"},{\\\"type\\\":\\\"document\\\",\\\"relations\\\":{\\\"reader\\\":{\\\"this\\\":{}},\\\"writer\\\":{\\\"this\\\":{}},\\\"owner\\\":{\\\"this\\\":{}}},\\\"metadata\\\":{\\\"relations\\\":{\\\"reader\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"writer\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"owner\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]}}}}]}\"; var body = JsonSerializer.Deserialize(modelJson); var response = await fgaClient.WriteAuthorizationModel(body); // response.AuthorizationModelId = \"01HVMMBCMGZNT3SED4Z17ECXCA\" Initialize the SDK # ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional. import asyncio import os import json from openfga_sdk.client import ClientConfiguration, OpenFgaClient async def main(): configuration = ClientConfiguration( api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request ) # Enter a context with an instance of the OpenFgaClient async with OpenFgaClient(configuration) as fga_client: api_response = await fga_client.read_authorization_models() await fga_client.close() asyncio.run(main()) # from openfga_sdk.models.write_authorization_model_request import WriteAuthorizationModelRequest async def write_authorization_model(): body_string = \"{\\\"schema_version\\\":\\\"1.1\\\",\\\"type_definitions\\\":[{\\\"type\\\":\\\"user\\\"},{\\\"type\\\":\\\"document\\\",\\\"relations\\\":{\\\"reader\\\":{\\\"this\\\":{}},\\\"writer\\\":{\\\"this\\\":{}},\\\"owner\\\":{\\\"this\\\":{}}},\\\"metadata\\\":{\\\"relations\\\":{\\\"reader\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"writer\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"owner\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]}}}}]}\" response = await fga_client_instance.write_authorization_model(json.loads(body)) # response.authorization_model_id = \"01HVMMBCMGZNT3SED4Z17ECXCA\" Initialize the SDK // ApiTokenIssuer, ApiAudience, ClientId and ClientSecret are optional. import dev.openfga.sdk.api.client.OpenFgaClient; import dev.openfga.sdk.api.configuration.ClientConfiguration; public class Example { public static void main(String[] args) throws Exception { var config = new ClientConfiguration() .apiUrl(System.getenv(\"FGA_API_URL\")) // If not specified, will default to \"https://localhost:8080\" .storeId(System.getenv(\"FGA_STORE_ID\")) // Not required when calling createStore() or listStores() .authorizationModelId(System.getenv(\"FGA_AUTHORIZATION_MODEL_ID\")); // Optional, can be overridden per request var fgaClient = new OpenFgaClient(config); } } // import com.fasterxml.jackson.databind.ObjectMapper; // import dev.openfga.sdk.api.model.WriteAuthorizationModelRequest; var mapper = new ObjectMapper().findAndRegisterModules(); var authorizationModel = fgaClient .writeAuthorizationModel(mapper.readValue(\"{\\\"schema_version\\\":\\\"1.1\\\",\\\"type_definitions\\\":[{\\\"type\\\":\\\"user\\\"},{\\\"type\\\":\\\"document\\\",\\\"relations\\\":{\\\"reader\\\":{\\\"this\\\":{}},\\\"writer\\\":{\\\"this\\\":{}},\\\"owner\\\":{\\\"this\\\":{}}},\\\"metadata\\\":{\\\"relations\\\":{\\\"reader\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"writer\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]},\\\"owner\\\":{\\\"directly_related_user_types\\\":[{\\\"type\\\":\\\"user\\\"}]}}}}]}\", WriteAuthorizationModelRequest.class)) .get(); Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example) Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example) fga model write --store-id=${FGA_STORE_ID} --format=json '{\"schema_version\":\"1.1\",\"type_definitions\":[{\"type\":\"user\"},{\"type\":\"document\",\"relations\":{\"reader\":{\"this\":{}},\"writer\":{\"this\":{}},\"owner\":{\"this\":{}}},\"metadata\":{\"relations\":{\"reader\":{\"directly_related_user_types\":[{\"type\":\"user\"}]},\"writer\":{\"directly_related_user_types\":[{\"type\":\"user\"}]},\"owner\":{\"directly_related_user_types\":[{\"type\":\"user\"}]}}}}]}' Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example) Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example) curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/authorization-models \\ -H \"Authorization: Bearer $FGA_API_TOKEN\" \\ # Not needed if service does not require authorization -H \"content-type: application/json\" \\ -d '{\"schema_version\":\"1.1\",\"type_definitions\":[{\"type\":\"user\"},{\"type\":\"document\",\"relations\":{\"reader\":{\"this\":{}},\"writer\":{\"this\":{}},\"owner\":{\"this\":{}}},\"metadata\":{\"relations\":{\"reader\":{\"directly_related_user_types\":[{\"type\":\"user\"}]},\"writer\":{\"directly_related_user_types\":[{\"type\":\"user\"}]},\"owner\":{\"directly_related_user_types\":[{\"type\":\"user\"}]}}}}]}' The API will then return the authorization model ID. Note The OpenFGA API only accepts an authorization model in the API's JSON syntax. To convert between the API Syntax and the friendly DSL, you can use the FGA CLI.","s":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"#step-by-step","p":434},{"i":441,"t":"Take a look at the following sections for more information on how to configure authorization model in your store. Getting Started with Modeling Read how to get started with modeling. More Modeling: Direct Relationships Read the basics of modeling authorization and granting access to users. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/configure-model","h":"#related-sections","p":434},{"i":443,"t":"A store is a OpenFGA entity that contains your authorization data. You will need to create a store in OpenFGA before adding an authorization model and relationship tuples to it. This article explains how to set up an OpenFGA store.","s":"Create a Store","u":"/pr-preview/pr-921/docs/getting-started/create-store","h":"","p":442},{"i":445,"t":"Node.js Go .NET Python Java CLI curl const { OpenFgaClient } = require('@openfga/sdk'); // OR import { OpenFgaClient } from '@openfga/sdk'; const openFga = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example }); const { id: storeId } = await openFga.createStore({ name: \"FGA Demo Store\", }); import ( \"context\" \"os\" . \"github.com/openfga/go-sdk/client\" ) func main() { fgaClient, err := NewSdkClient(&ClientConfiguration{ ApiUrl: os.Getenv(\"FGA_API_URL\"), // required, e.g. https://api.fga.example StoreId: os.Getenv(\"FGA_STORE_ID\"), // optional, not needed for \\`CreateStore\\` and \\`ListStores\\`, required before calling for all other methods AuthorizationModelId: os.Getenv(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }) if err != nil { // .. Handle error } resp, err := fgaClient.CreateStore(context.Background()).Body(ClientCreateStoreRequest{Name: \"FGA Demo\"}).Execute() if err != nil { // .. Handle error } } using OpenFga.Sdk.Client; using OpenFga.Sdk.Client.Model; using OpenFga.Sdk.Model; using Environment = System.Environment; namespace ExampleApp; class MyProgram { static async Task Main() { var configuration = new ClientConfiguration() { ApiUrl = Environment.GetEnvironmentVariable(\"FGA_API_URL\") ?? \"http://localhost:8080\", // required, e.g. https://api.fga.example StoreId = Environment.GetEnvironmentVariable(\"FGA_STORE_ID\"), // optional, not needed for \\`CreateStore\\` and \\`ListStores\\`, required before calling for all other methods AuthorizationModelId = Environment.GetEnvironmentVariable(\"FGA_MODEL_ID\"), // optional, can be overridden per request }; var fgaClient = new OpenFgaClient(configuration); var store = await fgaClient.CreateStore(new ClientCreateStoreRequest(){Name = \"FGA Demo Store\"}); } } import asyncio import os import openfga_sdk from openfga_sdk.client import OpenFgaClient from openfga_sdk.models.create_store_request import CreateStoreRequest async def main(): configuration = openfga_sdk.ClientConfiguration( api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example ) async with OpenFgaClient(configuration) as fga_client: body = CreateStoreRequest( name = \"FGA Demo Store\", ) response = await fga_client.create_store(body) asyncio.run(main()) import dev.openfga.sdk.api.client.OpenFgaClient; import dev.openfga.sdk.api.configuration.ClientConfiguration; import dev.openfga.sdk.api.model.CreateStoreRequest; public class Example { public static void main(String[] args) { var config = new ClientConfiguration() .apiUrl(System.getenv(\"FGA_API_URL\")) // If not specified, will default to \"https://localhost:8080\" .storeId(System.getenv(\"FGA_STORE_ID\")) // Not required when calling createStore() or listStores() .authorizationModelId(System.getenv(\"FGA_AUTHORIZATION_MODEL_ID\")); // Optional, can be overridden per request var fgaClient = new OpenFgaClient(config); var body = new CreateStoreRequest().name(\"FGA Demo Store\"); var store = fgaClient.createStore(body).get(); } } fga store create --name \"FGA Demo Store\" # To create the store and directly put the Store ID into an env variable: # export FGA_STORE_ID=$(fga store create --name \"FGA Demo Store\" | jq -r .store.id) curl -X POST $FGA_API_URL/stores \\ -H \"content-type: application/json\" \\ -d '{\"name\": \"FGA Demo Store\"}'","s":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/create-store","h":"#step-by-step","p":442},{"i":447,"t":"The OpenFGA SDK Client supports telemetry data collection using OpenTelemetry.","s":"Configure SDK Client Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"","p":446},{"i":449,"t":"Install the OpenFGA SDK Client Setup OpenTelemetry Install the OpenTelemetry SDK dependencies for your application Instantiate the OpenTelemetry SDK in your application Once you have completed these steps, the OpenFGA SDK Client will automatically collect telemetry data using your application's OpenTelemetry configuration.","s":"Enabling Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#enabling-telemetry","p":446},{"i":451,"t":"The OpenFGA SDK Client will automatically use a default configuration for telemetry collection. You can provide your own configuration to include additional metrics or to exclude metrics that are not relevant to your application. Node.js Go .NET Python Java import 'dotenv/config'; import { OpenFgaClient, TelemetryAttribute, TelemetryConfiguration, TelemetryMetric } from '@openfga/sdk'; const telemetryConfig = { metrics: { [TelemetryMetric.CounterCredentialsRequest]: { attributes: new Set([ TelemetryAttribute.UrlScheme, TelemetryAttribute.UserAgentOriginal, TelemetryAttribute.HttpRequestMethod, TelemetryAttribute.FgaClientRequestClientId, TelemetryAttribute.FgaClientRequestStoreId, TelemetryAttribute.FgaClientRequestModelId, TelemetryAttribute.HttpRequestResendCount, ]), }, [TelemetryMetric.HistogramRequestDuration]: { attributes: new Set([ TelemetryAttribute.HttpResponseStatusCode, TelemetryAttribute.UserAgentOriginal, TelemetryAttribute.FgaClientRequestMethod, TelemetryAttribute.FgaClientRequestClientId, TelemetryAttribute.FgaClientRequestStoreId, TelemetryAttribute.FgaClientRequestModelId, TelemetryAttribute.HttpRequestResendCount, ]), }, [TelemetryMetric.HistogramQueryDuration]: { attributes: new Set([ TelemetryAttribute.HttpResponseStatusCode, TelemetryAttribute.UserAgentOriginal, TelemetryAttribute.FgaClientRequestMethod, TelemetryAttribute.FgaClientRequestClientId, TelemetryAttribute.FgaClientRequestStoreId, TelemetryAttribute.FgaClientRequestModelId, TelemetryAttribute.HttpRequestResendCount, ]), }, }, }; const fgaClient = new OpenFgaClient({ telemetry: telemetryConfig, // ... }); import ( \"github.com/openfga/go-sdk/client\" \"github.com/openfga/go-sdk/telemetry\" ) otel := telemetry.Configuration{ Metrics: &telemetry.MetricsConfiguration{ METRIC_COUNTER_CREDENTIALS_REQUEST: &telemetry.MetricConfiguration{ ATTR_FGA_CLIENT_REQUEST_CLIENT_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_REQUEST_METHOD: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_REQUEST_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_REQUEST_STORE_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_RESPONSE_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_HOST: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_REQUEST_RESEND_COUNT: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_RESPONSE_STATUS_CODE: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_URL_FULL: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_URL_SCHEME: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_USER_AGENT_ORIGINAL: &telemetry.AttributeConfiguration{Enabled: true}, }, METRIC_HISTOGRAM_REQUEST_DURATION: &telemetry.MetricConfiguration{ ATTR_FGA_CLIENT_REQUEST_CLIENT_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_REQUEST_METHOD: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_REQUEST_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_REQUEST_STORE_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_RESPONSE_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_HOST: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_REQUEST_RESEND_COUNT: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_RESPONSE_STATUS_CODE: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_URL_FULL: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_URL_SCHEME: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_USER_AGENT_ORIGINAL: &telemetry.AttributeConfiguration{Enabled: true}, }, METRIC_HISTOGRAM_QUERY_DURATION: &telemetry.MetricConfiguration{ ATTR_FGA_CLIENT_REQUEST_CLIENT_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_REQUEST_METHOD: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_REQUEST_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_REQUEST_STORE_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_FGA_CLIENT_RESPONSE_MODEL_ID: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_HOST: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_REQUEST_RESEND_COUNT: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_HTTP_RESPONSE_STATUS_CODE: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_URL_FULL: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_URL_SCHEME: &telemetry.AttributeConfiguration{Enabled: true}, ATTR_USER_AGENT_ORIGINAL: &telemetry.AttributeConfiguration{Enabled: true}, }, }, } fgaClient, err := client.NewSdkClient(&client.ClientConfiguration{ Telemetry: &otel, // ... }) using OpenFga.Sdk.Client; using OpenFga.Sdk.Configuration; using OpenFga.Sdk.Telemetry; TelemetryConfig telemetryConfig = new TelemetryConfig() { Metrics = new Dictionary { [TelemetryMeter.RequestDuration] = new () { Attributes = new HashSet { TelemetryAttribute.HttpStatus, TelemetryAttribute.HttpUserAgent, TelemetryAttribute.RequestMethod, TelemetryAttribute.RequestClientId, TelemetryAttribute.RequestStoreId, TelemetryAttribute.RequestModelId, TelemetryAttribute.RequestRetryCount, }, }, }, }; var configuration = new ClientConfiguration { Telemetry = telemetryConfig, // ... }; var fgaClient = new OpenFgaClient(configuration); from openfga_sdk import ( ClientConfiguration, OpenFgaClient, ) telemetry_config: dict[str, dict[str, dict[str, bool]]] = { \"metrics\": { \"fga-client.request.duration\": { \"fga-client.request.model_id\": False, \"fga-client.response.model_id\": False, \"fga-client.user\": True, \"http.client.request.duration\": True, \"http.server.request.duration\": True, }, }, } configuration = ClientConfiguration( telemetry=telemetry_config, // ... ) with OpenFgaClient(configuration) as fga_client: # ... import dev.openfga.sdk.api.client.ApiClient; import dev.openfga.sdk.api.configuration.ClientConfiguration; import dev.openfga.sdk.api.configuration.TelemetryConfiguration; Map> attributes = new HashMap<>(); attributes.put(Attributes.FGA_CLIENT_REQUEST_CLIENT_ID, Optional.empty()); attributes.put(Attributes.FGA_CLIENT_REQUEST_METHOD, Optional.empty()); attributes.put(Attributes.FGA_CLIENT_REQUEST_MODEL_ID, Optional.empty()); attributes.put(Attributes.FGA_CLIENT_REQUEST_STORE_ID, Optional.empty()); attributes.put(Attributes.FGA_CLIENT_RESPONSE_MODEL_ID, Optional.empty()); attributes.put(Attributes.HTTP_HOST, Optional.empty()); attributes.put(Attributes.HTTP_REQUEST_METHOD, Optional.empty()); attributes.put(Attributes.HTTP_REQUEST_RESEND_COUNT, Optional.empty()); attributes.put(Attributes.HTTP_RESPONSE_STATUS_CODE, Optional.empty()); attributes.put(Attributes.URL_FULL, Optional.empty()); attributes.put(Attributes.URL_SCHEME, Optional.empty()); attributes.put(Attributes.USER_AGENT, Optional.empty()); Map>> metrics = new HashMap<>(); metrics.put(Counters.CREDENTIALS_REQUEST, attributes); metrics.put(Histograms.QUERY_DURATION, attributes); metrics.put(Histograms.REQUEST_DURATION, attributes); ClientConfiguration config = new ClientConfiguration() // ... .telemetryConfiguration(new TelemetryConfiguration(metrics); OpenFgaClient fgaClient = new OpenFgaClient(config);","s":"Customizing Telemetry","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#customizing-telemetry","p":446},{"i":453,"t":"We provide example applications for using telemetry with the OpenFGA SDK Client. Node.js Go .NET Python","s":"Examples","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#examples","p":446},{"i":455,"t":"The OpenFGA SDK Client can collect the following metrics: Metric Name Type Enabled by Default Description fga-client.request.duration Histogram Yes Total request time for FGA requests, in milliseconds fga-client.query.duration Histogram Yes Time taken by the FGA server to process and evaluate the request, in milliseconds fga-client.credentials.request Counter Yes Total number of new token requests initiated using the Client Credentials flow","s":"Supported Metrics","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#supported-metrics","p":446},{"i":457,"t":"The OpenFGA SDK Client can collect the following attributes: Attribute Name Type Enabled by Default Description fga-client.request.client_id string Yes Client ID associated with the request, if any fga-client.request.method string Yes FGA method/action that was performed (e.g., Check, ListObjects) in TitleCase fga-client.request.model_id string Yes Authorization model ID that was sent as part of the request, if any fga-client.request.store_id string Yes Store ID that was sent as part of the request fga-client.response.model_id string Yes Authorization model ID that the FGA server used fga-client.user string No User associated with the action of the request for check and list users http.client.request.duration int No Duration for the SDK to complete the request, in milliseconds http.host string Yes Host identifier of the origin the request was sent to http.request.method string Yes HTTP method for the request http.request.resend_count int Yes Number of retries attempted, if any http.response.status_code int Yes Status code of the response (e.g., 200 for success) http.server.request.duration int No Time taken by the FGA server to process and evaluate the request, in milliseconds url.scheme string Yes HTTP scheme of the request (http/https) url.full string Yes Full URL of the request user_agent.original string Yes User Agent used in the query","s":"Supported Attributes","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#supported-attributes","p":446},{"i":459,"t":"OpenFGA supports tracing with OpenTelemetry. If your application uses OpenTelemetry tracing, traces will be propagated to OpenFGA, provided the traces are exported to the same address. This can be useful to help diagnose any suspected performance issues when using OpenFGA. If your application does not already use tracing, OpenTelemetry offers zero-code instrumentation for several languages. For example, a TypeScript application can be configured with tracing by using one of the OpenTelemetry JavaScript Instrumentation Libraries: npm install --save @opentelemetry/auto-instrumentations-node Create an initialization file to configure tracing: // tracing.ts import { NodeSDK } from '@opentelemetry/sdk-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter(), // registers all instrumentation packages, you may wish to change this instrumentations: [getNodeAutoInstrumentations()], }); sdk.start(); Run the application with the appropriate OTEL environment variables: OTEL_SERVICE_NAME='YOUR-SERVICE-NAME' ts-node -r ./tracing.ts YOUR-APP.ts See the OpenTelemetry documentation for additional information to configure your application for tracing.","s":"Tracing","u":"/pr-preview/pr-921/docs/getting-started/configure-telemetry","h":"#tracing","p":446},{"i":461,"t":"Authorization Models in OpenFGA are immutable, they are created once and then can no longer be deleted or modified. Each time you write an authorization model, a new version is created.","s":"Immutable Authorization Models","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"","p":460},{"i":463,"t":"You can list all the authorization models for a store using the ReadAuthorizationModels API. This endpoint returns the results sorted in reverse chronological order, as in the first model in the list is the latest model. By default, only the last 50 models are returned, but you can paginate across by passing in the appropriate continuation_token.","s":"Viewing all the authorization models","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#viewing-all-the-authorization-models","p":460},{"i":465,"t":"Some endpoints relating to tuples (Check, ListObjects, ListUsers, Expand, Write) accept an authorization_model_id, which we strongly recommend passing, especially in production. In practice, you would pin the authorization model ID alongside the store ID in your configuration management system. Your services would read this value and use it in their requests to FGA. This helps you ensure that your services are using the same consistent ID across all your applications, and that rollouts can be seamless.","s":"How to target a particular model","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#how-to-target-a-particular-model","p":460},{"i":467,"t":"Targeting a specific model ID would ensure that you don't accidentally break your authorization checks in production because a mistake was made when updating the authorization model. It would also slightly improve the latency on your check requests. If that field is passed, evaluation and validation will happen for that particular authorization model ID. If this field is not passed, OpenFGA will use the last created Authorization Model for that store.","s":"Benefits of passing in an authorization model ID","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#benefits-of-passing-in-an-authorization-model-id","p":460},{"i":470,"t":"Certain model changes require adapting your application code and migrating tuples before rolling it out. For example, if you rename a relation, you need to change the application and copy the existing tuples to use the new relation name. This scenario requires the following steps: Update the authorization model with the renamed relation. A new model ID will be generated but it won't be used in production yet. Update the application to use the new relation name. Copy existing tuples to use the new relation name. Deploy the new application targeting the new model ID. You can learn more about model migrations here.","s":"Complex model migrations","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#complex-model-migrations","p":460},{"i":472,"t":"Being able to target multiple versions of the authorization model enables you to progressively roll out model changes, which is something you should consider doing if the changes are significant. You could: Do shadow checks where you would perform checks against both your existing model and the new upcoming model you are hoping to replace it with.This will help you detect and resolve any accidental discrepancies you may be introducing, and ensure that your new model is at least as good as your old one. When you are confident with your model, you could implement gradual rollouts that would allow you to monitor and check if any users are having access issues before you go ahead and increase the rollout to 100% of your user base. Getting an Authorization Model's Creation Date The Authorization Model ID is a ULID which includes the date created. You can extract the creation date using a library for your particular language. For example, in JavaScript you can do the following: import ulid = require('ulid'); const time = ulid.decodeTime(id);","s":"Progresivelly rollout changes","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#progresivelly-rollout-changes","p":460},{"i":474,"t":"Learn more about modeling and production usage in OpenFGA. Configuration Language Learn about the OpenFGA Configuration Language. More Getting Started with Modeling Read how to get started with modeling. More Data and API Best Practices Learn the best practices for managing data and invoking APIs in production environment More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/immutable-models","h":"#related-sections","p":460},{"i":476,"t":"To get started, install the OpenFGA SDK packages. Node.js Go .NET Python Java CLI You can find the Node.js package on npm at: @openfga/sdk. Using npm: npm install @openfga/sdk Using yarn: yarn add @openfga/sdk You can find the Go package on GitHub at: @openfga/go-sdk. To install: go get -u github.com/openfga/go-sdk In your code, import the module and use it: import ( openfga \"github.com/openfga/go-sdk\" ) func main() { configuration, err := openfga.NewConfiguration(openfga.Configuration{ ApiUrl: os.Getenv(\"FGA_API_URL\"), // required, e.g. https://api.fga.example }) if err != nil { // .. Handle error } } You can then run go mod tidy to update go.mod and go.sum if you are using them. The OpenFGA .NET SDK is available on NuGet. You can install it using: The dotnet CLI: dotnet add package OpenFGA.Sdk The Package Manager Console inside Visual Studio: Install-Package OpenFGA.Sdk Visual Studio, Visual Studio for Mac and IntelliJ Rider: Search for and install OpenFGA.Sdk in each of their respective package manager UIs. The OpenFGA Python SDK is available on PyPI. To install: pip3 install openfga_sdk In your code, import the module and use it: import openfga_sdk You can find the Java package on Maven Central. Using Maven: dev.openfga openfga-sdk 0.3.1 Using Gradle: implementation 'dev.openfga:openfga-sdk:0.3.1' The OpenFGA CLI is available on GitHub. To install: Brew​ brew install openfga/tap/fga Linux (deb, rpm and apk) packages​ Download the .deb, .rpm or .apk packages from the releases page. Debian: sudo apt install ./fga__linux_.deb Fedora: sudo dnf install ./fga__linux_.rpm Alpine Linux: sudo apk add --allow-untrusted ./fga__linux_.apk Docker​ docker pull openfga/cli; docker run -it openfga/cli Go​ note that the command will be named cli go install github.com/openfga/cli@latest Manually​ Download the pre-compiled binaries from the releases page. check API","s":"Install SDK Client","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"","p":475},{"i":478,"t":"brew install openfga/tap/fga","s":"Brew","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#brew","p":475},{"i":480,"t":"Download the .deb, .rpm or .apk packages from the releases page. Debian: sudo apt install ./fga__linux_.deb Fedora: sudo dnf install ./fga__linux_.rpm Alpine Linux: sudo apk add --allow-untrusted ./fga__linux_.apk","s":"Linux (deb, rpm and apk) packages","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#linux-deb-rpm-and-apk-packages","p":475},{"i":482,"t":"docker pull openfga/cli; docker run -it openfga/cli","s":"Docker","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#docker","p":475},{"i":484,"t":"note that the command will be named cli go install github.com/openfga/cli@latest","s":"Go","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#go","p":475},{"i":486,"t":"Download the pre-compiled binaries from the releases page.","s":"Manually","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#manually","p":475},{"i":488,"t":"Get OpenFGA's SDKs to add authorization to your API. OpenFGA Node.js SDK Install our Node.js & JavaScript SDK to get started. More OpenFGA Go SDK Use our Go SDK to easily connect your Go application to the OpenFGA API More OpenFGA .NET SDK Connect your .NET service with OpenFGA using our .NET SDK More OpenFGA Python SDK Connect your Python service with OpenFGA using our Python SDK More OpenFGA Java SDK Connect your Java service with OpenFGA using our Java SDK More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/install-sdk","h":"#related-sections","p":475},{"i":490,"t":"This section will illustrate how to integrate OpenFGA within a framework, such as Fastify or Fiber.","s":"Integrate Within a Framework","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"","p":489},{"i":492,"t":"Node.js Go Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the OpenFGA SDK. You have configured the authorization model and updated the relationship tuples. You know how to perform a Check. You have loaded FGA_API_URL and FGA_STORE_ID as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the OpenFGA SDK. You have configured the authorization model and updated the relationship tuples. You know how to perform a Check. You have loaded FGA_API_URL and FGA_STORE_ID as environment variables.","s":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#before-you-start","p":489},{"i":494,"t":"Assume that you want to have a web service for documents using one of the frameworks mentioned above. The service will authenticate users via JWT tokens, which contain the user ID. Note The reader should set up their own login method based on their OpenID connect provider's documentation. Assume that you want to provide a route GET /read/{document} to return documents depending on whether the authenticated user has access to it.","s":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#step-by-step","p":489},{"i":496,"t":"The first step is to install the framework. Node.js Go For the context of this example, we will use the Fastify framework. For that we need to install the following packages: the fastify package that provides the framework itself the fastify-plugin package that allows integrating plugins with Fastify the fastify-jwt package for processing JWT tokens Using npm: npm install fastify fastify-plugin fastify-jwt Using yarn: yarn add fastify fastify-plugin fastify-jwt Next, we setup the web service with the GET /read/{document} route in file app.js. // Require the framework and instantiate it const fastify = require('fastify')({ logger: true }); // Declare the route fastify.get('/read/:document', async (request, reply) => { return { read: request.params.document }; }); // Run the server const start = async () => { try { await fastify.listen(3000); } catch (err) { fastify.log.error(err); process.exit(1); } }; start(); For the context of this example, we will use the Fiber framework. For that we need to install the following Go packages: the gofiber/fiber package that provides the Fiber framework itself the gofiber/jwt middleware authentication layer for JWT the golang-jwt package that provides Go support for JWT go get -u github.com/gofiber/fiber/v2 github.com/gofiber/jwt/v3 github.com/golang-jwt/jwt/v4 Next, we setup the web service with the GET /read/{document} route. package main import \"github.com/gofiber/fiber/v2\" func main() { app := fiber.New() app.Get(\"/read/:document\", read) app.Listen(\":3000\") } func read(c *fiber.Ctx) error { return c.SendString(c.Params(\"document\")) }","s":"01. Install and setup framework","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#01-install-and-setup-framework","p":489},{"i":498,"t":"Before we can call OpenFGA to protect the /read/{document} route, we need to validate the user's JWT. Node.js Go The fastify-jwt package allows validation of JWT tokens, as well as providing access to the user's identity. In jwt-authenticate.js: const fp = require('fastify-plugin'); module.exports = fp(async function (fastify, opts) { fastify.register(require('fastify-jwt'), { secret: { private: readFileSync(`${path.join(__dirname, 'certs')}/private.key`, 'utf8'), public: readFileSync(`${path.join(__dirname, 'certs')}/public.key`, 'utf8'), }, sign: { algorithm: 'RS256' }, }); fastify.decorate('authenticate', async function (request, reply) { try { await request.jwtVerify(); } catch (err) { reply.send(err); } }); }); Then, use the preValidation hook of a route to protect it and access the user information inside the JWT: In route-read.js: module.exports = async function (fastify, opts) { fastify.get( '/read/:document', { preValidation: [fastify.authenticate], }, async function (request, reply) { // the user's id is in request.user return { read: request.params.document }; }, ); }; Finally, update app.js to register the newly added hooks. const fastify = require('fastify')({ logger: true }); const jwtAuthenticate = require('./jwt-authenticate'); const routeread = require('./route-read'); fastify.register(jwtAuthenticate); fastify.register(routeread); // Run the server! const start = async () => { try { await fastify.listen(3000); } catch (err) { fastify.log.error(err); process.exit(1); } } start(); We will now setup middleware to authenticate the incoming JWTs. package main import ( \"crypto/rand\" \"crypto/rsa\" \"log\" \"github.com/gofiber/fiber/v2\" jwtware \"github.com/gofiber/jwt/v3\" \"github.com/golang-jwt/jwt/v4\" ) var ( // Do not do this in production. // In production, you would have the private key and public key pair generated // in advance. NEVER add a private key to any GitHub repo. privateKey *rsa.PrivateKey ) func main() { app := fiber.New() // Just as a demo, generate a new private/public key pair on each run. rng := rand.Reader var err error privateKey, err = rsa.GenerateKey(rng, 2048) if err != nil { log.Fatalf(\"rsa.GenerateKey: %v\", err) } // JWT Middleware app.Use(jwtware.New(jwtware.Config{ SigningMethod: \"RS256\", SigningKey: privateKey.Public(), })) app.Get(\"/read/:document\", read) app.Listen(\":3000\") } func read(c *fiber.Ctx) error { user := c.Locals(\"user\").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) name := claims[\"name\"].(string) return c.SendString(name + \" read \" + c.Params(\"document\")) }","s":"02. Authenticate and get user ID","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#02-authenticate-and-get-user-id","p":489},{"i":500,"t":"Node.js Go First, we will create a decorator preauthorize to parse the incoming HTTP method as well as name of the document, and set the appropriate relation and object that we will call Check on. In preauthorize.js: const fp = require('fastify-plugin'); module.exports = fp(async function (fastify, opts) { fastify.decorate('preauthorize', async function (request, reply) { try { switch (request.method) { case 'GET': request.relation = 'reader'; break; case 'POST': request.relation = 'writer'; break; case 'DELETE': default: request.relation = 'owner'; break; } request.object = `document:${request.params.document}`; } catch (err) { reply.send(err); } }); }); Next, we will create a decorator called authorize. This decorator will invoke the Check API to see if the user has a relationship with the specified document. In authorize.js: const fp = require('fastify-plugin'); const { OpenFgaClient } = require('@openfga/sdk'); // OR import { OpenFgaClient } from '@openfga/sdk'; module.exports = fp(async function (fastify, opts) { fastify.decorate('authorize', async function (request, reply) { try { // configure the openfga api client const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example storeId: process.env.FGA_STORE_ID, }); const { allowed } = await fgaClient.check({ user: request.user, relation: request.relation, object: request.object, }); if (!allowed) { reply.code(403).send(`forbidden`); } } catch (err) { reply.send(err); } }); }); We can now update the GET /read/{document} route to check for user permissions. In route-read.js: module.exports = async function (fastify, opts) { fastify.get( '/read/:document', { preValidation: [fastify.authenticate, fastify.preauthorize, fastify.authorize], }, async function (request, reply) { // the user's id is in request.user return { read: request.params.document }; }, ); }; Finally, we will register the new hooks in app.js: const fastify = require('fastify')({ logger: true }); const jwtAuthenticate = require('./jwt-authenticate'); const preauthorize = require('./preauthorize'); const authorize = require('./authorize'); const routeread = require('./route-read'); fastify.register(jwtAuthenticate); fastify.register(preauthorize); fastify.register(authorize); fastify.register(routeread); const start = async () => { try { await fastify.listen(3000); } catch (err) { fastify.log.error(err); process.exit(1); } } start(); We will create two middlewares: preauthorize will parse the user's JWT and prepare variables needed to call Check API. checkAuthorization will call the Check API to see if the user has a relationship with the specified document. package main import ( \"context\" \"crypto/rand\" \"crypto/rsa\" \"log\" \"os\" \"github.com/gofiber/fiber/v2\" jwtware \"github.com/gofiber/jwt/v3\" \"github.com/golang-jwt/jwt/v4\" . \"github.com/openfga/go-sdk/client\" ) var ( // Do not do this in production. // In production, you would have the private key and public key pair generated // in advance. NEVER add a private key to any GitHub repo. privateKey *rsa.PrivateKey ) func main() { app := fiber.New() // Just as a demo, generate a new private/public key pair on each run. rng := rand.Reader var err error privateKey, err = rsa.GenerateKey(rng, 2048) if err != nil { log.Fatalf(\"rsa.GenerateKey: %v\", err) } // JWT Middleware app.Use(jwtware.New(jwtware.Config{ SigningMethod: \"RS256\", SigningKey: privateKey.Public(), })) app.Use(\"/read/:document\", preauthorize) app.Use(checkAuthorization) app.Get(\"/read/:document\", read) app.Listen(\":3000\") } func read(c *fiber.Ctx) error { user := c.Locals(\"user\").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) name := claims[\"name\"].(string) return c.SendString(name + \" read \" + c.Params(\"document\")) } func preauthorize(c *fiber.Ctx) error { // get the user name from JWT user := c.Locals(\"user\").(*jwt.Token) claims := user.Claims.(jwt.MapClaims) name := claims[\"name\"].(string) c.Locals(\"username\", name) // parse the HTTP method switch (c.Method()) { case \"GET\": c.Locals(\"relation\", \"reader\") case \"POST\": c.Locals(\"relation\", \"writer\") case \"DELETE\": c.Locals(\"relation\", \"owner\") default: c.Locals(\"relation\", \"owner\") } // get the object name and prepend with type name \"document:\" c.Locals(\"object\", \"document:\" + c.Params(\"document\")) return c.Next() } // Middleware to check whether user is authorized to access document func checkAuthorization(c *fiber.Ctx) error { fgaClient, err := NewSdkClient(&ClientConfiguration{ ApiUrl: os.Getenv(\"FGA_API_URL\"), // required, e.g. https://api.fga.example StoreId: os.Getenv(\"FGA_STORE_ID\"), // optional, not needed for \\`CreateStore\\` and \\`ListStores\\`, required before calling for all other methods AuthorizationModelId: os.Getenv(\"FGA_MODEL_ID\"), // optional, can be overridden per request }) if err != nil { return fiber.NewError(fiber.StatusServiceUnavailable, \"Unable to build OpenFGA client\") } body := ClientCheckRequest{ User: c.Locals(\"username\").(string), Relation: c.Locals(\"relation\").(string), Object: c.Locals(\"object\").(string), } data, err := fgaClient.Check(context.Background()).Body(body).Execute() if err != nil { return fiber.NewError(fiber.StatusServiceUnavailable, \"Unable to check for authorization\") } if !(*data.Allowed) { return fiber.NewError(fiber.StatusForbidden, \"Forbidden to access document\") } // Go to the next middleware return c.Next() }","s":"03. Integrate the OpenFGA check API into the service","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#03-integrate-the--check-api-into-the-service","p":489},{"i":502,"t":"Take a look at the following sections for examples that you can try when integrating with SDK. Entitlements Modeling Entitlements for a System in OpenFGA. More IoT Modeling Fine Grained Authorization for an IoT Security Camera System with OpenFGA. More Slack Modeling Authorization for Slack with OpenFGA. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/framework","h":"#related-sections","p":489},{"i":504,"t":"This section will illustrate how to perform a check request to determine whether a user has a certain relationship with an object.","s":"Perform a Check","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"","p":503},{"i":506,"t":"Node.js Go .NET Python Java CLI curl Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have configured the authorization model. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables.","s":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#before-you-start","p":503},{"i":508,"t":"Assume that you want to check whether user anne has relationship reader with object document:Z","s":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#step-by-step","p":503},{"i":510,"t":"Before calling the check API, you will need to configure the API client. Node.js Go .NET Python Java CLI curl // import the SDK const { OpenFgaClient } = require('@openfga/sdk'); // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example storeId: process.env.FGA_STORE_ID, authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request }); import ( \"os\" . \"github.com/openfga/go-sdk\" . \"github.com/openfga/go-sdk/client\" ) func main() { // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options fgaClient, err := NewSdkClient(&ClientConfiguration{ ApiUrl: os.Getenv(\"FGA_API_URL\"), // required, e.g. https://api.fga.example StoreId: os.Getenv(\"FGA_STORE_ID\"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods AuthorizationModelId: os.Getenv(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }) if err != nil { // .. Handle error } } // import the SDK using OpenFga.Sdk.Client; using OpenFga.Sdk.Client.Model; using OpenFga.Sdk.Model; using Environment = System.Environment; namespace Example; class Example { public static async Task Main() { // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options var configuration = new ClientConfiguration() { ApiUrl = Environment.GetEnvironmentVariable(\"FGA_API_URL\"), ?? \"http://localhost:8080\", // required, e.g. https://api.fga.example StoreId = Environment.GetEnvironmentVariable(\"FGA_STORE_ID\"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods AuthorizationModelId = Environment.GetEnvironmentVariable(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }; var fgaClient = new OpenFgaClient(configuration); } } import asyncio import os import json from openfga_sdk.client import ClientConfiguration, OpenFgaClient async def main(): configuration = ClientConfiguration( api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request ) # Enter a context with an instance of the OpenFgaClient async with OpenFgaClient(configuration) as fga_client: api_response = await fga_client.read_authorization_models() await fga_client.close() asyncio.run(main()) import dev.openfga.sdk.api.client.OpenFgaClient; import dev.openfga.sdk.api.configuration.ClientConfiguration; public class Example { public static void main(String[] args) throws Exception { var config = new ClientConfiguration() .apiUrl(System.getenv(\"FGA_API_URL\")) // If not specified, will default to \"https://localhost:8080\" .storeId(System.getenv(\"FGA_STORE_ID\")) // Not required when calling createStore() or listStores() .authorizationModelId(System.getenv(\"FGA_AUTHORIZATION_MODEL_ID\")); // Optional, can be overridden per request var fgaClient = new OpenFgaClient(config); } } Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example) To obtain the access token: Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)","s":"01. Configure the OpenFGA API client","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#01-configure-the--api-client","p":503},{"i":512,"t":"To check whether user user:anne has relationship can_view with object document:Z Node.js Go .NET Python Java CLI curl // Run a check const { allowed } = await fgaClient.check({ user: 'user:anne', relation: 'can_view', object: 'document:Z', }, { authorization_model_id: '01HVMMBCMGZNT3SED4Z17ECXCA', }); // allowed = true options := ClientCheckOptions{ AuthorizationModelId: PtrString(\"01HVMMBCMGZNT3SED4Z17ECXCA\"), } body := ClientCheckRequest{ User: \"user:anne\", Relation: \"can_view\", Object: \"document:Z\", } data, err := fgaClient.Check(context.Background()). Body(body). Options(options). Execute() // data = { allowed: true } var options = new ClientCheckOptions { AuthorizationModelId = \"01HVMMBCMGZNT3SED4Z17ECXCA\", }; var body = new ClientCheckRequest { User = \"user:anne\", Relation = \"can_view\", Object = \"document:Z\", }; var response = await fgaClient.Check(body, options); // response.Allowed = true options = { \"authorization_model_id\": \"01HVMMBCMGZNT3SED4Z17ECXCA\" } body = ClientCheckRequest( user=\"user:anne\", relation=\"can_view\", object=\"document:Z\", ) response = await fga_client.check(body, options) # response.allowed = true var options = new ClientCheckOptions() .authorizationModelId(\"01HVMMBCMGZNT3SED4Z17ECXCA\"); var body = new ClientCheckRequest() .user(\"user:anne\") .relation(\"can_view\") ._object(\"document:Z\"); var response = fgaClient.check(body, options).get(); // response.getAllowed() = true fga query check --store-id=$FGA_STORE_ID --model-id=01HVMMBCMGZNT3SED4Z17ECXCA user:anne can_view document:Z # Response: {\"allowed\":true} curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/check \\ -H \"Authorization: Bearer $FGA_API_TOKEN\" \\ # Not needed if service does not require authorization -H \"content-type: application/json\" \\ -d '{\"authorization_model_id\": \"01HVMMBCMGZNT3SED4Z17ECXCA\", \"tuple_key\":{\"user\":\"user:anne\",\"relation\":\"can_view\",\"object\":\"document:Z\"}}' # Response: {\"allowed\":true} The result's allowed field will return true if the relationship exists and false if the relationship does not exist.","s":"02. Calling Check API","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#02-calling-check-api","p":503},{"i":514,"t":"If you want to check multiple user-object-relationship combinations in a single request, you can use the Batch Check API endpoint. Batching authorization checks together in a single request significantly reduces overall network latency. The Batch Check endpoint requires a correlation_id parameter for each check. The correlation_id is used to \"correlate\" the check responses with the checks sent in the request, since tuple_keys and contextual_tuples are not returned in the response on purpose to reduce data transfer to improve network latency. A correlation_id can be composed of any string of alphanumeric characters or dashes between 1-36 characters in length. This means you can use: simple iterating integers 1,2,3,etc UUID e5fe049b-f252-40b3-b795-fe485d588279 ULID 01JBMD9YG0XH3B4GVA8A9D2PSN or some other unique string But each correlation_id within a request must be unique. Note: If you are using one of our SDKs, the correlation_id is inserted for you by default and automatically correlates the allowed response with the proper tuple_key. To check whether user user:anne has multiple relationships writer and reader with object document:Z curl curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/batch-check \\ -H \"Authorization: Bearer $FGA_API_TOKEN\" \\ # Not needed if service does not require authorization -H \"content-type: application/json\" \\ -d '{ \"authorization_model_id\": \"01HVMMBCMGZNT3SED4Z17ECXCA\", \"checks\": [ { \"tuple_key\": { \"user\":\"user:anne\", \"relation\":\"writer\", \"object\":\"document:Z\", }, \"correlation_id\": \"886224f6-04ae-4b13-bd8e-559c7d3754e1\" }, { \"tuple_key\": { \"user\":\"user:anne\", \"relation\":\"reader\", \"object\":\"document:Z\", }, \"correlation_id\": \"da452239-a4e0-4791-b5d1-fb3d451ac078\" }, # Response: { \"results\": { { \"886224f6-04ae-4b13-bd8e-559c7d3754e1\": { \"allowed\": false }}, # writer { \"da452239-a4e0-4791-b5d1-fb3d451ac078\": { \"allowed\": true }}, # reader } } The result will include an allowed field for each authorization check that will return true if the relationship exists and false if the relationship does not exist. Configuring Batch Check​ BatchCheck has two available configuration options: Limit the number of checks allowed in a single BatchCheck request. Environment variable: OPENFGA_MAX_CHECKS_PER_BATCH_CHECK Command line flag: --max-checks-per-batch-check If more items are received in a single request than allowed by this limit, the API will return an error. Limit the number of Checks which can be resolved concurrently Environment variable: OPENFGA_MAX_CONCURRENT_CHECKS_PER_BATCH_CHECK Command line flag: --max-concurrent-checks-per-batch-check","s":"03. Calling Batch Check API","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#03-calling-batch-check-api","p":503},{"i":516,"t":"Take a look at the following section for more on how to perform authorization checks in your system OpenFGA Check API Read the Check API documentation and see how it works. More OpenFGA Batch Check API Read the Batch Check API documentation and see how it works. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/perform-check","h":"#related-sections","p":503},{"i":518,"t":"This section describes how to perform a list objects request. The List Objects API allows you to retrieve all objects of a specified type that a user has a given relationship with. This can be used in scenarios like displaying all documents a user can read or listing resources a user can manage.","s":"Perform a list objects call","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"","p":517},{"i":520,"t":"Node.js Go .NET Python Java CLI curl Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have installed the SDK. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have configured the authorization model. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables. Deploy an instance of the OpenFGA server, and have ready the values for your setup: FGA_STORE_ID, FGA_API_URL and, if needed, FGA_API_TOKEN. You have configured the authorization model and updated the relationship tuples. You have loaded FGA_STORE_ID and FGA_API_URL as environment variables.","s":"Before you start","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#before-you-start","p":517},{"i":522,"t":"Consider the following model which includes a user that can have a reader relationship with a document: model schema 1.1 type user type document relations define reader: [user] Assume that you want to list all objects of type document that user anne has reader relationship with:","s":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#step-by-step","p":517},{"i":524,"t":"Before calling the check API, you will need to configure the API client. Node.js Go .NET Python Java CLI curl // import the SDK const { OpenFgaClient } = require('@openfga/sdk'); // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options const fgaClient = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL, // required, e.g. https://api.fga.example storeId: process.env.FGA_STORE_ID, authorizationModelId: process.env.FGA_MODEL_ID, // Optional, can be overridden per request }); import ( \"os\" . \"github.com/openfga/go-sdk\" . \"github.com/openfga/go-sdk/client\" ) func main() { // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options fgaClient, err := NewSdkClient(&ClientConfiguration{ ApiUrl: os.Getenv(\"FGA_API_URL\"), // required, e.g. https://api.fga.example StoreId: os.Getenv(\"FGA_STORE_ID\"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods AuthorizationModelId: os.Getenv(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }) if err != nil { // .. Handle error } } // import the SDK using OpenFga.Sdk.Client; using OpenFga.Sdk.Client.Model; using OpenFga.Sdk.Model; using Environment = System.Environment; namespace Example; class Example { public static async Task Main() { // Initialize the SDK with no auth - see \"How to setup SDK client\" for more options var configuration = new ClientConfiguration() { ApiUrl = Environment.GetEnvironmentVariable(\"FGA_API_URL\"), ?? \"http://localhost:8080\", // required, e.g. https://api.fga.example StoreId = Environment.GetEnvironmentVariable(\"FGA_STORE_ID\"), // optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods AuthorizationModelId = Environment.GetEnvironmentVariable(\"FGA_MODEL_ID\"), // Optional, can be overridden per request }; var fgaClient = new OpenFgaClient(configuration); } } import asyncio import os import json from openfga_sdk.client import ClientConfiguration, OpenFgaClient async def main(): configuration = ClientConfiguration( api_url = os.environ.get('FGA_API_URL'), # required, e.g. https://api.fga.example store_id = os.environ.get('FGA_STORE_ID'), # optional, not needed for `CreateStore` and `ListStores`, required before calling for all other methods authorization_model_id = os.environ.get('FGA_MODEL_ID'), # Optional, can be overridden per request ) # Enter a context with an instance of the OpenFgaClient async with OpenFgaClient(configuration) as fga_client: api_response = await fga_client.read_authorization_models() await fga_client.close() asyncio.run(main()) import dev.openfga.sdk.api.client.OpenFgaClient; import dev.openfga.sdk.api.configuration.ClientConfiguration; public class Example { public static void main(String[] args) throws Exception { var config = new ClientConfiguration() .apiUrl(System.getenv(\"FGA_API_URL\")) // If not specified, will default to \"https://localhost:8080\" .storeId(System.getenv(\"FGA_STORE_ID\")) // Not required when calling createStore() or listStores() .authorizationModelId(System.getenv(\"FGA_AUTHORIZATION_MODEL_ID\")); // Optional, can be overridden per request var fgaClient = new OpenFgaClient(config); } } Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example) To obtain the access token: Set FGA_API_URL according to the service you are using (e.g. https://api.fga.example)","s":"01. Configure the OpenFGA API client","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#01-configure-the--api-client","p":517},{"i":526,"t":"To return all documents that user user:anne has relationship reader with: Node.js Go .NET Python Java CLI curl const response = await fgaClient.listObjects({ user: \"user:anne\", relation: \"reader\", type: \"document\", }, { authorization_model_id: \"01HVMMBCMGZNT3SED4Z17ECXCA\", }); // response.objects = [\"document:otherdoc\", \"document:planning\"] options := ClientListObjectsOptions{ AuthorizationModelId: PtrString(\"01HVMMBCMGZNT3SED4Z17ECXCA\"), } body := ClientListObjectsRequest{ User: \"user:anne\", Relation: \"reader\", Type: \"document\", } data, err := fgaClient.ListObjects(context.Background()). Body(body). Options(options). Execute() // data = { \"objects\": [\"document:otherdoc\", \"document:planning\"] } var options = new ClientCheckOptions { AuthorizationModelId = \"01HVMMBCMGZNT3SED4Z17ECXCA\", }; var body = new ClientListObjectsRequest { User = \"user:anne\", Relation = \"reader\", Type = \"document\", }; var response = await fgaClient.ListObjects(body, options); // response.Objects = [\"document:otherdoc\", \"document:planning\"] options = { \"authorization_model_id\": \"01HVMMBCMGZNT3SED4Z17ECXCA\" } body = ClientListObjectsRequest( user=\"user:anne\", relation=\"reader\", type=\"document\", ) response = await fga_client.list_objects(body, options) # response.objects = [\"document:otherdoc\", \"document:planning\"] var options = new ClientListObjectsOptions() .authorizationModelId(\"01HVMMBCMGZNT3SED4Z17ECXCA\"); var body = new ClientListObjectsRequest() .user(\"user:anne\") .relation(\"reader\") .type(\"document\"); var response = fgaClient.listObjects(body, options).get(); // response.getObjects() = [\"document:otherdoc\", \"document:planning\"] fga query list-objects --store-id=${FGA_STORE_ID} --model-id=01HVMMBCMGZNT3SED4Z17ECXCA user:anne reader document # Response: {\"objects\": [\"document:otherdoc\", \"document:planning\"]} curl -X POST $FGA_API_URL/stores/$FGA_STORE_ID/list-objects \\ -H \"Authorization: Bearer $FGA_API_TOKEN\" \\ # Not needed if service does not require authorization -H \"content-type: application/json\" \\ -d '{ \"authorization_model_id\": \"01HVMMBCMGZNT3SED4Z17ECXCA\", \"type\": \"document\", \"relation\": \"reader\", \"user\":\"user:anne\" }' # Response: {\"objects\": [\"document:otherdoc\", \"document:planning\"]} The result document:otherdoc and document:planning are the document objects that user:anne has reader relationship with. Warning The performance characteristics of the ListObjects endpoint vary drastically depending on the model complexity, number of tuples, and the relations it needs to evaluate. Relations with 'and' or 'but not' are more expensive to evaluate than relations with 'or'.","s":"02. Calling list objects API","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#02-calling-list-objects-api","p":517},{"i":528,"t":"Take a look at the following section for more on how to perform authorization checks in your system OpenFGA List Objects API Read the List Objects API documentation and see how it works. More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/perform-list-objects","h":"#related-sections","p":517},{"i":530,"t":"The following list outlines best practices for running OpenFGA in a production environment: Configure Authentication Enable HTTP TLS or gRPC TLS or both Set the log format to \"json\" and log level to \"info\" Disable the Playground Set Cluster Set Database Options Set Maximum Results Set Concurrency Limits","s":"Running OpenFGA in Production","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"","p":529},{"i":532,"t":"We recommend: Turn on in-memory caching in Check API via flags. This will reduce latency of requests, but it will increase the staleness of OpenFGA's responses. Please see Cache Expiration for details on the flags. Prefer having a small pool of servers with high capacity (memory and CPU cores) instead of a big pool of servers, to increase cache hit ratios and simplify pool management. Turn on metrics collection via the flags --metrics-enabled and --datastore-metrics-enabled. This will allow you to debug issues. Turn on tracing via the flag --trace-enabled, but set sampling ratio to a low value, for example --trace-sample-ratio=0.3. This will allow you to debug issues without overwhelming the tracing server. However, keep in mind that enabling tracing comes with a slight performance cost.","s":"Cluster recommendations","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#cluster-recommendations","p":529},{"i":534,"t":"To ensure good performance for OpenFGA, it is recommended that the database be: Co-located in the same physical datacenter and network as your OpenFGA servers. This will minimize latency of database calls. Used exclusively for OpenFGA and not shared with other applications. This allows scaling the database independently and avoiding contention with your database. Bootstrapped and managed with the openfga migrate command. This will ensure the appropriate database indexes are created. It's strongly recommended to fine-tune your server database connection settings to avoid having to re-establish database connections frequently. Establishing database connections is slow and will negatively impact performance, and so here are some guidelines for managing database connection settings: The server setting OPENFGA_DATASTORE_MAX_OPEN_CONNS should be set to be equal to your database's max connections. For example, in Postgres, you can see this value via running the SQL query SHOW max_connections;. If you are running multiple instances of the OpenFGA server, you should divide this setting equally among the instances. For example, if your database's max_connections is 100, and you have 2 OpenFGA instances, OPENFGA_DATASTORE_MAX_OPEN_CONNS should be set to 50 for each instance. The OPENFGA_DATASTORE_MAX_IDLE_CONNS should be set to a value no greater than the maximum open connections (see the bullet point above), but it should be set sufficiently high enough to avoid having to recreate connections on each request. If, when monitoring your database stats, you see a lot of database connections being closed and subsequently reopened, then you should consider increasing the maximum number of idle connections. If idle connections are getting reaped frequently, then consider increasing the OPENFGA_DATASTORE_CONN_MAX_IDLE_TIME to a large value. When in doubt, prioritize keeping connections around for longer rather than shorter, because doing so will drastically improve performance.","s":"Database recommendations","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#database-recommendations","p":529},{"i":536,"t":"note Before modifying concurrency limits please make sure you've followed the guidance for Database Recommendations OpenFGA queries such as Check, ListObjects and ListUsers can be quite database and CPU intensive in some cases. If you notice that a single request is consuming a lot of CPU or creating a high degree of database contention, then you may consider setting some concurrency limits to protect other requests from being negatively impacted by overly aggressive queries. The following table enumerates the server's concurrency specific settings: flag env config --max-concurrent-reads-for-list-objects OPENFGA_MAX_CONCURRENT_READS_FOR_LIST_OBJECTS maxConcurrentReadsForListObjects --max-concurrent-reads-for-list-users OPENFGA_MAX_CONCURRENT_READS_FOR_LIST_USERS maxConcurrentReadsForListUsers --max-concurrent-reads-for-check OPENFGA_MAX_CONCURRENT_READS_FOR_CHECK maxConcurrentReadsForCheck --resolve-node-limit OPENFGA_RESOLVE_NODE_LIMIT resolveNodeLimit --resolve-node-breadth-limit OPENFGA_RESOLVE_NODE_BREADTH_LIMIT resolveNodeBreadthLimit --max-concurrent-checks-per-batch-check OPENFGA_MAX_CONCURRENT_CHECKS_PER_BATCH_CHECK maxConcurrentChecksPerBatchCheck Determining the right values for these settings will be based on a variety of factors including, but not limited to, the database specific deployment topology, the FGA model(s) involved, and the relationship tuples in the system. However, here are some high-level guidelines: If a single ListObjects or ListUsers query is negatively impacting other query endpoints by increasing their latency or their error rate, then consider setting a lower value for OPENFGA_MAX_CONCURRENT_READS_FOR_LIST_OBJECTS or OPENFGA_MAX_CONCURRENT_READS_FOR_LIST_USERS. If a single Check query is negatively impacting other query endpoints by increasing their latency or their error rate, then consider setting a lower value for OPENFGA_MAX_CONCURRENT_READS_FOR_CHECK. If you still see high request latencies despite the guidance above, then you may additionally consider setting stricter limits on the query resolution behavior by limiting the resolution depth and resolution breadth. These can be controlled with the OPENFGA_RESOLVE_NODE_LIMIT and OPENFGA_RESOLVE_NODE_BREADTH_LIMIT settings, respectively. Consider these guidelines: OPENFGA_RESOLVE_NODE_LIMIT limits the resolution depth of a single query, and thus it sets an upper bound on how deep a relationship hierarchy may be. A high value will allow a single query to involve more hierarchical resolution and therefore more database queries, while a low value will reduce the number of hierarchical resolutions that will be allowed and thus reduce the number of database queries. OPENFGA_RESOLVE_NODE_BREADTH_LIMIT limits the resolution breadth. It sets an upper bound on the number of in-flight resolutions that can be taking place on one or more usersets. A high value will allow a single query to involve more concurrent evaluations to take place and therefore more database queries and server processes, while a low value will reduce the overall number of concurrent resolutions that will be allowed and thus reduce the number of database queries and server processes.","s":"Concurrency limits","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#concurrency-limits","p":529},{"i":538,"t":"Both the ListObjects and ListUsers endpoints will continue retrieving results until one of the following conditions is met: The maximum number of results is found The entire pool of possible results has been searched The API times out By default, both ListObjects and ListUsers have a maximum results limit of 1,000. The higher the quantity of potential results in the system, the more time and resource-intensive it becomes to search for a large number of maximum results. This increased load can impact performance, potentially leading to time-outs in some cases. If your use case allows, consider setting a lower max results value via the OPENFGA_LIST_OBJECTS_MAX_RESULTS or OPENFGA_LIST_USERS_MAX_RESULTS configuration properties. This adjustment can lead to immediate improvements in time and resource efficiency.","s":"Maximum results","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#maximum-results","p":529},{"i":540,"t":"Check the following sections for more on how to run OpenFGA in production environment. Data and API Best Practices Learn the best practices for managing data and invoking APIs in production environment More Migrating Relations Learn how to migrate relations in a production environment More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/running-in-production","h":"#related-sections","p":529},{"i":542,"t":"In OpenFGA v1.7.0, we introduced an experimental built-in access control feature that allows you to control access to your OpenFGA server. It relies on a control store with its own model and tuples to authorize requests to the OpenFGA server itself. Currently, there is no provided way to initialize that access control store and model, nor is there a way to bootstrap the client IDs that are supposed to be admins. Warning The built-in access control feature in OpenFGA is experimental and is not recommended for production use. We are looking for feedback on this, so if you do try it, please reach out on our openfga Slack channel in the CNCF community. Read the following steps to enable access control.","s":"🛡️Setup Access Control","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"","p":541},{"i":544,"t":"OIDC Provider: You need to have an OIDC provider set up and configured in your OpenFGA server set up to use access control. A Client ID ready to be used: You need to have the initial (admin) client ID that you want to manage access to your OpenFGA server. The FGA CLI: While the CLI is not strictly required, you need to follow the steps below. You can install it by following the instructions here. If you do not want to use the CLI, you can call the API with the equivalent SDK or REST calls.","s":"Requirements","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#requirements","p":541},{"i":546,"t":"This is important. If you enable access control before setting up the store and model and grant your initial client ID access, you will lock yourself out of the server, and you will have to turn it back off.","s":"01. Ensure the server is running (with access control disabled)","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#01-ensure-the-server-is-running-with-access-control-disabled","p":541},{"i":548,"t":"We will be using the following model to enable access control. Customizing your access control model You may choose to modify this model to suit your needs, however, keep in mind that configuring the model may not be supported in the future and you may be responsible for your own migrations at that point. The required types and relations that need to be defined are marked in the model below. model schema 1.1 type system # required relations define admin: [application] # required define can_call_create_stores: admin # required define can_call_list_stores: [application, application:*] or admin # required type application # required type store # required relations define system: [system] # required define admin: [application] or admin from system # required define model_writer: [application] or admin define reader: [application] or admin define writer: [application] or admin define can_call_delete_store: admin # required define can_call_get_store: reader or writer or model_writer # required define can_call_check: reader # required define can_call_expand: reader # required define can_call_list_objects: reader # required define can_call_list_users: reader # required define can_call_read: reader # required define can_call_read_assertions: reader or model_writer # required define can_call_read_authorization_models: reader or model_writer # required define can_call_read_changes: reader # required define can_call_write: writer # required define can_call_write_assertions: model_writer # required define can_call_write_authorization_models: model_writer # required type module # required relations define store: [store] # required define writer: [application] define can_call_write: writer or writer from store # required Place the model above in a file called model.fga. Run the following command to create the store and model: fga store create --name root-access-control --model ./model.fga This prints a store ID and model ID. You will need these IDs in the following steps. Grant your initial client ID access. You can do so by writing a tuple to the access control store you just created. The tuple should be of the type application and should have the client_id field set to the client ID of the client you want to grant access to. You can use the FGA CLI to do this: fga tuple write --store-id \"${ACCESS_CONTROL_STORE_ID}\" \"application:${FGA_ADMIN_CLIENT_ID}\" admin \"system:fga\" Replace ${ACCESS_CONTROL_STORE_ID} with the store ID you received in the previous step; replace ${FGA_ADMIN_CLIENT_ID} with the client ID you want to grant access to.","s":"02. Create the access control store and model","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#02-create-the-access-control-store-and-model","p":541},{"i":551,"t":"Enable the experimental support for access control by setting the environment variable OPENFGA_EXPERIMENTALS to enable-access-control. Enable the access control feature by setting the environment variable OPENFGA_ACCESS_CONTROL_ENABLED to true. Set the environment variable OPENFGA_ACCESS_CONTROL_STORE_ID to the store ID you received in the previous step. Set the environment variable OPENFGA_ACCESS_CONTROL_MODEL_ID to the model ID you received in the previous step.","s":"i. Enable access control in the server","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#i-enable-access-control-in-the-server","p":541},{"i":553,"t":"By default, the API will use the following claims (in order) in the OIDC token to identify the client. If you want to use a different claim, you can set the environment variable OPENFGA_AUTHN_OIDC_CLIENT_ID_CLAIMS to the claim(s) you want to use. If the claims are not set in the configuration, the following claims are used as default (in order): azp: following the OpenID standard client_id following RFC9068 That means that if the azp claim is present in the token, it will be used to identify the client. If not, the client_id claim will be used instead. For example, you can set the environment variable OPENFGA_AUTHN_OIDC_CLIENT_ID_CLAIMS to user_id,employee_id,client_id to allow the OpenFGA server to authorize based on: Use the user_id claim if present in the token. If not try to use the employee_id claim if present. If not try to use the client_id claim.","s":"ii. Customize what claim you want the API to use (optional)","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#ii-customize-what-claim-you-want-the-api-to-use-optional","p":541},{"i":555,"t":"You now need to restart the OpenFGA server in order for the configuration changes above to take effect. Congrats, you now have access control enabled! 🎉🎉","s":"iii. Restart the server","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#iii-restart-the-server","p":541},{"i":557,"t":"You can now use the admin client ID to manage access to your OpenFGA server. We will call it FGA_ADMIN_CLIENT_ID in the following examples to differentiate it from the client ID (called FGA_CLIENT_ID) you are granting access to. We will also use ACCESS_CONTROL_STORE_ID as the store ID of the access control store, and STORE_ID as the store ID you are granting the client access to. Grant access to a store (based on the model above, your choices are admin, model_writer, writer and reader). fga tuple write --store-id \"${ACCESS_CONTROL_STORE_ID}\" \"application:${FGA_CLIENT_ID}\" model_writer \"store:${STORE_ID}\" --client-id \"${FGA_ADMIN_CLIENT_ID}\" --client-secret ... --api-token-issuer ... --api-audience ... Grant access to writing tuples of a certain module in a store. In order to grant access to only write to relations in certain modules, you must have a model with modules. Refer to the modular models documentation for more on that feature. If you want to grant access to a module in a store, you must namespace the module ID with the store ID, so the object of the tuple will be of the form module:|. fga tuple write --store-id \"${ACCESS_CONTROL_STORE_ID}\" \"application:${FGA_CLIENT_ID}\" writer \"module:${STORE_ID}|\" --client-id \"${FGA_ADMIN_CLIENT_ID}\" --client-secret ... --api-token-issuer ... --api-audience ... Note If you are calling Write with a credential that only has access to certain modules and not the store, you will not be able to send tuples for more than 1 module in a certain request or you will get the following error: the principal cannot write tuples of more than 1 module(s) in a single request","s":"04. Grant access to a store","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#04-grant-access-to-a-store","p":541},{"i":559,"t":"Check the following sections for more on how to use OpenFGA. Setup OpenFGA Learn how to setup and configure an OpenFGA server More Setup OIDC Learn how to setup and configure an OpenFGA server More Production Best Practices Learn the best practices of running OpenFGA in a production environment More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/access-control","h":"#related-sections","p":541},{"i":561,"t":"Refer to the OpenFGA Getting Started for info on the various ways to install OpenFGA. The instructions below assume OpenFGA is installed and that you have the openfga binary in your PATH. If you have built openfga as a binary, but not in your path, you can refer to it directly (e.g. replace openfga in the instructions below with ./openfga or /path/to/openfga). You can configure the OpenFGA server in three ways: Using a configuration file. Using environment variables. Using command line parameters. If the same option is configured in multiple ways the command line parameters will take precedence over environment variables, which will take precedence over the configuration file. The configuration options and their default values are defined in config-schema.json.","s":"Configuring OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"","p":560},{"i":563,"t":"You can configure the OpenFGA server with a config.yaml file, which can be specified in either: /etc/openfga $HOME/.openfga . (i.e., the current working directory). The OpenFGA server will search for the configuration file in the above order. Here is a sample configuration to run OpenFGA with a Postgres database and using a preshared key for authentication: datastore: engine: postgres uri: postgres://user:password@localhost:5432/mydatabase authn: method: preshared preshared: keys: [\"key1\", \"key2\"]","s":"Using a configuration file","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#using-a-configuration-file","p":560},{"i":565,"t":"The OpenFGA server supports environment variables for configuration, and they will take priority over your configuration file. Each variable must be prefixed with OPENFGA_ and followed by your option in uppercase (e.g. --grpc-tls-key becomes OPENFGA_GRPC_TLS_KEY).","s":"Using environment variables","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#using-environment-variables","p":560},{"i":567,"t":"Command line parameters take precedence over environment variables and options in the configuration file. They are prefixed with -- , e.g. openfga run \\ --datastore-engine postgres \\ --datastore-uri 'postgres://postgres:password@postgres:5432/postgres?sslmode=disable'","s":"Using command line variables","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#using-command-line-variables","p":560},{"i":569,"t":"OpenFGA supports multiple storage engine options, including: memory - A memory storage engine, which is the default. Data is lost between server restarts. postgres - A Postgres storage engine. mysql - A MySQL storage engine. sqlite - A SQLite storage engine. The first time you run OpenFGA, or when you install a new version, you need to run the openfga migrate command. This will create the required database tables or perform the database migration required for a new version.","s":"Configuring data storage","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#configuring-data-storage","p":560},{"i":571,"t":"openfga migrate \\ --datastore-engine postgres \\ --datastore-uri 'postgres://postgres:password@postgres:5432/postgres?sslmode=disable' openfga run \\ --datastore-engine postgres \\ --datastore-uri 'postgres://postgres:password@postgres:5432/postgres?sslmode=disable' To learn how to run in Docker, check our Docker documentation.","s":"Postgres","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#postgres","p":560},{"i":573,"t":"The MySQL datastore has stricter limits for the max length of some fields for tuples compared to other datastore engines, in particular: object type is at most 128 characters (down from 256) object id is at most 128 characters (down from 256) user is at most 256 characters (down from 512) The connection URI needs to specify the query parseTime=true. openfga migrate \\ --datastore-engine mysql \\ --datastore-uri 'root:secret@tcp(mysql:3306)/openfga?parseTime=true' openfga run \\ --datastore-engine mysql \\ --datastore-uri 'root:secret@tcp(mysql:3306)/openfga?parseTime=true' To learn how to run in Docker, check our Docker documentation.","s":"MySQL","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#mysql","p":560},{"i":575,"t":"openfga migrate --datastore-engine sqlite \\ --datastore-uri 'file:/path/to/openfga.db' openfga run --datastore-engine sqlite \\ --datastore-uri 'file:/path/to/openfga.db' To learn how to run in Docker, check our Docker documentation.","s":"SQLite","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#sqlite","p":560},{"i":577,"t":"You can configure authentication in three ways: no authentication (default) pre-shared key authentication OIDC","s":"Configuring authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#configuring-authentication","p":560},{"i":579,"t":"If using Pre-shared key authentication, you will configure OpenFGA with one or more secret keys and your application calling OpenFGA will have to set an Authorization: Bearer header. Warning If you are going to use this setup in production, you should enable HTTP TLS in your OpenFGA server. You will need to configure the TLS certificate and key. Configuration File Environment Variables Update the config.yaml file to authn: method: preshared preshared: keys: [\"key1\", \"key2\"] http: tls: enabled: true cert: /Users/myuser/key/server.crt key: /Users/myuser/key/server.key Configure the authentication method to preshared: export OPENFGA_AUTHN_METHOD=preshared. Configure the authentication keys: export OPENFGA_AUTHN_PRESHARED_KEYS=key1,key2 Enable the HTTP TLS configuration: export OPENFGA_HTTP_TLS_ENABLED=true Configure the HTTP TLS certificate location: export OPENFGA_HTTP_TLS_CERT=/Users/myuser/key/server.crt Configure the HTTP TLS key location: export OPENFGA_HTTP_TLS_KEY=/Users/myuser/key/server.key To learn how to run in Docker, check our Docker documentation.","s":"Pre-shared key authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#pre-shared-key-authentication","p":560},{"i":581,"t":"To configure with OIDC authentication, you will first need to obtain the OIDC issuer and audience from your provider. Warning If you are going to use this setup in production, you should enable HTTP TLS in your OpenFGA server. You will need to configure the TLS certificate and key. Configuration File Environment Variables Update the config.yaml file to authn: method: oidc oidc: issuer: \"oidc-issuer\" # required issuerAliases: \"oidc-issuer-1\", \"oidc-issuer-2\" # optional audience: \"oidc-audience\" # required subjects: \"valid-subject-1\", \"valid-subject-2\" # optional http: tls: enabled: true cert: /Users/myuser/key/server.crt key: /Users/myuser/key/server.key Configure the authentication method to OIDC: export OPENFGA_AUTHN_METHOD=oidc. Configure the valid issuer (required): export OPENFGA_AUTHN_OIDC_ISSUER=oidc-issuer Configure the valid issuer aliases (optional): export OPENFGA_AUTHN_OIDC_ISSUER_ALIASES=oidc-issuer-1,oidc-issuer-2 Configure the valid audience (required): export OPENFGA_AUTHN_OIDC_AUDIENCE=oidc-audience Configure the valid subjects (optional): export OPENFGA_AUTHN_OIDC_SUBJECTS=oidc-subject-1,oidc-subject-2 Enable the HTTP TLS configuration: export OPENFGA_HTTP_TLS_ENABLED=true Configure the HTTP TLS certificate location: export OPENFGA_HTTP_TLS_CERT=/Users/myuser/key/server.crt Configure the HTTP TLS key location: export OPENFGA_HTTP_TLS_KEY=/Users/myuser/key/server.key To learn how to run in Docker, check our Docker documentation.","s":"OIDC","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#oidc","p":560},{"i":583,"t":"Warning Continuous profiling can be used in production deployments, but we recommend disabling it unless it is needed to troubleshoot specific performance or memory problems. Profiling through pprof can be enabled on the OpenFGA server by providing the --profiler-enabled flag. For example: openfga run --profiler-enabled If you need to serve the profiler on a different port than the default 3001, you can do so by specifying the --profiler-addr flag. For example: openfga run --profiler-enabled --profiler-addr :3002 If you want to run it in docker: docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 -p 3002:3002 openfga/openfga run --profiler-enabled --profiler-addr :3002","s":"Profiler (pprof)","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#profiler-pprof","p":560},{"i":585,"t":"OpenFGA is configured with an HTTP health check endpoint /healthz and a gRPC health check grpc.health.v1.Health/Check, which is wired to datastore testing. Possible response values are UNKNOWN SERVING NOT_SERVING SERVICE_UNKNOWN cURL gRPC curl -X GET $FGA_API_URL/healthz # {\"status\":\"SERVING\"} # See https://github.com/fullstorydev/grpcurl#installation grpcurl -plaintext $FGA_API_URL grpc.health.v1.Health/Check # {\"status\":\"SERVING\"}","s":"Health check","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#health-check","p":560},{"i":587,"t":"Various releases of OpenFGA may have experimental features that can be enabled by providing the --experimentals flag or the experimentals config. openfga run --experimentals=\"feature1, feature2\" or if you're using environment variables, openfga -e OPENFGA_EXPERIMENTALS=\"feature1, feature2\" run The following table enumerates the experimental flags, a description of what they do, and the versions of OpenFGA the flag is supported in: Name Description OpenFGA Version otel-metrics Enables support for exposing OpenFGA metrics through OpenTelemetry 0.3.2 <= v < 0.3.5 list-objects Enables ListObjects API 0.2.0 <= v < 0.3.3 check-query-cache Enables caching of check subproblem result 1.3.1 <= v < 1.3.6 enable-conditions Enables conditional relationship tuples 1.3.8 <= v < 1.4.0 enable-modular-models Enables modular authorization modules 1.5.1 <= v < 1.5.3 enable-list-users Enables new ListUsers API 1.5.4 <= v < 1.5.6 enable-consistency-params Enables consistency options 1.5.6 <= v < 1.6.0 enable-check-optimizations Enables performance optimization on Check 1.6.2 <= v enable-access-control Enables the ability to configure and setup access control 1.7.0 <= v Warning Experimental features are not guaranteed to be stable and may lead to server instabilities. It is not recommended to enable experimental features for anything other than experimentation. Experimental feature flags are also not considered part of API compatibility and are subject to change, so please refer to each OpenFGA specific release for a list of the experimental feature flags that can be enabled for that release.","s":"Experimental features","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#experimental-features","p":560},{"i":589,"t":"OpenFGA telemetry data is collected by default starting on version v0.3.5. The telemetry information that is captured includes Metrics, Traces, and Logs. note Please refer to the docker-compose.yaml file as an example of how to collect Metrics and Tracing in OpenFGA in a Docker environment using the OpenTelemetry Collector. This should serve as a good example that you can adjust for your specific deployment scenario.","s":"Telemetry","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#telemetry","p":560},{"i":591,"t":"OpenFGA metrics are collected with the Prometheus data format and exposed on address 0.0.0.0:2112/metrics. Metrics are exposed by default, but you can disable this with --metrics-enabled=false (or OPENFGA_METRICS_ENABLED=false environment variable). To set an alternative address, you can provide the --metrics-addr flag (OPENFGA_METRICS_ADDR environment variable). For example: openfga run --metrics-addr=0.0.0.0:2114 To see the request latency per endpoint of your OpenFGA deployment, you can provide the --metrics-enable-rpc-histograms flag (OPENFGA_METRICS_ENABLE_RPC_HISTOGRAMS environment variable).","s":"Metrics","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#metrics","p":560},{"i":593,"t":"OpenFGA traces can be collected with the OTLP data format. Tracing is disabled by default, but you can enable this with the --trace-enabled=true (OPENFGA_TRACE_ENABLED=true environment variable). Traces will be exported by default to address 0.0.0.0:4317. You can change this address with the --trace-otlp-endpoint flag (OPENFGA_TRACE_OTLP_ENDPOINT environment variable). To increase or decrease the trace sampling ratio, you can provide the --trace-sample-ratio flag (OPENFGA_TRACE_SAMPLE_RATIO env variable). Tracing by default uses a insecure connection. You can enable TLS by using --trace-otlp-tls-enabled=true flag or the environment variable OPENFGA_TRACE_OTLP_TLS_ENABLED. Warning It is not recommended to sample all traces (e.g. --trace-sample-ratio=1). You will need to adjust your sampling ratio based on the amount of traffic your deployment receives. Higher traffic will require less sampling and lower traffic can tolerate higher sampling ratios.","s":"Tracing","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#tracing","p":560},{"i":595,"t":"OpenFGA generates structured logs by default, and it can be configured with the following flags: --log-format: sets the log format. Today we support text and json format. --log-level: sets the minimum log level (defaults to info). It can be set to none to turn off logging. Warning It is highly recommended to enable logging in production environments. Disabling logging (--log-level=none) can mask important operations and hinder the ability to detect and diagnose issues, including potential security incidents. Ensure that logs are enabled and properly monitored to maintain visibility into the application's behavior and security.","s":"Logging","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#logging","p":560},{"i":597,"t":"Check the following sections for more on how to use OpenFGA. Production Best Practices Learn the best practices of running OpenFGA in a production environment More","s":"Related Sections","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/configure-openfga","h":"#related-sections","p":560},{"i":599,"t":"This article explains how to run your own OpenFGA server using Docker. To learn the different ways to configure OpenFGA check Configuring OpenFGA.","s":"🐳 Setup OpenFGA with Docker","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"","p":598},{"i":601,"t":"If you want to run OpenFGA locally as a Docker container, follow these steps: Install Docker (if not already installed). Run docker pull openfga/openfga to get the latest docker image. Run docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 openfga/openfga run. This will start an HTTP server and gRPC server with the default configuration options. Port 8080 is used to serve the HTTP API, 8081 is used to serve the gRPC API, and 3000 is used for the Playground.","s":"Step by step","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#step-by-step","p":598},{"i":603,"t":"Docker Docker Compose To run OpenFGA and Postgres in containers, you can create a new network to make communication between containers simpler: docker network create openfga You can then start Postgres in the network you created above: docker run -d --name postgres --network=openfga -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=password postgres:14 You should now have Postgres running in a container in the openfga network. However, it will not have the tables required for running OpenFGA. You can use the migrate command to create the tables. Using the OpenFGA container, this will look like: docker run --rm --network=openfga openfga/openfga migrate \\ --datastore-engine postgres \\ --datastore-uri \"postgres://postgres:password@postgres:5432/postgres?sslmode=disable\" Finally, start OpenFGA: docker run --name openfga --network=openfga -p 3000:3000 -p 8080:8080 -p 8081:8081 openfga/openfga run \\ --datastore-engine postgres \\ --datastore-uri 'postgres://postgres:password@postgres:5432/postgres?sslmode=disable' Copy the below code block into a local file named: docker-compose.yaml version: '3.8' networks: openfga: services: postgres: image: postgres:14 container_name: postgres networks: - openfga ports: - \"5432:5432\" environment: - POSTGRES_USER=postgres - POSTGRES_PASSWORD=password healthcheck: test: [ \"CMD-SHELL\", \"pg_isready -U postgres\" ] interval: 5s timeout: 5s retries: 5 migrate: depends_on: postgres: condition: service_healthy image: openfga/openfga:latest container_name: migrate command: migrate environment: - OPENFGA_DATASTORE_ENGINE=postgres - OPENFGA_DATASTORE_URI=postgres://postgres:password@postgres:5432/postgres?sslmode=disable networks: - openfga openfga: depends_on: migrate: condition: service_completed_successfully image: openfga/openfga:latest container_name: openfga environment: - OPENFGA_DATASTORE_ENGINE=postgres - OPENFGA_DATASTORE_URI=postgres://postgres:password@postgres:5432/postgres?sslmode=disable - OPENFGA_LOG_FORMAT=json command: run networks: - openfga ports: # Needed for the http server - \"8080:8080\" # Needed for the grpc server (if used) - \"8081:8081\" # Needed for the playground (Do not enable in prod!) - \"3000:3000\" In a terminal, navigate to that directory and run: docker-compose up This will start the Postgres database, run openfga migrate to configure the database and finally start the OpenFGA server.","s":"Using Postgres","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#using-postgres","p":598},{"i":605,"t":"Docker Docker Compose We first make a network: docker network create openfga Then, start MySQL in the network you created above: docker run -d --name mysql --network=openfga -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=openfga mysql:8 You should now have MySQL running in a container in the openfga network. But we still have to migrate all the tables to be able to run OpenFGA. You can use the migrate command to create the tables. Using the OpenFGA container, this will look like: docker run --rm --network=openfga openfga/openfga migrate \\ --datastore-engine mysql \\ --datastore-uri 'root:secret@tcp(mysql:3306)/openfga?parseTime=true' Finally, start OpenFGA: docker run --name openfga --network=openfga -p 3000:3000 -p 8080:8080 -p 8081:8081 openfga/openfga run \\ --datastore-engine mysql \\ --datastore-uri 'root:secret@tcp(mysql:3306)/openfga?parseTime=true' Copy the below code block into a local file named: docker-compose.yaml version: '3.8' networks: openfga: services: mysql: image: mysql:8 container_name: mysql networks: - openfga ports: - \"3306:3306\" environment: - MYSQL_ROOT_PASSWORD=secret - MYSQL_DATABASE=openfga healthcheck: test: [\"CMD\", 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD' ] timeout: 20s retries: 5 migrate: depends_on: mysql: condition: service_healthy image: openfga/openfga:latest container_name: migrate command: migrate environment: - OPENFGA_DATASTORE_ENGINE=mysql - OPENFGA_DATASTORE_URI=root:secret@tcp(mysql:3306)/openfga?parseTime=true networks: - openfga openfga: depends_on: migrate: condition: service_completed_successfully image: openfga/openfga:latest container_name: openfga environment: - OPENFGA_DATASTORE_ENGINE=mysql - OPENFGA_DATASTORE_URI=root:secret@tcp(mysql:3306)/openfga?parseTime=true - OPENFGA_LOG_FORMAT=json command: run networks: - openfga ports: # Needed for the http server - \"8080:8080\" # Needed for the grpc server (if used) - \"8081:8081\" # Needed for the playground (Do not enable in prod!) - \"3000:3000\" In a terminal, navigate to that directory and run: docker-compose up This will start the MySQL database, run openfga migrate to configure the database and finally start the OpenFGA server.","s":"Using MySQL","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#using-mysql","p":598},{"i":607,"t":"Docker Docker Compose We first make a network: docker network create openfga Then, create a volume to hold the openfga database: docker volume create openfga Next you have to migrate all the tables to be able to run OpenFGA. You can use the migrate command to create the tables. Using the OpenFGA container, this will look like: docker run --rm --network=openfga \\ -v openfga:/home/nonroot \\ -u nonroot \\ openfga/openfga migrate \\ --datastore-engine sqlite \\ --datastore-uri 'file:/home/nonroot/openfga.db' Finally, start OpenFGA: docker run --name openfga --network=openfga \\ -p 3000:3000 -p 8080:8080 -p 8081:8081 \\ -v openfga:/home/nonroot \\ -u nonroot \\ openfga/openfga run \\ --datastore-engine sqlite \\ --datastore-uri 'file:/home/nonroot/openfga.db' Copy the below code block into a local file named: docker-compose.yaml version: '3.8' networks: openfga: volumes: openfga: services: migrate: image: openfga/openfga:latest container_name: migrate command: migrate user: nonroot environment: - OPENFGA_DATASTORE_ENGINE=sqlite - OPENFGA_DATASTORE_URI=file:/home/nonroot/openfga.db networks: - openfga volumes: - openfga:/home/nonroot openfga: depends_on: migrate: condition: service_completed_successfully image: openfga/openfga:latest container_name: openfga user: nonroot environment: - OPENFGA_DATASTORE_ENGINE=sqlite - OPENFGA_DATASTORE_URI=file:/home/nonroot/openfga.db - OPENFGA_LOG_FORMAT=json command: run networks: - openfga volumes: - openfga:/home/nonroot ports: # Needed for the http server - \"8080:8080\" # Needed for the grpc server (if used) - \"8081:8081\" # Needed for the playground (Do not enable in prod!) - \"3000:3000\" In a terminal, navigate to that directory and run: docker-compose up This will create a new openfga volume to store the SQLite database, run openfga migrate to configure the database and finally start the OpenFGA server.","s":"Using SQLite","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#using-sqlite","p":598},{"i":609,"t":"To configure with pre-shared authentication and enabling TLS in http server with Docker. Copy the certificate and key files to your Docker container. Run with the following command: docker run --name openfga --network=openfga -p 3000:3000 -p 8080:8080 -p 8081:8081 openfga/openfga run \\ --authn-method=preshared \\ --authn-preshared-keys=\"key1,key2\" \\ --http-tls-enabled=true \\ --http-tls-cert=\"/Users/myuser/key/server.crt\" \\ --http-tls-key=\"/Users/myuser/key/server.key\"","s":"Pre-shared key authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#pre-shared-key-authentication","p":598},{"i":611,"t":"To configure with OIDC authentication and enabling TLS in http server with Docker. Copy the certificate and key files to your docker container. Run the following command docker run --name openfga --network=openfga -p 3000:3000 -p 8080:8080 -p 8081:8081 openfga/openfga run \\ --authn-method=oidc \\ --authn-oidc-issuer=\"oidc-issuer\" \\ --authn-oidc-audience=\"oidc-audience\" \\ --http-tls-enabled=true \\ --http-tls-cert=\"/Users/myuser/key/server.crt\" \\ --http-tls-key=\"/Users/myuser/key/server.key\"","s":"OIDC authentication","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#oidc-authentication","p":598},{"i":613,"t":"If you are enabling profiling, make sure you enable the corresponding port in docker. The default port is 3001, but if you need to serve the profiler on a different port, you can do so by specifying the --profiler-addr flag. For example: docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 -p 3002:3002 openfga/openfga run --profiler-enabled --profiler-addr :3002","s":"Enabling profiling","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#enabling-profiling","p":598},{"i":615,"t":"Check the following sections for more on how to use OpenFGA. Production Best Practices Learn the best practices of running OpenFGA in a production environment More","s":"Related sections","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/docker","h":"#related-sections","p":598},{"i":617,"t":"To deploy OpenFGA into a Kubernetes environment you can use the official OpenFGA Helm chart. Please refer to the official documentation on Artifact Hub for the Helm chart for more instructions.","s":"☸️ Setup OpenFGA with Kubernetes","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/kubernetes","h":"","p":616},{"i":619,"t":"Follow the guides below to set up an OpenFGA server. Configure an OpenFGA Server How to setup an OpenFGA server. Click to navigate Docker Setup Guide How to setup an OpenFGA server with Docker. Click to navigate Kubernetes Setup Guide How to setup an OpenFGA server with Kubernetes. Click to navigate Setup Access Control How to enable and setup the built-in access control OpenFGA server (experimental). Click to navigate","s":"Setup OpenFGA","u":"/pr-preview/pr-921/docs/getting-started/setup-openfga/overview","h":"","p":618},{"i":621,"t":"The Playground facilitates rapid development by allowing you to visualize and model your application's authorization models and manage relationship tuples with a locally running OpenFGA instance. It is enabled on port 3000 by default and accessible at http://localhost:3000/playground. The Playground is designed for early prototyping and learning. It has several limitations: It works by embedding the public Playground website in an