├── content ├── search.md ├── featured-background.jpg ├── docs │ ├── archive │ │ ├── proposals │ │ │ ├── _index.md │ │ │ ├── token-revocation.md │ │ │ ├── user-object.md │ │ │ └── upstream-refreshing.md │ │ ├── _index.md │ │ ├── integrations.md │ │ └── v2.md │ ├── guides │ │ ├── _index.md │ │ ├── templates.md │ │ ├── kubelogin-activedirectory.md │ │ └── using-dex.md │ ├── configuration │ │ ├── _index.md │ │ ├── oauth2.md │ │ ├── custom-scopes-claims-clients.md │ │ ├── tokens.md │ │ └── api.md │ ├── development │ │ ├── _index.md │ │ ├── releases.md │ │ ├── integration-tests.md │ │ └── oidc-certification.md │ ├── _index.md │ ├── connectors │ │ ├── keystone.md │ │ ├── linkedin.md │ │ ├── gitea.md │ │ ├── atlassian-crowd.md │ │ ├── bitbucketcloud.md │ │ ├── oauth.md │ │ ├── gitlab.md │ │ ├── _index.md │ │ ├── openshift.md │ │ ├── google.md │ │ ├── local.md │ │ ├── saml.md │ │ ├── authproxy.md │ │ ├── oidc.md │ │ ├── github.md │ │ └── microsoft.md │ ├── getting-started.md │ └── openid-connect.md ├── _index.md └── community.md ├── static ├── img │ ├── caution.png │ ├── dex-flow.png │ ├── architecture.png │ ├── dex-backend-flow.png │ ├── logos │ │ ├── cncf-color.png │ │ ├── cncf-white.png │ │ ├── dex-glyph-bw.png │ │ ├── dex-glyph-color.png │ │ ├── dex-glyph-white.png │ │ ├── dex-horizontal-color.png │ │ ├── dex-horizontal-white.png │ │ ├── dex-glyph-bw.svg │ │ ├── dex-glyph-color.svg │ │ ├── dex-glyph-white.svg │ │ ├── dex-horizontal-color.svg │ │ └── dex-horizontal-white.svg │ └── test │ │ └── architecture.png └── favicons │ └── favicon.png ├── layouts ├── partials │ ├── favicons.html │ ├── docs │ │ └── content.html │ ├── single-header.html │ ├── home │ │ ├── content.html │ │ └── hero.html │ ├── github-edit.html │ ├── footer.html │ └── breadcrumb.html ├── simple │ └── single.html └── index.redirects ├── .envrc ├── package.json ├── .gitmodules ├── .gitignore ├── .editorconfig ├── assets ├── scss │ ├── _variables_project.scss │ └── _styles_project.scss ├── js │ └── app.js ├── sass │ ├── helpers.sass │ ├── _docs.sass │ ├── custom.sass │ ├── content.sass │ └── style.sass └── icons │ └── logo.svg ├── flake.nix ├── Makefile ├── .markdown-link-check.json ├── netlify.toml ├── README.md ├── flake.lock └── hugo.toml /content/search.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Search Results 3 | layout: search 4 | --- 5 | -------------------------------------------------------------------------------- /static/img/caution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/caution.png -------------------------------------------------------------------------------- /static/img/dex-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/dex-flow.png -------------------------------------------------------------------------------- /static/favicons/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/favicons/favicon.png -------------------------------------------------------------------------------- /static/img/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/architecture.png -------------------------------------------------------------------------------- /content/featured-background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/content/featured-background.jpg -------------------------------------------------------------------------------- /static/img/dex-backend-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/dex-backend-flow.png -------------------------------------------------------------------------------- /static/img/logos/cncf-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/cncf-color.png -------------------------------------------------------------------------------- /static/img/logos/cncf-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/cncf-white.png -------------------------------------------------------------------------------- /layouts/partials/favicons.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/img/logos/dex-glyph-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/dex-glyph-bw.png -------------------------------------------------------------------------------- /static/img/test/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/test/architecture.png -------------------------------------------------------------------------------- /layouts/partials/docs/content.html: -------------------------------------------------------------------------------- 1 | {{ with .Content }} 2 |
3 | {{ . }} 4 |
5 | {{ end }} 6 | -------------------------------------------------------------------------------- /static/img/logos/dex-glyph-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/dex-glyph-color.png -------------------------------------------------------------------------------- /static/img/logos/dex-glyph-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/dex-glyph-white.png -------------------------------------------------------------------------------- /static/img/logos/dex-horizontal-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/dex-horizontal-color.png -------------------------------------------------------------------------------- /static/img/logos/dex-horizontal-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dexidp/website/HEAD/static/img/logos/dex-horizontal-white.png -------------------------------------------------------------------------------- /content/docs/archive/proposals/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Proposals" 3 | description: "Proposals Index" 4 | date: 2020-01-07T14:59:38+01:00 5 | draft: true 6 | toc: true 7 | --- 8 | -------------------------------------------------------------------------------- /content/docs/guides/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Guides" 3 | description: "Most common scenarios and how to solve them" 4 | date: 2020-01-07T14:59:38+01:00 5 | draft: false 6 | toc: true 7 | weight: 2000 8 | --- 9 | -------------------------------------------------------------------------------- /content/docs/configuration/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Configuration" 3 | description: "Configuring general settings for Dex" 4 | date: 2020-01-07T14:59:38+01:00 5 | draft: false 6 | toc: true 7 | weight: 2000 8 | --- 9 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then 2 | source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs=" 3 | fi 4 | use flake 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "autoprefixer": "^10.4.19", 4 | "postcss": "^8.4.38", 5 | "postcss-cli": "^9.0.1" 6 | }, 7 | "devDependencies": { 8 | "markdown-link-check": "^3.12.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "themes/docsy"] 2 | path = themes/docsy 3 | url = https://github.com/cncf/docsy.git 4 | docsy-pin = v0.9.1 5 | docsy-reminder = "Ensure that all tags from google/docsy are also present in cncf/docsy, otherwise add (push) them." 6 | -------------------------------------------------------------------------------- /content/docs/archive/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Archive" 3 | description: "The following documents are no longer maintained and are archived for reference purposes only" 4 | date: 2020-01-07T14:59:38+01:00 5 | draft: false 6 | toc: true 7 | weight: 9999 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Hugo-generated assets 2 | public/ 3 | resources/ 4 | 5 | # npm assets 6 | node_modules/ 7 | 8 | # files 9 | package-lock.json 10 | yarn.lock 11 | 12 | # Direnv files 13 | /.direnv/ 14 | 15 | /.hugo_build.lock 16 | 17 | # Themes are submodules 18 | /themes/ 19 | -------------------------------------------------------------------------------- /layouts/partials/single-header.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | {{ if ne .Kind "section" }} 4 | {{ partial "breadcrumb.html" . }} 5 | {{ partial "github-edit.html" . }} 6 | {{ end }} 7 |
8 |
9 | -------------------------------------------------------------------------------- /layouts/partials/home/content.html: -------------------------------------------------------------------------------- 1 | {{ $title := site.Title }} 2 | {{ $desc := site.Params.description | markdownify }} 3 | 4 | {{ with .Content }} 5 |
6 |
7 |
8 | {{ . }} 9 |
10 |
11 |
12 | {{ end }} 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [Makefile] 12 | indent_style = tab 13 | 14 | [*.{html,js,json,md,sass,yaml}] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /assets/scss/_variables_project.scss: -------------------------------------------------------------------------------- 1 | /* Docsy-delta full file override: we're not tracking changes to the Docsy file of the same name. */ 2 | 3 | $dex-colors: ( 4 | 'red': #F04D5C, 5 | 'blue': #449FD8, 6 | 'gray': #D3D3D3, 7 | ); 8 | 9 | $primary: map-get($dex-colors, 'blue'); 10 | $secondary: map-get($dex-colors, 'red'); 11 | $td-enable-google-fonts: true; 12 | -------------------------------------------------------------------------------- /assets/js/app.js: -------------------------------------------------------------------------------- 1 | const navbarBurger = () => { 2 | const burger = $(".navbar-burger"), 3 | menu = $(".navbar-menu"); 4 | 5 | burger.click(() => { 6 | 7 | 8 | [burger, menu].forEach((el) => el.toggleClass('is-active')); 9 | }); 10 | } 11 | 12 | $(() => { 13 | console.log("Welcome to the CNCF's Hugo + Netlify starter"); 14 | 15 | navbarBurger(); 16 | }); 17 | -------------------------------------------------------------------------------- /layouts/partials/github-edit.html: -------------------------------------------------------------------------------- 1 |
2 | {{ $repoUrl := .Site.Params.repositoryUrl }} 3 | {{ $filePath := .File.Path }} 4 | {{ $editUrl := print $repoUrl "/blob/main/content/" $filePath }} 5 | 6 |   Edit on GitHub 7 | 8 |
9 | -------------------------------------------------------------------------------- /assets/scss/_styles_project.scss: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Nothing defined here. The Hugo project that uses this theme can override Bootstrap by adding a file to: 4 | 5 | assets/scss/_styles_project.scss 6 | 7 | */ 8 | 9 | .logo { 10 | max-height: 250px; 11 | -webkit-filter: drop-shadow(12px 12px 7px rgba(0, 0, 0, 0.5)); 12 | filter: drop-shadow(12px 12px 7px rgba(0, 0, 0, 0.5)); 13 | } 14 | -------------------------------------------------------------------------------- /content/docs/archive/integrations.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Integrations" 3 | description: "" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 1100 8 | --- 9 | 10 | This document tracks the libraries and tools that are compatible with dex. [Join the community](https://github.com/dexidp/dex/), and help us keep the list up-to-date. 11 | 12 | ## Tools 13 | 14 | ## Projects with a dex dependency 15 | -------------------------------------------------------------------------------- /layouts/simple/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |
5 |

{{ .Page.Title | markdownify }}

6 |

{{ .Page.Description | markdownify }}

7 | {{ with .Content }} 8 |
9 | {{ . }} 10 |
11 | {{ end }} 12 |
13 |
14 |
15 | {{ end }} 16 | -------------------------------------------------------------------------------- /content/docs/development/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Development" 3 | description: "Dev Environment Setup, Testing, and Contributing to Dex" 4 | date: 2020-12-09 5 | draft: false 6 | toc: false 7 | weight: 3000 8 | --- 9 | 10 | This section explains how you can develop for the Dex project and documents what steps need to be done at each phase of development (setting up the development environment, running tests, submitting changes, releasing software, etc). 11 | 12 | Dex is an open source software (licensed under the Apache-2.0 license) and contributions (of any kind) are more than welcome from anyone in the community. 13 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Dex website"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 6 | flake-utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, flake-utils }: 10 | flake-utils.lib.eachDefaultSystem (system: 11 | let 12 | pkgs = import nixpkgs { inherit system; }; 13 | in 14 | { 15 | devShells.default = pkgs.mkShell { 16 | buildInputs = with pkgs; [ 17 | git 18 | gnumake 19 | hugo 20 | npm 21 | ]; 22 | }; 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 | {{ $year := now.Year }} 2 | 3 | 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dependencies: 2 | npm install -D 3 | 4 | docsy: dependencies 5 | git submodule update --init --recursive 6 | cd themes/docsy/ && npm install 7 | 8 | serve: docsy 9 | hugo server \ 10 | --buildDrafts \ 11 | --buildFuture \ 12 | --disableFastRender 13 | 14 | production-build: docsy 15 | hugo \ 16 | --minify 17 | 18 | preview-build: docsy 19 | hugo \ 20 | --baseURL $(DEPLOY_PRIME_URL) \ 21 | --buildDrafts \ 22 | --buildFuture \ 23 | --minify 24 | 25 | open: 26 | open https://dexidp.netlify.com 27 | 28 | check-links: 29 | markdown-link-check -c .markdown-link-check.json $$(find ./content -name "*.md" | xargs) 30 | -------------------------------------------------------------------------------- /layouts/partials/breadcrumb.html: -------------------------------------------------------------------------------- 1 | {{ define "breadcrumb" }} 2 | {{ if .p1.Parent }} 3 | {{ template "breadcrumb" (dict "p1" .p1.Parent "p2" .p2) }} 4 | {{ else if not .p1.IsHome }} 5 | {{ template "breadcrumb" (dict "p1" .p1.Site.Home "p2" .p2) }} 6 | {{ end }} 7 | 8 | {{ $isHere := eq .p1 .p2 }} 9 | {{ if $isHere }}{{ end }} 10 | / 11 | {{ .p1.Title | markdownify }} 12 | 13 | {{ if $isHere }}{{ end }} 14 | {{ end }} 15 | 16 | 21 | -------------------------------------------------------------------------------- /.markdown-link-check.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignorePatterns": [ 3 | { 4 | "pattern": "^http://localhost" 5 | }, 6 | { 7 | "pattern": "^http://127.0.0.1" 8 | }, 9 | { 10 | "pattern": "^#" 11 | }, 12 | { 13 | "pattern": "^https://dex.example.com" 14 | }, 15 | { 16 | "pattern": "^https://twitter.com/dexidp" 17 | } 18 | ], 19 | "replacementPatterns": [ 20 | { 21 | "pattern": "^/", 22 | "replacement": "http://localhost:1313/" 23 | }, 24 | { 25 | "pattern": "^/", 26 | "replacement": "http://localhost:1313/" 27 | } 28 | ], 29 | "timeout": "3s", 30 | "retryOn429": true, 31 | "aliveStatusCodes": [200, 206] 32 | } 33 | -------------------------------------------------------------------------------- /layouts/partials/home/hero.html: -------------------------------------------------------------------------------- 1 | {{ $title := site.Title }} 2 | {{ $desc := site.Params.description | markdownify }} 3 |
4 |
5 |
6 |
7 |

A Federated OpenID Connect Provider

8 |

Integrate any identity provider into your application using OpenID Connect.

9 |

Federate across upstream identity providers with ease.

10 |
11 |
12 | 13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /assets/sass/helpers.sass: -------------------------------------------------------------------------------- 1 | // This guarantees that the footer stays stuck to the bottom of the page 2 | .is-page 3 | display: flex 4 | flex-direction: column 5 | min-height: 100vh 6 | 7 | .is-main 8 | flex: 1 9 | @extend .has-bottom-margin 10 | 11 | .has-bottom-border 12 | border-bottom: 1px solid #ebebeb 13 | 14 | .has-bottom-margin 15 | margin-bottom: 3rem 16 | 17 | .has-bottom-margin-sm 18 | margin-bottom: 1.5rem 19 | 20 | .has-top-margin 21 | margin-top: 3rem 22 | 23 | .page-meta 24 | .breadcrumb, .github-edit 25 | display: inline 26 | color: $cncf-blue-3 27 | a 28 | color: $white 29 | &:hover 30 | color: $cncf-blue-4 31 | button 32 | background-color: $white 33 | border: 0px 34 | a 35 | color: $cncf-blue-7 36 | &:hover 37 | color: $cncf-blue-9 38 | -------------------------------------------------------------------------------- /content/docs/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Documentation" 3 | description: "" 4 | date: 2020-01-07T14:59:38+01:00 5 | draft: false 6 | toc: true 7 | menu: { main: { weight: 10 } } 8 | --- 9 | 10 | ## Architecture 11 | 12 | Dex is an identity service that uses OpenID Connect to drive authentication for other apps. Dex acts as a portal to other identity providers through "connectors." This lets Dex defer authentication to LDAP servers, SAML providers, or established identity providers like GitHub, Google, and Active Directory. 13 | 14 | 15 | 16 | ## Getting help 17 | 18 | * For feature requests and bugs, file an [issue.](https://github.com/dexidp/dex/issues) 19 | * For general discussion about both using and developing Dex, you can join the [#dexidp channel](slack://channel?team=T09NY5SBT&id=C011URMR41W) 20 | on the Kubernetes Slack, or join the [Dex-dev](https://groups.google.com/forum/#!forum/dex-dev) mailing list. 21 | 22 | ## Reporting a security vulnerability 23 | 24 | Due to their public nature, GitHub and mailing lists are NOT appropriate places for reporting vulnerabilities. Please refer to the project's [security disclosure](https://github.com/dexidp/dex/blob/master/.github/SECURITY.md) process when reporting issues that may be security related. 25 | 26 |
27 | -------------------------------------------------------------------------------- /content/docs/connectors/keystone.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through OpenStack Keystone" 3 | linkTitle: "OpenStack Keystone" 4 | description: "" 5 | date: 2021-03-11 6 | draft: false 7 | toc: true 8 | weight: 2135 9 | --- 10 | 11 | ## Overview 12 | 13 | [Keystone](https://docs.openstack.org/keystone/latest/) is an OpenStack service that provides API client authentication, service discovery, and distributed multi-tenant authorization. 14 | 15 | OpenStack Keystone connector supports `offline_access` and `groups` scopes. To use this connector, create a domain and user with an admin role, then specify the credentials in the configuration file (see the example below). 16 | 17 | OpenStack Keystone exposes the [Identity API v3](https://docs.openstack.org/api-ref/identity/v3/) to work with dex. 18 | 19 | 20 | ## Configuration 21 | 22 | The following is an example of an OpenStack Keystone configuration for dex: 23 | 24 | ```yaml 25 | connectors: 26 | - type: keystone 27 | # Required field for connector id. 28 | id: keystone 29 | # Required field for connector name. 30 | name: Keystone 31 | config: 32 | # Required, without v3 suffix. 33 | keystoneHost: http://example:5000 34 | # Required, admin user credentials to connect to keystone. 35 | domain: default 36 | keystoneUsername: demo 37 | keystonePassword: DEMO_PASS 38 | ``` 39 | -------------------------------------------------------------------------------- /content/docs/connectors/linkedin.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through LinkedIn" 3 | linkTitle: "LinkedIn" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2070 9 | --- 10 | 11 | ## Overview 12 | 13 | One of the login options for dex uses the LinkedIn OAuth2 flow to identify the end user through their LinkedIn account. 14 | 15 | When a client redeems a refresh token through dex, dex will re-query LinkedIn to update user information in the ID Token. To do this, __dex stores a readonly LinkedIn access token in its backing datastore.__ Users that reject dex's access through LinkedIn will also revoke all dex clients which authenticated them through LinkedIn. 16 | 17 | ## Configuration 18 | 19 | Register a new application via `My Apps -> Create Application` ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`. 20 | 21 | The following is an example of a configuration for `examples/config-dev.yaml`: 22 | 23 | ```yaml 24 | connectors: 25 | - type: linkedin 26 | # Required field for connector id. 27 | id: linkedin 28 | # Required field for connector name. 29 | name: LinkedIn 30 | config: 31 | # Credentials can be string literals or pulled from the environment. 32 | clientID: $LINKEDIN_APPLICATION_ID 33 | clientSecret: $LINKEDIN_CLIENT_SECRET 34 | redirectURI: http://127.0.0.1:5556/dex/callback 35 | ``` 36 | -------------------------------------------------------------------------------- /static/img/logos/dex-glyph-bw.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /content/docs/connectors/gitea.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through Gitea" 3 | linkTitle: "Gitea" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2130 9 | --- 10 | 11 | ## Overview 12 | 13 | One of the login options for dex uses the Gitea OAuth2 flow to identify the end user through their Gitea account. 14 | 15 | When a client redeems a refresh token through dex, dex will re-query Gitea to update user information in the ID Token. To do this, __dex stores a readonly Gitea access token in its backing datastore.__ Users that reject dex's access through Gitea will also revoke all dex clients which authenticated them through Gitea. 16 | 17 | ## Configuration 18 | 19 | Register a new OAuth consumer with [Gitea](https://docs.gitea.com/next/development/oauth2-provider) ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`. 20 | 21 | The following is an example of a configuration for `examples/config-dev.yaml`: 22 | 23 | ```yaml 24 | connectors: 25 | - type: gitea 26 | # Required field for connector id. 27 | id: gitea 28 | # Required field for connector name. 29 | name: Gitea 30 | config: 31 | # Credentials can be string literals or pulled from the environment. 32 | clientID: $GITEA_CLIENT_ID 33 | clientSecret: $GITEA_CLIENT_SECRET 34 | redirectURI: http://127.0.0.1:5556/dex/callback 35 | # optional, default = https://gitea.com 36 | baseURL: https://gitea.com 37 | ``` 38 | -------------------------------------------------------------------------------- /static/img/logos/dex-glyph-color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /static/img/logos/dex-glyph-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "public" 3 | command = "make production-build" 4 | 5 | [build.environment] 6 | HUGO_VERSION = "0.124.1" 7 | NODE_VERSION = "20" 8 | 9 | [context.deploy-preview] 10 | command = "make preview-build" 11 | 12 | [context.branch-deploy] 13 | command = "make preview-build" 14 | 15 | [[redirects]] 16 | from = "/docs/tokens/" 17 | to = "/docs/configuration/tokens/" 18 | status = 301 19 | force = false 20 | 21 | [[redirects]] 22 | from = "/docs/storage/" 23 | to = "/docs/configuration/storage/" 24 | status = 301 25 | force = false 26 | 27 | [[redirects]] 28 | from = "/docs/oauth2/" 29 | to = "/docs/configuration/oauth2/" 30 | status = 301 31 | force = false 32 | 33 | [[redirects]] 34 | from = "/docs/api/" 35 | to = "/docs/configuration/api/" 36 | status = 301 37 | force = false 38 | 39 | [[redirects]] 40 | from = "/docs/custom-scopes-claims-clients/" 41 | to = "/docs/configuration/custom-scopes-claims-clients/" 42 | status = 301 43 | force = false 44 | 45 | [[redirects]] 46 | from = "/docs/templates/" 47 | to = "/docs/guides/templates/" 48 | status = 301 49 | force = false 50 | 51 | [[redirects]] 52 | from = "/docs/token-exchange/" 53 | to = "/docs/guides/token-exchange/" 54 | status = 301 55 | force = false 56 | 57 | [[redirects]] 58 | from = "/docs/using-dex/" 59 | to = "/docs/guides/using-dex/" 60 | status = 301 61 | force = false 62 | 63 | [[redirects]] 64 | from = "/docs/kubernetes/" 65 | to = "/docs/guides/kubernetes/" 66 | status = 301 67 | force = false 68 | 69 | [[redirects]] 70 | from = "/docs/kubelogin-activedirectory/" 71 | to = "/docs/guides/kubelogin-activedirectory/" 72 | status = 301 73 | force = false 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CNCF Hugo Starter 2 | 3 | This repository contains a boilerplate static site generator setup for creating CNCF documentation projects. We strongly recommend using this setup (it helps us help you and your project!), but none of the technologies in the stack are strictly required. 4 | 5 | The starter uses the following: 6 | * **[Hugo](https://gohugo.io/)** as a static site generator 7 | * **[Docsy](https://www.docsy.dev/)** as a documentation theme 8 | * **[Netlify](https://www.netlify.com/)** for building, hosting, and DNS management 9 | 10 | ## Running locally 11 | 12 | Make sure you have [npm](https://www.npmjs.com/) and [yarn](https://yarnpkg.com/) installed. Clone this repository and run the following two commands in its directory: 13 | 14 | ```shell 15 | # Run the server locally 16 | make serve 17 | ``` 18 | 19 | ## Running on Netlify 20 | 21 | Netlify is a CI/CD build tool and hosting solution for (among other things) static sites. We **strongly** recommend using Netlify unless you have a good reason not to. 22 | 23 | This repository comes with a pre-configured [`netlify.toml`](https://github.com/cncf/hugo-netlify-starter/blob/master/netlify.toml) file. To build to Netlify: 24 | 25 | 1. Go to [netlify.com](https://netlify.com) and sign up. We recommend signing up using a GitHub account. 26 | 2. Click **New Site from Git**, and give Netlify access to your GitHub account. 27 | > **Note:** For projects with lots of contributors, it can be handy to create a general/bot account instead of granting access with a personal account. 28 | 29 | 3. Install Netlify with access to your documentation site repository. 30 | 4. Leave all other settings as default and click **Deploy Site**. 31 | -------------------------------------------------------------------------------- /assets/sass/_docs.sass: -------------------------------------------------------------------------------- 1 | /* Header & Hero */ 2 | 3 | .single-hero .hero-body 4 | padding: 1.5rem 5 | code 6 | border-radius: 2px 7 | padding: 0.1rem 0.2rem 0.1rem 0.2rem 8 | 9 | .docs-title 10 | //background: linear-gradient(99.62deg, $cncf-blue-6 3.15%, $cncf-violet-10 88.41%) 11 | background-color: $cncf-violet-9 12 | h1, p 13 | color: #ffffff 14 | 15 | .title 16 | @extend .title 17 | font-weight: 200 18 | font-size: 3.815rem 19 | margin-top: 1rem 20 | margin-bottom: 1.5rem 21 | 22 | .subtitle 23 | font-weight: 200 24 | 25 | .breadcrumb ul li 26 | display: inline 27 | 28 | /* Nav */ 29 | nav 30 | ul 31 | @extend .menu-list 32 | ul ul li 33 | border-left: 1px solid $cncf-blue-1 34 | .menu-list ul, ul li ul 35 | margin: 0 36 | 37 | /* Body */ 38 | .hashlink 39 | @extend .icon 40 | font-size: 1rem 41 | height: 1rem 42 | width: 1rem 43 | 44 | .headline-hash 45 | display: none 46 | 47 | @for $i from 1 through 6 48 | h#{$i} 49 | &:hover > .headline-hash 50 | display: inline 51 | 52 | .content 53 | table 54 | background-color: $white 55 | thead th 56 | border-bottom: 1px solid $cncf-blue-5 57 | background-color: $cncf-blue-5 58 | font-size: $size-7 59 | font-weight: 600 60 | letter-spacing: 0.02rem 61 | text-transform: uppercase 62 | td 63 | border-bottom: 1px solid $cncf-blue-2 64 | background-color: $cncf-blue-2 65 | 66 | code 67 | background-color: $white-ter 68 | color: $cncf-violet-5 69 | padding: 0.1rem 0.35rem 0.1rem 0.3rem 70 | border-radius: 2px 71 | pre 72 | background-color: transparent 73 | 74 | .docs-section-nav 75 | border-left: 1px solid #ebebeb 76 | hr 77 | height: 1px 78 | color: #ebebeb 79 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1681202837, 9 | "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "cfacdce06f30d2b68473a46042957675eebb3401", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1681903854, 24 | "narHash": "sha256-U3vbSEdct4aUu+vk3YsBiwokN3th4Jvde7S8gnVmeAA=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "bb2009ca185d97813e75736c2b8d1d8bb81bde05", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixpkgs-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /content/docs/guides/templates.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Customizing Dex Templates" 3 | description: "" 4 | date: 2020-09-30 5 | toc: true 6 | weight: 1100 7 | --- 8 | 9 | ## Using your own templates 10 | 11 | Dex supports using your own templates and passing arbitrary data to them to help customize your installation. 12 | 13 | Steps: 14 | 15 | 1. Copy contents of the `web` directory over to a new directory. 16 | 1. Customize the templates as needed, be sure to retain all the existing variables so Dex continues working correctly. 17 | (Use the following syntax to render values from `frontend.extra` config: `{{ "your_key" | extra }}`) 18 | 1. Set the `frontend.dir` value to your own `web` directory (Alternatively, you can set the `DEX_FRONTEND_DIR` environment variable). 19 | 1. Add your custom data to the Dex configuration `frontend.extra`. (optional) 20 | 1. Change the issuer by setting the `frontend.issuer` config in order to modify the Dex title and the `Log in to <>` tag. (optional) 21 | 1. Create a custom theme for your templates in the `themes` directory. (optional) 22 | 23 | Here is an example configuration: 24 | 25 | ```yaml 26 | frontend: 27 | dir: /path/to/custom/web 28 | issuer: my-dex 29 | extra: 30 | tos_footer_link: "https://example.com/terms" 31 | client_logo_url: "../theme/client-logo.png" 32 | foo: "bar" 33 | ``` 34 | 35 | To test your templates simply run Dex with a valid configuration and go through a login flow. 36 | 37 | 38 | ## Customize the official container image 39 | 40 | Dex is primarily distributed as a container image. 41 | The above guide explains how to customize the templates for any Dex instance. 42 | 43 | You can combine that with a custom `Dockerfile` to ease the deployment of those custom templates: 44 | 45 | ```dockerfile 46 | FROM ghcr.io/dexidp/dex:latest 47 | 48 | ENV DEX_FRONTEND_DIR=/srv/dex/web 49 | 50 | COPY --chown=root:root web /srv/dex/web 51 | ``` 52 | 53 | Using the snippet above, you can avoid setting the `frontend.dir` config. 54 | -------------------------------------------------------------------------------- /content/docs/connectors/atlassian-crowd.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through Atlassian Crowd" 3 | linkTitle: "Atlassian Crowd" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2120 9 | --- 10 | 11 | ## Overview 12 | 13 | Atlassian Crowd is a centralized identity management solution providing single sign-on and user identity. 14 | 15 | Current connector uses request to [Crowd REST API](https://developer.atlassian.com/server/crowd/json-requests-and-responses/) endpoints: 16 | * `/user` - to get user-info 17 | * `/session` - to authenticate the user 18 | 19 | Offline Access scope support provided with a new request to user authentication and user info endpoints. 20 | 21 | ## Configuration 22 | To start using the Atlassian Crowd connector, firstly you need to register an application in your Crowd like specified in the [docs](https://confluence.atlassian.com/crowd/adding-an-application-18579591.html). 23 | 24 | The following is an example of a configuration for dex `examples/config-dev.yaml`: 25 | 26 | ```yaml 27 | connectors: 28 | - type: atlassian-crowd 29 | # Required field for connector id. 30 | id: crowd 31 | # Required field for connector name. 32 | name: Crowd 33 | config: 34 | # Required field to connect to Crowd. 35 | baseURL: https://crowd.example.com/crowd 36 | # Credentials can be string literals or pulled from the environment. 37 | clientID: $ATLASSIAN_CROWD_APPLICATION_ID 38 | clientSecret: $ATLASSIAN_CROWD_CLIENT_SECRET 39 | # Optional groups whitelist, communicated through the "groups" scope. 40 | # If `groups` is omitted, all of the user's Crowd groups are returned when the groups scope is present. 41 | # If `groups` is provided, this acts as a whitelist - only the user's Crowd groups that are in the configured `groups` below will go into the groups claim. 42 | # Conversely, if the user is not in any of the configured `groups`, the user will not be authenticated. 43 | groups: 44 | - my-group 45 | # Prompt for username field. 46 | usernamePrompt: Login 47 | # Optionally set preferred_username claim. 48 | # If `preferredUsernameField` is omitted or contains an invalid option, the `preferred_username` claim will be empty. 49 | # If `preferredUsernameField` is set, the `preferred_username` claim will be set to the chosen Crowd user attribute value. 50 | # Possible choices are: "key", "name", "email" 51 | preferredUsernameField: name 52 | ``` 53 | -------------------------------------------------------------------------------- /content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dex 3 | --- 4 | 5 | {{< blocks/cover image_anchor="top" height="min">}} 6 | 7 |
8 | 9 |
10 |
11 |
12 |

Dex

13 |

A Federated OpenID Connect Provider

14 | 15 | 16 |
17 | 18 | 19 | Download 20 | 21 | 22 | Subscribe 23 | 24 | 25 | Communicate 26 | 27 | 28 | {{< /blocks/cover >}} 29 | 30 | {{% blocks/lead color="primary" %}} 31 |
32 | 33 | {{% blocks/feature icon="text-white fa-puzzle-piece" %}} 34 |
35 | Dex supports a wide range of identity providers such as LDAP, SAML, and OAuth2 and implements OpenID Connect (OIDC), allowing your application to plug in any upstream identity provider, but implement only OIDC. 36 |
37 | {{% /blocks/feature %}} 38 | {{% blocks/feature icon="text-white fa-lock" %}} 39 |
40 | Whether you’re looking to secure your internal applications, provide seamless Single Sign-On (SSO) across your organization, or create a secure public-facing platform, Dex can be tailored to meet your unique requirements. 41 |
42 | {{% /blocks/feature %}} 43 |
44 | {{% /blocks/lead %}} 45 | 46 | {{% blocks/section color="white" %}} 47 |
48 |

49 | 50 | 51 | 52 |

53 | Dex is a Cloud Native Computing Foundation sandbox project. 54 |

55 |
56 | {{% /blocks/section %}} 57 | -------------------------------------------------------------------------------- /content/docs/connectors/bitbucketcloud.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through Bitbucket Cloud" 3 | linkTitle: "Bitbucket Cloud" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2100 9 | --- 10 | 11 | ## Overview 12 | 13 | One of the login options for dex uses the Bitbucket OAuth2 flow to identify the end user through their Bitbucket account. 14 | 15 | When a client redeems a refresh token through dex, dex will re-query Bitbucket to update user information in the ID Token. To do this, __dex stores a readonly Bitbucket access token in its backing datastore.__ Users that reject dex's access through Bitbucket will also revoke all dex clients which authenticated them through Bitbucket. 16 | 17 | ## Configuration 18 | 19 | Register a new OAuth consumer with [Bitbucket](https://confluence.atlassian.com/bitbucket/oauth-on-bitbucket-cloud-238027431.html) ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`. 20 | 21 | There are several permissions required for an OAuth consumer to use it with Dex: 22 | * `Account: Read` - required for extracting base information (email, username) 23 | * `Workspace membership: Read` - only necessary to get user's teams 24 | 25 | The following is an example of a configuration for `examples/config-dev.yaml`: 26 | 27 | ```yaml 28 | connectors: 29 | - type: bitbucket-cloud 30 | # Required field for connector id. 31 | id: bitbucket-cloud 32 | # Required field for connector name. 33 | name: Bitbucket Cloud 34 | config: 35 | # Credentials can be string literals or pulled from the environment. 36 | clientID: $BITBUCKET_CLIENT_ID 37 | clientSecret: $BITBUCKET_CLIENT_SECRET 38 | redirectURI: http://127.0.0.1:5556/dex/callback 39 | # Optional teams whitelist, communicated through the "groups" scope. 40 | # If `teams` is omitted, all of the user's Bitbucket teams are returned when the groups scope is present. 41 | # If `teams` is provided, this acts as a whitelist - only the user's Bitbucket teams that are in the configured `teams` below will go into the groups claim. Conversely, if the user is not in any of the configured `teams`, the user will not be authenticated. 42 | teams: 43 | - my-team 44 | # Optional parameter to include team groups. 45 | # If enabled, the groups claim of dex id_token will looks like this: 46 | # ["my_team", "my_team/administrators", "my_team/members"] 47 | includeTeamGroups: true 48 | ``` 49 | -------------------------------------------------------------------------------- /layouts/index.redirects: -------------------------------------------------------------------------------- 1 | # Netlify redirects. See https://www.netlify.com/docs/redirects/ 2 | {{/* cSpell:ignore cond wordmark */ -}} 3 | 4 | {{ range $p := .Site.Pages -}} 5 | 6 | {{ range $p.Params.redirects -}} 7 | {{ $from := cond (strings.HasPrefix .from "/") 8 | .from 9 | (print $p.RelPermalink .from) -}} 10 | {{ $to := cond (strings.HasPrefix .to "/") 11 | .to 12 | (print $p.RelPermalink .to) -}} 13 | {{ $from | printf "%-35s" }} {{ $to }} 14 | {{ end -}} 15 | 16 | {{ range $p.Aliases -}} 17 | {{/* Temporary workaround for semconv alias errors */ -}} 18 | {{ if strings.HasPrefix . "docs/specs/semconv/general" -}} 19 | {{ . | printf "%-35s" }} {{ $p.RelPermalink }} 20 | {{ else -}} 21 | {{ $alias := cond (strings.HasPrefix . "/") 22 | . 23 | (partial "relative-redirects-alias" (dict "alias" . "p" $p.Parent)) -}} 24 | {{ $alias | printf "%-35s" }} {{ $p.RelPermalink }} 25 | {{ end -}} 26 | {{ end -}} 27 | 28 | {{ with $p.Params.redirect -}} 29 | {{ $p.RelPermalink | printf "%-35s" }} {{ . }} 30 | {{ end -}} 31 | 32 | {{ end }}{{/* range $p */ -}} 33 | 34 | {{ $languages := (.Site.GetPage "/docs/instrumentation").Pages -}} 35 | {{ range $languages -}} 36 | {{ $lang := .File.ContentBaseName -}} 37 | {{ if ne $lang "other" -}} 38 | /docs/{{ $lang }} /docs/instrumentation/{{ $lang }} 39 | /docs/{{ $lang }}/* /docs/instrumentation/{{ $lang }}/:splat 40 | {{ end -}} 41 | {{ end -}} 42 | 43 | /docs/reference/specification /docs/specs/otel 44 | /docs/reference/specification/* /docs/specs/otel/:splat 45 | /docs/specification/otel/* /docs/specs/otel/:splat 46 | 47 | {{ $schemaFiles := partial "schema-file-list" . -}} 48 | {{ $latestSchemaFile := index $schemaFiles 0 -}} 49 | 50 | /schemas/latest /schemas/{{ $latestSchemaFile.Name }} 51 | 52 | {{/* 53 | Social-media image redirects. As mentioned in 54 | https://developers.facebook.com/docs/sharing/webmasters/images, we need to 55 | preserve og:image (and other social media image) URLs forever. 56 | */ -}} 57 | 58 | {{ $og_image_current := `/img/social/logo-wordmark-001.png` -}} 59 | 60 | /featured-background.jpg {{ $og_image_current }} {{- /* homepage og:image used prior to 2022/08 */}} 61 | 62 | {{- define "partials/relative-redirects-alias" -}} 63 | {{ $result := "" }} 64 | {{ if strings.HasPrefix .alias "../" }} 65 | {{ $result = (partial "relative-redirects-alias" 66 | (dict 67 | "alias" (strings.TrimPrefix "../" .alias) 68 | "p" .p.Parent )) 69 | }} 70 | {{ else }} 71 | {{ $result = path.Join .p.RelPermalink .alias }} 72 | {{ end }} 73 | {{ return $result }} 74 | {{ end }} 75 | -------------------------------------------------------------------------------- /content/docs/connectors/oauth.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through an OAuth 2.0 Provider" 3 | linkTitle: "OAuth 2.0" 4 | description: "" 5 | date: 2021-03-15 6 | toc: true 7 | weight: 2055 8 | --- 9 | 10 | ## Overview 11 | 12 | Dex users can make use of this connector to work with standards-compliant [OAuth 2.0](https://oauth.net/2/) authorization providers, in case those authorization providers are not already in the Dex connectors list. 13 | 14 | ## Configuration 15 | 16 | The following is an example of a configuration for using OAuth connector with Reddit. 17 | 18 | ```yaml 19 | connectors: 20 | - type: oauth 21 | # ID of OAuth 2.0 provider 22 | id: reddit 23 | # Name of OAuth 2.0 provider 24 | name: reddit 25 | config: 26 | # Connector config values starting with a "$" will read from the environment. 27 | clientID: $REDDIT_CLIENT_ID 28 | clientSecret: $REDDIT_CLIENT_SECRET 29 | redirectURI: http://127.0.0.1:5556/dex/callback 30 | 31 | tokenURL: https://www.reddit.com/api/v1/access_token 32 | authorizationURL: https://www.reddit.com/api/v1/authorize 33 | userInfoURL: https://www.reddit.com/api/v1/me 34 | 35 | # Optional: Some providers return claims without "email_verified", when they had no usage of emails verification in enrollment process 36 | # or if they are acting as a proxy for another IDP etc AWS Cognito with an upstream SAML IDP 37 | # This can be overridden with the below option 38 | # insecureSkipEmailVerified: true 39 | 40 | # Optional: Specify whether to communicate to Auth provider without 41 | # validating SSL certificates 42 | # insecureSkipVerify: false 43 | 44 | # Optional: The location of file containing SSL certificates to communicate 45 | # to Auth provider 46 | # rootCAs: 47 | # - /etc/ssl/reddit.pem 48 | 49 | # Optional: List of scopes to request Auth provider for access user account 50 | # scopes: 51 | # - identity 52 | 53 | # Optional: Configurable keys for user ID look up 54 | # Default: id 55 | # userIDKey: 56 | 57 | # Auth providers return non-standard user identity profile 58 | # Use claimMapping to map those user informations to standard claims: 59 | claimMapping: 60 | # Optional: Configurable keys for user name look up 61 | # Default: user_name 62 | # userNameKey: 63 | 64 | # Optional: Configurable keys for preferred username look up 65 | # Default: preferred_username 66 | # preferredUsernameKey: 67 | 68 | # Optional: Configurable keys for user groups look up 69 | # Default: groups 70 | # groupsKey: 71 | 72 | # Optional: Configurable keys for email look up 73 | # Default: email 74 | # emailKey: 75 | 76 | # Optional: Configurable keys for email verified look up 77 | # Default: email_verified 78 | # emailVerifiedKey: 79 | ``` 80 | -------------------------------------------------------------------------------- /content/docs/connectors/gitlab.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through GitLab" 3 | linkTitle: "GitLab" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2040 9 | --- 10 | 11 | ## Overview 12 | 13 | GitLab is a web-based Git repository manager with wiki and issue tracking features, using an open source license, developed by GitLab Inc. One of the login options for dex uses the GitLab OAuth2 flow to identify the end user through their GitLab account. You can use this option with [gitlab.com](https://gitlab.com), GitLab community or enterprise edition. 14 | 15 | When a client redeems a refresh token through dex, dex will re-query GitLab to update user information in the ID Token. To do this, __dex stores a readonly GitLab access token in its backing datastore.__ Users that reject dex's access through GitLab will also revoke all dex clients which authenticated them through GitLab. 16 | 17 | ## Configuration 18 | 19 | Register a new application via `User Settings -> Applications` ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`. 20 | 21 | The application requires the user to grant the `read_user` and `openid` scopes. The latter is required only if group membership is a desired claim. 22 | 23 | The following is an example of a configuration for `examples/config-dev.yaml`: 24 | 25 | ```yaml 26 | connectors: 27 | - type: gitlab 28 | # Required field for connector id. 29 | id: gitlab 30 | # Required field for connector name. 31 | name: GitLab 32 | config: 33 | # optional, default = https://gitlab.com 34 | baseURL: https://gitlab.com 35 | # Credentials can be string literals or pulled from the environment. 36 | clientID: $GITLAB_APPLICATION_ID 37 | clientSecret: $GITLAB_CLIENT_SECRET 38 | redirectURI: http://127.0.0.1:5556/dex/callback 39 | # Optional groups whitelist, communicated through the "groups" scope. 40 | # If `groups` is omitted, all of the user's GitLab groups are returned when the groups scope is present. 41 | # If `groups` is provided, this acts as a whitelist - only the user's GitLab groups that are in the configured `groups` below will go into the groups claim. Conversely, if the user is not in any of the configured `groups`, the user will not be authenticated. 42 | groups: 43 | - my-group 44 | # flag which will switch from using the internal GitLab id to the users handle (@mention) as the user id. 45 | # It is possible for a user to change their own user name but it is very rare for them to do so 46 | useLoginAsID: false 47 | # Flag to include user group permissions in the user groups. 48 | # For example, if the user has maintainer access to a GitLab group named "project/group1", 49 | # the user's groups will reflect two entries: "project/group1" and "project/group1:maintainer". 50 | getGroupsPermission: false 51 | ``` 52 | -------------------------------------------------------------------------------- /content/docs/configuration/oauth2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "OAuth2" 3 | description: "OAuth2 flow customization options" 4 | date: 2024-01-05 5 | draft: false 6 | toc: true 7 | weight: 1060 8 | --- 9 | Dex provides a range of configurable options that empower you to fine-tune and personalize various aspects of the authentication and user flow. 10 | 11 | ## Flow Customization 12 | Customize OAuth2 settings to align with your authentication requirements. 13 | 14 | ```yaml 15 | oauth2: 16 | responseTypes: [ "code" ] 17 | skipApprovalScreen: true 18 | alwaysShowLoginScreen: false 19 | ``` 20 | 21 | ### Authentication flow 22 | * `responseTypes` - allows you to configure the desired auth flow (`Authorization Code Flow`, `Implicit Flow`, or `Hybrid Flow`) based on different values. See the table below for valid configuration options. 23 | 24 | | `responseTypes` value | flow | 25 | |------------------------|-------------------------| 26 | | `code` | Authorization Code Flow | 27 | | `id_token` | Implicit Flow | 28 | | `id_token token` | Implicit Flow | 29 | | `code id_token` | Hybrid Flow | 30 | | `code token` | Hybrid Flow | 31 | | `code id_token token` | Hybrid Flow | 32 | Examples of the different flows and their behavior can be found in the [official openid spec](https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationExamples). 33 | 34 | ### User flow 35 | 36 | Customizing the user flow allows you to influence how users login into your application. 37 | 38 | * `skipApprovalScreen` - controls the need for user approval before sharing data with connected applications. If enabled, users must approve data sharing with every auth flow. 39 | {{% alert color="info" %}} 40 | This setting is not applicable when the request has the `approval_prompt=force` parameter. In this case, the approval screen is always shown. 41 | {{% /alert %}} 42 | * `alwaysShowLoginScreen` - whether to always display the login screen. If only one authentication method is enabled, the default behavior is to go directly to it. For connected IdPs, this redirects the browser away from the application to upstream provider, such as the Google login page. 43 | 44 | ## Password grants 45 | Password grants involve clients directly sending a user's credentials (`username` and `password`) to the authorization server (dex), acquiring access tokens without the need for an intermediate authorization step. 46 | ```yaml 47 | oauth2: 48 | passwordConnector: local 49 | ``` 50 | * `passwordConnector` - specifies the connector's id that is used for password grants 51 | 52 | {{% alert title="Warning" color="warning" %}} 53 | The password grant type is not recommended for use by the [OAuth 2.0 Security Best Current Practice](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-13#section-3.4) because of serious security concerns. 54 | Please see [oauth.net](https://oauth.net/2/grant-types/password/) for additional information. 55 | {{% /alert %}} 56 | -------------------------------------------------------------------------------- /assets/sass/custom.sass: -------------------------------------------------------------------------------- 1 | // Custom.scss 2 | @charset "utf-8" 3 | 4 | {{ $extraColors := site.Params.colors.extra }} 5 | {{ $fontAwesomeVersion := site.Params.font_awesome_version }} 6 | {{ $fonts := site.Params.fonts }} 7 | 8 | {{ with $fontAwesomeVersion }} 9 | {{ $fontAwesomeUrl := printf "https://use.fontawesome.com/releases/v%s/css/all.css" . }} 10 | @import url("{{ $fontAwesomeUrl }}") 11 | {{ end }} 12 | 13 | {{ if $fonts }} 14 | {{ $fontSlice := (slice) }} 15 | {{ range $fonts }} 16 | {{ $fontSlice = $fontSlice | append (printf "%s:%s" (replace .name " " "+") (delimit .sizes ",")) }} 17 | {{ end }} 18 | {{ $fontsUrl := printf "https://fonts.googleapis.com/css?family=%s" (delimit $fontSlice "|") }} 19 | @import url("{{ $fontsUrl }}") 20 | {{ end }} 21 | 22 | 23 | // Required 24 | @import "bootstrap/scss/functions" 25 | @import "bootstrap/scss/variables" 26 | @import "bootstrap/scss/mixins" 27 | @import "bootstrap/scss/root" 28 | 29 | //Optional 30 | @import "bootstrap/scss/reboot" 31 | @import "bootstrap/scss/type" 32 | @import "bootstrap/scss/images" 33 | @import "bootstrap/scss/code" 34 | @import "bootstrap/scss/grid" 35 | @import "bootstrap/scss/tables" 36 | @import "bootstrap/scss/forms" 37 | @import "bootstrap/scss/buttons" 38 | @import "bootstrap/scss/transitions" 39 | @import "bootstrap/scss/dropdown" 40 | //@import "bootstrap/scss/button-group" 41 | //@import "bootstrap/scss/input-group" 42 | //@import "bootstrap/scss/custom-forms" 43 | @import "bootstrap/scss/nav" 44 | @import "bootstrap/scss/navbar" 45 | //@import "bootstrap/scss/card" 46 | //@import "bootstrap/scss/breadcrumb" 47 | //@import "bootstrap/scss/pagination" 48 | //@import "bootstrap/scss/badge" 49 | @import "bootstrap/scss/jumbotron" 50 | //@import "bootstrap/scss/alert" 51 | //@import "bootstrap/scss/progress" 52 | //@import "bootstrap/scss/media" 53 | //@import "bootstrap/scss/list-group" 54 | //@import "bootstrap/scss/close" 55 | //@import "bootstrap/scss/toasts" 56 | //@import "bootstrap/scss/modal" 57 | //@import "bootstrap/scss/tooltip" 58 | //@import "bootstrap/scss/popover" 59 | //@import "bootstrap/scss/carousel" 60 | //@import "bootstrap/scss/spinners" 61 | @import "bootstrap/scss/utilities" 62 | //@import "bootstrap/scss/print" 63 | 64 | 65 | // Custom 66 | 67 | $font-family-headers: "Fira Sans" 68 | 69 | .logo 70 | max-width: 85px 71 | 72 | .breadcrumb 73 | li 74 | list-style: none 75 | display: inline 76 | ul 77 | padding-left: 0 78 | 79 | .hashlink 80 | font-size: smaller !important 81 | 82 | .highlight pre 83 | padding: 0.5rem 84 | border-radius: 5px 85 | 86 | .content 87 | table 88 | @extend .table 89 | 90 | img 91 | @extend .img-fluid 92 | 93 | h1, h2, h3, h4, h5, h6 94 | font-family: $font-family-headers 95 | scroll-margin-top: 5rem 96 | margin-top: 1.8rem 97 | 98 | nav 99 | ul 100 | list-style-type: none 101 | padding-left: 0 102 | ul 103 | padding-left: 1.5rem 104 | 105 | .jumbotron img 106 | @extend .img-fluid 107 | max-width: 90% 108 | height: auto 109 | 110 | .jumbotron 111 | background-color: #86c6df65 112 | // background-color: transparent !important 113 | -------------------------------------------------------------------------------- /content/docs/development/releases.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Releases" 3 | description: "" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 3100 8 | --- 9 | 10 | Releasing a new version of Dex can be done by one of the core maintainers with push access to the 11 | [git repository](https://github.com/dexidp/dex). 12 | It's usually good to have an extra pair of eyes ready when tagging a new release though, 13 | so feel free to ask a peer to be ready in case anything goes wrong or you need a review. 14 | 15 | The release process is semi-automated at the moment: artifacts are automatically built and published to 16 | GitHub Container Registry (primary source of container images) and Docker Hub. 17 | 18 | The GitHub release needs to be manually created (use past releases as templates). 19 | 20 | > *Note:* this will hopefully be improved in the future. 21 | 22 | 23 | ## Tagging a new release 24 | 25 | Make sure you've [uploaded your GPG key](https://github.com/settings/keys) and 26 | configured git to [use that signing key]( 27 | https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) either globally or 28 | for the Dex repo. Note that the email the key is issued for must be the email 29 | you use for git. 30 | 31 | ```bash 32 | git config [--global] user.signingkey "{{ GPG key ID }}" 33 | git config [--global] user.email "{{ Email associated with key }}" 34 | ``` 35 | 36 | Create a signed tag at the commit you wish to release. 37 | 38 | ```bash 39 | RELEASE_VERSION=v2.0.0 40 | git tag -s -m "Release $RELEASE_VERSION" $RELEASE_VERSION # optionally: commit hash as the last argument 41 | ``` 42 | 43 | Push that tag to the Dex repo. 44 | 45 | ```bash 46 | git push origin $RELEASE_VERSION 47 | ``` 48 | 49 | Draft releases on GitHub and summarize the changes since the last release. 50 | See [previous releases](https://github.com/dexidp/dex/releases) for the expected format. 51 | 52 | 53 | ## Patch releases 54 | 55 | Occasionally, patch releases might be necessary to fix an urgent bug or vulnerability. 56 | 57 | First, check if there is a release branch for a minor release. Create one if necessary: 58 | 59 | ```bash 60 | MINOR_RELEASE="v2.1.0" 61 | RELEASE_BRANCH="v2.1.x" 62 | git checkout -b $RELEASE_BRANCH tags/$MINOR_RELEASE 63 | git push origin $RELEASE_BRANCH 64 | ``` 65 | 66 | If a patch version is needed (2.1.1, 2.1.2, etc.), checkout the desired release branch and cherry pick specific commits. 67 | 68 | ```bash 69 | RELEASE_BRANCH="v2.1.x" 70 | git checkout $RELEASE_BRANCH 71 | git checkout -b "cherry-picked-change" 72 | git cherry-pick (SHA of change) 73 | git push origin "cherry-picked-change" 74 | ``` 75 | 76 | Open a PR onto `$RELEASE_BRANCH` to get the changes approved. 77 | 78 | Continue with the regular release process. 79 | 80 | ## Dex API 81 | 82 | If there are changes in the API, the API version should be bumped to appear correctly in 83 | the [pkg.go.dev](https://pkg.go.dev/github.com/dexidp/dex/api/v2) and be able to 84 | be pulled by tags (via go get or go modules). 85 | 86 | Create a new tag with the `api/` path: 87 | ```bash 88 | RELEASE_VERSION=v2.3.0 89 | git tag -s -m "${RELEASE_VERSION} Dex API release" "api/${RELEASE_VERSION}" 90 | ``` 91 | 92 | Push that tag to the Dex repo. 93 | 94 | ```bash 95 | git push origin "api/${RELEASE_VERSION}" 96 | ``` 97 | -------------------------------------------------------------------------------- /content/docs/connectors/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Connectors" 3 | description: "Documentation about configuration of Dex connectors" 4 | date: 2020-01-07T14:59:38+01:00 5 | draft: false 6 | toc: true 7 | weight: 2000 8 | --- 9 | 10 | When a user logs in through Dex, the user's identity is usually stored in another user-management system: a LDAP directory, a GitHub org, etc. Dex acts as a shim between a client app and the upstream identity provider. The client only needs to understand OpenID Connect to query Dex, while Dex implements an array of protocols for querying other user-management systems. 11 | 12 | ![](/img/dex-flow.png) 13 | 14 | A "connector" is a strategy used by Dex for authenticating a user against another identity provider. Dex implements connectors that target specific platforms such as GitHub, LinkedIn, and Microsoft as well as established protocols like LDAP and SAML. 15 | 16 | Depending on the connectors limitations in protocols can prevent Dex from issuing [refresh tokens][scopes] or returning [group membership][scopes] claims. For example, because SAML doesn't provide a non-interactive way to refresh assertions, if a user logs in through the SAML connector Dex won't issue a refresh token to its client. Refresh token support is required for clients that require offline access, such as `kubectl`. 17 | 18 | Dex implements the following connectors: 19 | 20 | | Name | supports refresh tokens | supports groups claim | supports preferred_username claim | status | notes | 21 | | ---- | ----------------------- | --------------------- | --------------------------------- | ------ | ----- | 22 | | [LDAP](/docs/connectors/ldap/) | yes | yes | yes | stable | | 23 | | [GitHub](/docs/connectors/github/) | yes | yes | yes | stable | | 24 | | [SAML 2.0](/docs/connectors/saml/) | no | yes | no | stable | 25 | | [GitLab](/docs/connectors/gitlab/) | yes | yes | yes | beta | | 26 | | [OpenID Connect](/docs/connectors/oidc/) | yes | yes | yes | beta | Includes Salesforce, Azure, etc. | 27 | | [OAuth 2.0](/docs/connectors/oauth/) | no | yes | yes | alpha | 28 | | [Google](/docs/connectors/google/) | yes | yes | yes | alpha | | 29 | | [LinkedIn](/docs/connectors/linkedin/) | yes | no | no | beta | | 30 | | [Microsoft](/docs/connectors/microsoft/) | yes | yes | no | beta | | 31 | | [AuthProxy](/docs/connectors/authproxy/) | no | no | no | alpha | Authentication proxies such as Apache2 mod_auth, etc. | 32 | | [Bitbucket Cloud](/docs/connectors/bitbucketcloud/) | yes | yes | no | alpha | | 33 | | [OpenShift](/docs/connectors/openshift/) | no | yes | no | stable | | 34 | | [Atlassian Crowd](/docs/connectors/atlassian-crowd/) | yes | yes | yes * | beta | preferred_username claim must be configured through config | 35 | | [Gitea](/docs/connectors/gitea/) | yes | no | yes | alpha | | 36 | | [OpenStack Keystone](/docs/connectors/keystone/) | yes | yes | no | alpha | | 37 | 38 | 39 | Stable, beta, and alpha are defined as: 40 | 41 | * Stable: well tested, in active use, and will not change in backward incompatible ways. 42 | * Beta: tested and unlikely to change in backward incompatible ways. 43 | * Alpha: may be untested by core maintainers and is subject to change in backward incompatible ways. 44 | 45 | All changes or deprecations of connector features will be announced in the [release notes.][release-notes] 46 | 47 | [scopes]: /docs/configuration/custom-scopes-claims-clients/#scopes 48 | [release-notes]: https://github.com/dexidp/dex/releases 49 | -------------------------------------------------------------------------------- /content/docs/connectors/openshift.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication using OpenShift" 3 | linkTitle: "OpenShift" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2110 9 | --- 10 | 11 | ## Overview 12 | 13 | Dex can make use of users and groups defined within OpenShift by querying the platform provided OAuth server. 14 | 15 | ## Configuration 16 | 17 | 18 | ### Creating an OAuth Client 19 | 20 | Two forms of OAuth Clients can be utilized: 21 | 22 | * [Using a Service Account as an OAuth Client](https://docs.openshift.com/container-platform/latest/authentication/using-service-accounts-as-oauth-client.html) (Recommended) 23 | * [Registering An Additional OAuth Client](https://docs.openshift.com/container-platform/latest/authentication/configuring-internal-oauth.html#oauth-register-additional-client_configuring-internal-oauth) 24 | 25 | #### Using a Service Account as an OAuth Client 26 | 27 | OpenShift Service Accounts can be used as a constrained form of OAuth client. Making use of a Service Account to represent an OAuth Client is the recommended option as it does not require elevated privileged within the OpenShift cluster. Create a new Service Account or make use of an existing Service Account. 28 | 29 | Patch the Service Account to add an annotation for location of the Redirect URI 30 | 31 | ```bash 32 | oc patch serviceaccount --type='json' -p='[{"op": "add", "path": "/metadata/annotations/serviceaccounts.openshift.io~1oauth-redirecturi.dex", "value":"https:///callback"}]' 33 | ``` 34 | 35 | The Client ID for a Service Account representing an OAuth Client takes the form `system:serviceaccount::` 36 | 37 | The Client Secret for a Service Account representing an OAuth Client is the long lived OAuth Token that is configued for the Service Account. Execute the following command to retrieve the OAuth Token. 38 | 39 | ```bash 40 | oc serviceaccounts get-token 41 | ``` 42 | 43 | #### Registering An Additional OAuth Client 44 | 45 | Instead of using a constrained form of Service Account to represent an OAuth Client, an additional OAuthClient resource can be created. 46 | 47 | Create a new OAuthClient resource similar to the following: 48 | 49 | ```yaml 50 | kind: OAuthClient 51 | apiVersion: oauth.openshift.io/v1 52 | metadata: 53 | name: dex 54 | # The value that should be utilized as the `client_secret` 55 | secret: "" 56 | # List of valid addresses for the callback. Ensure one of the values that are provided is `(dex issuer)/callback` 57 | redirectURIs: 58 | - "https:////callback" 59 | grantMethod: prompt 60 | ``` 61 | 62 | ### Dex Configuration 63 | 64 | The following is an example of a configuration for `examples/config-dev.yaml`: 65 | 66 | ```yaml 67 | connectors: 68 | - type: openshift 69 | # Required field for connector id. 70 | id: openshift 71 | # Required field for connector name. 72 | name: OpenShift 73 | config: 74 | # OpenShift API 75 | issuer: https://api.mycluster.example.com:6443 76 | # Credentials can be string literals or pulled from the environment. 77 | clientID: $OPENSHIFT_OAUTH_CLIENT_ID 78 | clientSecret: $OPENSHIFT_OAUTH_CLIENT_SECRET 79 | redirectURI: http://127.0.0.1:5556/dex/ 80 | # Optional: Specify whether to communicate to OpenShift without validating SSL certificates 81 | insecureCA: false 82 | # Optional: The location of file containing SSL certificates to communicate to OpenShift 83 | rootCA: /etc/ssl/openshift.pem 84 | # Optional list of required groups a user must be a member of 85 | groups: 86 | - users 87 | ``` 88 | -------------------------------------------------------------------------------- /content/community.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Community" 3 | type: "simple" 4 | menu: {main: { weight: 30 }} 5 | --- 6 | 7 | Welcome to the Dex Identity Provider (IdP) Community Page! 8 | 9 | Dex IdP is a cutting-edge identity provider that empowers organizations with seamless authentication and authorization solutions. Whether you're a developer, IT professional, or security enthusiast, this community page is your hub for all things Dex. 10 | 11 | ## Resources 12 | 13 | - [Source code](https://github.com/dexidp/dex) 14 | - [Documentation](/docs/) 15 | - [Issue tracker](https://github.com/dexidp/dex/issues) 16 | - [Discussions](https://github.com/dexidp/dex/discussions) 17 | - [Slack channel](https://cloud-native.slack.com/messages/dexidp) 18 | 19 | ## Questions and help 20 | 21 | - Use [GitHub Discussions](https://github.com/dexidp/dex/discussions/new?category=q-a) for discussions and asking questions 22 | - Search the [documentation](/docs/) 23 | - Join the [Slack](https://cloud-native.slack.com/messages/dexidp) channel for conversations 24 | 25 | We generally prefer GitHub Discussions for help requests as they are searchable and remain available to other members of the community. 26 | 27 | {{< card header="📣 **Announcements**" >}} 28 | The primary channel for release announcements is GitHub Discussions. 29 | We also post information about other important changes there. 30 | 31 |

32 | Security vulnerabilities are tracked on GitHub and are published as security advisories. 33 |

34 |

35 | In addition to the above, we also usually cross-post announcements to our Slack channel on CNCF Slack. 36 |

37 | {{< /card >}} 38 |
39 | {{< cardpane >}} 40 | {{< card header="🛡️ **Reporting security vulnerabilities**" >}} 41 | If you've found a security vulnerability, please follow the disclosure process outlined here. 42 |

43 | Alternatively, you can open a draft security advisory on GitHub. 44 | This is where we keep track of vulnerabilities (and the work necessary to fix them) anyway, 45 | so you can help us by filling out the necessary details in advance. 46 | {{< /card >}} 47 | 48 | {{< card header="🐛 **Reporting bugs**" >}} 49 | Before reporting a bug or feature request, please: 50 | 54 | If it hasn't already been fixed or reported, create an issue in GitHub Issues. 55 | {{< /card >}} 56 | {{< /cardpane >}} 57 | 58 | {{< card header="🚀 **Requesting features and enhancements**" >}} 59 | If you are interested in contributing, feel free to reach out to the maintainers in one of the available communication channels. 60 | They will help you get started. (A more detailed contribution guide is in the works) 61 | 62 | Otherwise, open a feature request in GitHub Issues. 63 | 64 | {{% pageinfo color="primary" %}} 65 | **Note:** If you are not sure if the nature of your requests fits into Dex or just want to discuss it first, we encourage you to reach out on GitHub Discussions first. 66 | {{% /pageinfo %}} 67 | {{< /card >}} 68 | -------------------------------------------------------------------------------- /content/docs/archive/v2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Dex v2" 3 | linkTitle: "What's new in v2" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 1030 9 | --- 10 | 11 | ## Streamlined deployments 12 | 13 | Many of the changes between v1 and v2 were aimed at making dex easier to deploy and manage, perhaps the biggest pain point for dex v1. Dex is now a single, scalable binary with a sole source of configuration. Many components which previously had to be set through the API, such as OAuth2 clients and IDP connectors can now be specified statically. The new architecture lacks a singleton component eliminating deployment ordering. There are no more special development modes; instructions for running dex on a workstation translate with minimal changes to a production system. 14 | 15 | All of this results in a much simpler deployment story. Write a config file, run the dex binary, and that's it. 16 | 17 | ## More storage backends 18 | 19 | Dex's internal storage interface has been improved to support multiple backing databases including Postgres, SQLite3, and the Kubernetes API through Third Party Resources. This allows dex to meet a more diverse set of use cases instead of insisting on one particular deployment pattern. For example, The Kubernetes API implementation, a [key value store][k8s-api-docs], allows dex to be run natively on top of a Kubernetes cluster with extremely little administrative overhead. Starting with support for multiple storage backends also should help ensure that the dex storage interface is actually pluggable, rather than being coupled too tightly with a single implementation. 20 | 21 | A more in depth discussion of existing storage options and how to add new ones can be found [here][storage-docs]. 22 | 23 | ## Additional improvements 24 | 25 | The rewrite came with several, miscellaneous improvements including: 26 | 27 | * More powerful connectors. For example the GitHub connector can now query for teams. 28 | * Combined the two APIs into a single [gRPC API][api-docs] with no complex authorization rules. 29 | * Expanded OAuth2 capabilities such as the implicit flow. 30 | * Simplified codebase and improved testing. 31 | 32 | ## Rethinking registration 33 | 34 | Dex v1 performed well when it could manage users. It provided features such as registration, email invites, password resets, administrative abilities, etc. However, login flows and APIs remain tightly coupled with concepts like registration and admin users even when v1 federated to an upstream identity provider (IDP) where it likely only had read only access to the actual user database. 35 | 36 | Many of v2's use cases focus on federation to other IPDs rather than managing users itself. Because of this, options associated with registration, such as SMTP credentials, have been removed. We hope to add registration and user management back into the project through orthogonal applications using the [gRPC API][api-docs], but in a way that doesn't impact other use cases. 37 | 38 | ## Removed features 39 | 40 | Dex v2 lacks certain features present in v1. For the most part _we aim to add most of these features back into v2_, but in a way that installations have to _opt in_ to a feature instead of burdening every deployment with extra configuration. 41 | 42 | Notable missing features include: 43 | 44 | * Registration flows. 45 | * Local user management. 46 | * SMTP configuration and email verification. 47 | * Several of the login connectors that have yet to be ported. 48 | 49 | ## Support for dex v1 50 | 51 | Dex v1 will continue to live under the `github.com/dexidp/dex` repo on a branch. Bug fixes and minor changes will continue to be accepted, but development of new features by the dex team will largely cease. 52 | 53 | [k8s-api-docs]: http://kubernetes.io/docs/api/ 54 | [storage-docs]: /docs/configuration/storage 55 | [api-docs]: /docs/configuration/api 56 | -------------------------------------------------------------------------------- /content/docs/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting Started" 3 | description: "First touch with Dex" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 1010 8 | type: "docs" 9 | --- 10 | 11 | ## Container image 12 | 13 | Dex is primarily distributed as a container image, published to the following locations: 14 | 15 | - [ghcr.io/dexidp/dex](https://github.com/dexidp/dex/pkgs/container/dex) 16 | - [docker.io/dexidp/dex](https://hub.docker.com/r/dexidp/dex/tags) 17 | 18 | 2 variants (`alpine` and `distroless`) of container images are provided 19 | based on Alpine Linux and Distroless base images. 20 | 21 | A reference Kubernetes Helm chart for dex can be found at [charts.dexidp.io](https://charts.dexidp.io). 22 | 23 | ## Building the dex binary 24 | 25 | To build dex from source code, install a working Go environment with version 1.19 or greater according to the [official documentation][go-setup]. 26 | Then clone the repository and use `make` to compile the dex binary. 27 | 28 | ```bash 29 | $ git clone https://github.com/dexidp/dex.git 30 | $ cd dex/ 31 | $ make build 32 | ``` 33 | 34 | ## Configuration 35 | 36 | Dex exclusively pulls configuration options from a config file. Use the [example config][example-config] file found in the `examples/` directory to start an instance of dex with a sqlite3 data store, and a set of predefined OAuth2 clients. 37 | 38 | ```bash 39 | ./bin/dex serve examples/config-dev.yaml 40 | ``` 41 | 42 | The [example config][example-config] file documents many of the configuration options through inline comments. For extra config options, look at that file. 43 | 44 | ### Templated configuration 45 | 46 | The default entrypoint for distributed container images utilize [gomplate][gomplate] 47 | to pre-process configuration files (`.tpl`, `.tmpl`, `.yaml`) passed as arguments. 48 | This enables templating any field from the environment, for example: 49 | 50 | ```yaml 51 | secret: "{{ .Env.MY_SECRET_ENV }}" 52 | ``` 53 | 54 | See [gomplate docs][gomplate-docs] for templating syntax. 55 | 56 | ## Running a client 57 | 58 | Dex operates like most other OAuth2 providers. Users are redirected from a client app to dex to login. Dex ships with an example client app (built with the `make examples` command), for testing and demos. 59 | 60 | By default, the example client is configured with the same OAuth2 credentials defined in `examples/config-dev.yaml` to talk to dex. Running the example app will cause it to query dex's [discovery endpoint][oidc-discovery] and determine the OAuth2 endpoints. 61 | 62 | ```bash 63 | ./bin/example-app 64 | ``` 65 | 66 | Login to dex through the example app using the following steps. 67 | 68 | 1. Navigate to the example app at http://localhost:5555/ in your browser. 69 | 2. Hit "login" on the example app to be redirected to dex. 70 | 3. Choose an option to authenticate: 71 | - "Login with Example" to use mocked user data. 72 | - "Login with Email" to fill the form with static user credentials `admin@example.com` and `password`. 73 | 4. Approve the example app's request. 74 | 5. See the resulting token the example app claims from dex. 75 | 76 | ## Further reading 77 | 78 | Dex is generally used as a building block to drive authentication for other apps. See [_"Writing apps that use Dex"_][using-dex] for an overview of instrumenting apps to work with dex. 79 | 80 | For a primer on using LDAP to back dex's user store, see the OpenLDAP [_"Getting started"_](/docs/connectors/ldap/#getting-started) example. 81 | 82 | Check out the Documentation directory for further reading on setting up different storages, interacting with the dex API, intros for OpenID Connect, and logging in through other identity providers such as Google, GitHub, or LDAP. 83 | 84 | [go-setup]: https://golang.org/doc/install 85 | [example-config]: https://github.com/dexidp/dex/blob/master/examples/config-dev.yaml 86 | [gomplate]: https://github.com/hairyhenderson/gomplate 87 | [gomplate-docs]: https://docs.gomplate.ca/ 88 | [oidc-discovery]: https://openid.net/specs/openid-connect-discovery-1_0-17.html#ProviderMetadata 89 | [using-dex]: /docs//using-dex/ 90 | -------------------------------------------------------------------------------- /assets/icons/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 17 | 22 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /static/img/logos/dex-horizontal-color.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 17 | 22 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /static/img/logos/dex-horizontal-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 17 | 22 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /content/docs/connectors/google.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through Google" 3 | linkTitle: "Google" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2060 9 | --- 10 | 11 | ## Overview 12 | 13 | Dex is able to use Google's OpenID Connect provider as an authentication source. 14 | 15 | The connector uses the same authentication flow as the OpenID Connect provider but adds Google specific features such as Hosted domain support and reading groups using a service account. 16 | 17 | ## Configuration 18 | 19 | ```yaml 20 | connectors: 21 | - type: google 22 | id: google 23 | name: Google 24 | config: 25 | 26 | # Connector config values starting with a "$" will read from the environment. 27 | clientID: $GOOGLE_CLIENT_ID 28 | clientSecret: $GOOGLE_CLIENT_SECRET 29 | 30 | # Dex's issuer URL + "/callback" 31 | redirectURI: http://127.0.0.1:5556/dex/callback 32 | 33 | # Set the value of `prompt` query parameter in the authorization request 34 | # The default value is "consent" when not set. 35 | # promptType: consent 36 | 37 | # Google supports whitelisting allowed domains when using G Suite 38 | # (Google Apps). The following field can be set to a list of domains 39 | # that can log in: 40 | # 41 | # hostedDomains: 42 | # - example.com 43 | 44 | # The Google connector supports whitelisting allowed groups when using G Suite 45 | # (Google Apps). The following field can be set to a list of groups 46 | # that can log in: 47 | # 48 | # groups: 49 | # - admins@example.com 50 | 51 | # Google does not support the OpenID Connect groups claim and only supports 52 | # fetching a user's group membership with a service account. 53 | # This service account requires an authentication JSON file and the email 54 | # of a G Suite admin to impersonate: 55 | # 56 | #serviceAccountFilePath: googleAuth.json 57 | #domainToAdminEmail: 58 | # *: super-user@example.com 59 | # my-domain.com: super-user@my-domain.com 60 | ``` 61 | 62 | ## Fetching groups from Google 63 | 64 | To allow Dex to fetch group information from Google, you will need to configure a service account for Dex to use. 65 | This account needs Domain-Wide Delegation and permission to access the `https://www.googleapis.com/auth/admin.directory.group.readonly` API scope. 66 | 67 | To get group fetching set up: 68 | 69 | 1. Follow the [instructions](https://developers.google.com/admin-sdk/directory/v1/guides/delegation) to set up a service account with Domain-Wide Delegation 70 | - During service account creation, a JSON key file will be created that contains authentication information for the service account. This needs storing in a location accessible by Dex and you will set the `serviceAccountFilePath` to point at it. 71 | - When delegating the API scopes to the service account, delegate the `https://www.googleapis.com/auth/admin.directory.group.readonly` scope and only this scope. If you delegate more scopes to the service account, it will not be able to access the API. 72 | 2. Enable the [Admin SDK](https://console.developers.google.com/apis/library/admin.googleapis.com/) 73 | 3. Add the `serviceAccountFilePath` and `domainToAdminEmail` configuration options to your Dex config. 74 | - `serviceAccountFilePath` should point to the location of the service account JSON key file 75 | - `domainToAdminEmail` should map the base domain to the email address of a Google Workspace user with a minimum of the `Groups Reader (BETA)` Role assigned. The service account you created earlier will impersonate this user when making calls to the admin API. A valid user should be able to retrieve a list of groups when [testing the API](https://developers.google.com/admin-sdk/directory/v1/reference/groups/list#try-it). 76 | 77 | ## Consent Screen 78 | 79 | Dex will set `prompt=consent` by default when redirecting users to Google's 80 | authorization endpoint. This will force users to see the consent screen every 81 | time they log in. 82 | 83 | To change this behavior, you can set the `promptType` field in config file to 84 | any OIDC-supported value. To skip the consent screen for every authorization 85 | request, set `promptType` to `""` (empty string) to fall back to Google's 86 | default behavior. 87 | -------------------------------------------------------------------------------- /content/docs/archive/proposals/token-revocation.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Proposal: Design for Revoking Refresh Tokens" 3 | linkTitle: "Design for Revoking Refresh Tokens" 4 | description: "" 5 | date: 2020-09-30 6 | draft: true 7 | toc: true 8 | weight: 20 9 | --- 10 | 11 | Refresh tokens are issued to the client by the authorization server and are used 12 | to request a new access token when the current access token becomes invalid or expires. 13 | It is a common usecase for the end users to revoke client access to their identity. 14 | This proposal defines the changes needed in Dex v2 to support refresh token revocation. 15 | 16 | ## Motivation 17 | 18 | 1. Currently refresh tokens are not associated with the user. Need a new "session object" for this. 19 | 2. Need an API to list refresh tokens based on the UserID. 20 | 3. We need a way for users to login to dex and revoke a client. 21 | 4. Limit the number refresh tokens for each user-client pair to 1. 22 | 23 | ## Details 24 | 25 | Currently in Dex when an end user successfully logs in via a connector and has the OfflineAccess 26 | scope set to true, a refresh token is created and stored in the backing datastore. There is no 27 | association between the end user and the refresh token. Hence if we want to support the functionality 28 | of users being able to revoke refresh tokens, the first step is to have a structure in place that allows 29 | us retrieve a list of refresh tokens depending on the authenticated user. 30 | 31 | ```go 32 | // Reference object for RefreshToken containing only metadata. 33 | type RefreshTokenRef struct { 34 | // ID of the RefreshToken 35 | ID string 36 | CreatedAt time.Time 37 | LastUsed time.Time 38 | } 39 | 40 | // Session objects pertaining to users with refresh tokens. 41 | // 42 | // Will have to handle garbage collection i.e. if no refresh token exists for a user, 43 | // this object must be cleaned up. 44 | type OfflineSession struct { 45 | // UserID of an end user who has logged into the server. 46 | UserID string 47 | // The ID of the connector used to login the user. 48 | ConnID string 49 | // List of pointers to RefreshTokens issued for SessionID 50 | Refresh []*RefreshTokenRef 51 | } 52 | 53 | // Retrieve OfflineSession obj for given userId and connID 54 | func getOfflineSession (userId string, connID string) 55 | 56 | ``` 57 | 58 | ### Changes in Dex CodeFlows 59 | 60 | 1. Client requests a refresh token: 61 | Try to retrieve the `OfflineSession` object for the User with the given `UserID + ConnID`. 62 | This leads to two possibilities: 63 | * Object exists: This means a Refresh token already exists for the user. 64 | Update the existing `OfflineSession` object with the newly received token as follows: 65 | * CreateRefresh() will create a new `RefreshToken` obj in the storage. 66 | * Update the `Refresh` list with the new `RefreshToken` pointer. 67 | * Delete the old refresh token in storage. 68 | 69 | * No object found: This implies that this will be the first refresh token for the user. 70 | * CreateRefresh() will create a new `RefreshToken` obj in the storage. 71 | * Create an OfflineSession for the user and add the new `RefreshToken` pointer to 72 | the `Refresh` list. 73 | 74 | 2. Refresh token rotation: 75 | There will be no change to this codeflow. When the client refreshes a refresh token, the `TokenID` 76 | still remains intact and only the `RefreshToken` obj gets updated with a new nonce. We do not need 77 | any additional checks in the OfflineSession objects as the `RefreshToken` pointers still remain intact. 78 | 79 | 3. User revokes a refresh token (New functionality): 80 | A user that has been authenticated externally will have the ability to revoke their refresh tokens. 81 | Please note that Dex's API does not perform the authentication, this will have to be done by an 82 | external app. 83 | Steps involved: 84 | * Get `OfflineSession` obj with given UserID + ConnID. 85 | * If a refresh token exists in `Refresh`, delete the `RefreshToken` (handle this in storage) 86 | and its pointer value in `Refresh`. Clean up the OfflineSession object. 87 | * If there is no refresh token found, handle error case. 88 | 89 | NOTE: To avoid race conditions between “requesting a refresh token” and “revoking a refresh token”, use 90 | locking mechanism when updating an `OfflineSession` object. 91 | -------------------------------------------------------------------------------- /assets/sass/content.sass: -------------------------------------------------------------------------------- 1 | // This file is a "fork" of https://github.com/jgthms/bulma/blob/master/sass/elements/content.sass 2 | 3 | $content-heading-color: $text-strong !default 4 | $content-heading-weight: $weight-semibold !default 5 | $content-heading-line-height: 1.125 !default 6 | 7 | $content-blockquote-background-color: $background !default 8 | $content-blockquote-border-left: 5px solid $border !default 9 | $content-blockquote-padding: 1.25em 1.5em !default 10 | 11 | $content-pre-padding: 1.25em 1.5em !default 12 | 13 | $content-table-cell-border: 1px solid $border !default 14 | $content-table-cell-border-width: 0 0 1px !default 15 | $content-table-cell-padding: 0.5em 0.75em !default 16 | $content-table-cell-heading-color: $text-strong !default 17 | $content-table-head-cell-border-width: 0 0 2px !default 18 | $content-table-head-cell-color: $text-strong !default 19 | $content-table-foot-cell-border-width: 2px 0 0 !default 20 | $content-table-foot-cell-color: $text-strong !default 21 | 22 | .content 23 | @extend %block 24 | // Inline 25 | li + li 26 | margin-top: 0.25em 27 | // Block 28 | p, 29 | dl, 30 | ol, 31 | ul, 32 | blockquote, 33 | pre, 34 | table 35 | &:not(:last-child) 36 | margin-bottom: 1em 37 | h1, 38 | h2, 39 | h3, 40 | h4, 41 | h5, 42 | h6 43 | color: $content-heading-color 44 | font-weight: $content-heading-weight 45 | line-height: $content-heading-line-height 46 | h1 47 | font-size: 2em 48 | margin-bottom: 0.5em 49 | &:not(:first-child) 50 | margin-top: 1em 51 | h2 52 | font-size: 1.75em 53 | margin-bottom: 0.5714em 54 | &:not(:first-child) 55 | margin-top: 1.1428em 56 | h3 57 | font-size: 1.5em 58 | margin-bottom: 0.6666em 59 | &:not(:first-child) 60 | margin-top: 1.3333em 61 | h4 62 | font-size: 1.25em 63 | margin-bottom: 0.8em 64 | h5 65 | font-size: 1.125em 66 | margin-bottom: 0.8888em 67 | h6 68 | font-size: 1em 69 | margin-bottom: 1em 70 | blockquote 71 | background-color: $content-blockquote-background-color 72 | border-left: $content-blockquote-border-left 73 | padding: $content-blockquote-padding 74 | ol 75 | list-style-position: outside 76 | margin-left: 2em 77 | margin-top: 1em 78 | &:not([type]) 79 | list-style-type: decimal 80 | &.is-lower-alpha 81 | list-style-type: lower-alpha 82 | &.is-lower-roman 83 | list-style-type: lower-roman 84 | &.is-upper-alpha 85 | list-style-type: upper-alpha 86 | &.is-upper-roman 87 | list-style-type: upper-roman 88 | ul 89 | list-style: disc outside 90 | margin-left: 2em 91 | margin-top: 1em 92 | ul 93 | list-style-type: circle 94 | margin-top: 0.5em 95 | ul 96 | list-style-type: square 97 | dd 98 | margin-left: 2em 99 | figure 100 | margin-left: 2em 101 | margin-right: 2em 102 | text-align: center 103 | &:not(:first-child) 104 | margin-top: 2em 105 | &:not(:last-child) 106 | margin-bottom: 2em 107 | img 108 | display: inline-block 109 | figcaption 110 | font-style: italic 111 | pre 112 | +overflow-touch 113 | overflow-x: auto 114 | padding: $content-pre-padding 115 | white-space: pre 116 | word-wrap: normal 117 | sup, 118 | sub 119 | font-size: 75% 120 | table 121 | width: 100% 122 | td, 123 | th 124 | border: $content-table-cell-border 125 | border-width: $content-table-cell-border-width 126 | padding: $content-table-cell-padding 127 | vertical-align: top 128 | th 129 | color: $content-table-cell-heading-color 130 | &:not([align]) 131 | text-align: left 132 | thead 133 | td, 134 | th 135 | border-width: $content-table-head-cell-border-width 136 | color: $content-table-head-cell-color 137 | tfoot 138 | td, 139 | th 140 | border-width: $content-table-foot-cell-border-width 141 | color: $content-table-foot-cell-color 142 | tbody 143 | tr 144 | &:last-child 145 | td, 146 | th 147 | border-bottom-width: 0 148 | .tabs 149 | li + li 150 | margin-top: 0 151 | // Sizes 152 | &.is-small 153 | font-size: $size-small 154 | &.is-medium 155 | font-size: $size-medium 156 | &.is-large 157 | font-size: $size-large 158 | -------------------------------------------------------------------------------- /content/docs/connectors/local.md: -------------------------------------------------------------------------------- 1 | --- 2 | linkTitle: "BuiltIn (local)" 3 | title: "Authentication Through the builtin connector" 4 | description: "" 5 | date: 2024-01-05 6 | draft: false 7 | toc: true 8 | weight: 2110 9 | --- 10 | 11 | ## Overview 12 | Dex comes with a built-in local connector, acting as a "virtual" identity provider within Dex's ecosystem, securely storing login credentials in the specified [storage](/docs/storage). 13 | This local connector simplifies authentication workflows by managing and storing user credentials directly within Dex's infrastructure. 14 | 15 | 16 | ## Configuration 17 | The local connector can be utilized by adding the following flag to the configuration. 18 | ```yaml 19 | enablePasswordDB: true 20 | ``` 21 | 22 | ### Creating Users 23 | 24 | Once the local connector is enabled, users can be added in two ways: statically within the configuration file or dynamically through the [gRPC API](/docs/api). 25 | 26 | #### Static configuration (config file) 27 | ```yaml 28 | staticPasswords: 29 | - email: "admin@example.com" 30 | # bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2) 31 | hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" 32 | username: "admin" 33 | userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" 34 | ``` 35 | 36 | To specify users within the configuration file, the `staticPasswords` option can be used. It contains a list of predefined users, each defined by the following entities: 37 | 38 | * `email`: The email address of the user (used as the main identifier). 39 | * `hash`: The bcrypt hash of the user's password. 40 | * `username`: The username associated with the user. 41 | * `userID`: The unique identifier (ID) of the user. 42 | 43 | 44 | #### Dynamic configuration (API) 45 | Users can be dynamically managed via the gRPC API, offering a versatile method to handle user-related operations within the system. 46 | This functionality enables seamless additions, updates, and removals of users, providing a flexible approach to user management. 47 | For comprehensive information and detailed procedures, please refer to the specific [API documentation](/docs/api). 48 | 49 | ### Obtaining a token 50 | Let's explore a sample configuration in dex that involves a public and private client along with a static user. 51 | Both local users and password grants are enabled, allowing the exchange of a token for user credentials. 52 | 53 | ```yaml 54 | issuer: http://localhost:8080/dex 55 | storage: # .. storage configuration 56 | # Setup clients 57 | staticClients: 58 | - id: public-client 59 | public: true 60 | name: 'Public Client' 61 | redirectURIs: 62 | - 'https://example.com/oidc/callback' 63 | - id: private-client 64 | secret: app-secret 65 | name: 'Private Client' 66 | redirectURIs: 67 | - 'https://example.com/oidc/callback' 68 | # Set up an test user 69 | staticPasswords: 70 | - email: "admin@example.com" 71 | # bcrypt hash of the string "password": $(echo password | htpasswd -BinC 10 admin | cut -d: -f2) 72 | hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" 73 | username: "admin" 74 | userID: "08a8684b-db88-4b73-90a9-3cd1661f5466" 75 | 76 | # Enable local users 77 | enablePasswordDB: true 78 | # Allow password grants with local users 79 | oauth2: 80 | passwordConnector: local 81 | ``` 82 | 83 | Depending on whether you use a public or a private client you need to either include the just `clientId` or the `clientId` and `clientPassword` in the authorization header. 84 | 85 | **Public Client** 86 | ```shell 87 | curl -L -X POST 'http://localhost:8080/dex/token' \ 88 | -H 'Authorization: Basic cHVibGljLWNsaWVudDo=' \ # base64 encoded: public-client: 89 | -H 'Content-Type: application/x-www-form-urlencoded' \ 90 | --data-urlencode 'grant_type=password' \ 91 | --data-urlencode 'scope=openid profile' \ 92 | --data-urlencode 'username=admin@example.com' \ 93 | --data-urlencode 'password=password' 94 | ``` 95 | 96 | 97 | **Private Client** 98 | ```shell 99 | curl -L -X POST 'http://localhost:8080/dex/token' \ 100 | -H 'Authorization: Basic cHJpdmF0ZS1jbGllbnQ6YXBwLXNlY3JldA==' \ # base64 encoded: private-client:app-secret 101 | -H 'Content-Type: application/x-www-form-urlencoded' \ 102 | --data-urlencode 'grant_type=password' \ 103 | --data-urlencode 'scope=openid' \ 104 | --data-urlencode 'username=admin@example.com' \ 105 | --data-urlencode 'password=password' 106 | ``` 107 | -------------------------------------------------------------------------------- /content/docs/guides/kubelogin-activedirectory.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Integration kubelogin and Active Directory" 3 | linkTitle: "Integration kubelogin and Active Directory" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2140 9 | --- 10 | 11 | ## Overview 12 | 13 | kubelogin is helper tool for kubernetes and oidc integration. 14 | It makes easy to login Open ID Provider. 15 | This document describes how dex work with kubelogin and Active Directory. 16 | 17 | examples/config-ad-kubelogin.yaml is sample configuration to integrate Active Directory and kubelogin. 18 | 19 | ## Precondition 20 | 21 | 1. Active Directory 22 | You should have Active Directory or LDAP has Active Directory compatible schema such as samba ad. 23 | You may have user objects and group objects in AD. Please ensure TLS is enabled. 24 | 25 | 2. Install kubelogin 26 | Download kubelogin from https://github.com/int128/kubelogin/releases. 27 | Install it to your terminal. 28 | 29 | ## Getting started 30 | 31 | ### Generate certificate and private key 32 | 33 | Create OpenSSL conf req.conf as follow: 34 | 35 | ```bash 36 | [req] 37 | req_extensions = v3_req 38 | distinguished_name = req_distinguished_name 39 | 40 | [req_distinguished_name] 41 | 42 | [ v3_req ] 43 | basicConstraints = CA:FALSE 44 | keyUsage = nonRepudiation, digitalSignature, keyEncipherment 45 | subjectAltName = @alt_names 46 | 47 | [alt_names] 48 | DNS.1 = dex.example.com 49 | ``` 50 | 51 | Please replace dex.example.com to your favorite hostname. 52 | Generate certificate and private key by following command. 53 | 54 | ```bash 55 | $ openssl req -new -x509 -sha256 -days 3650 -newkey rsa:4096 -extensions v3_req -out openid-ca.pem -keyout openid-key.pem -config req.cnf -subj "/CN=kube-ca" -nodes 56 | $ ls openid* 57 | openid-ca.pem openid-key.pem 58 | ``` 59 | 60 | ### Modify dex config 61 | 62 | Modify following host, bindDN and bindPW in examples/config-ad-kubelogin.yaml. 63 | 64 | ```yaml 65 | connectors: 66 | - type: ldap 67 | name: OpenLDAP 68 | id: ldap 69 | config: 70 | host: ldap.example.com:636 71 | 72 | # No TLS for this setup. 73 | insecureNoSSL: false 74 | insecureSkipVerify: true 75 | 76 | # This would normally be a read-only user. 77 | bindDN: cn=Administrator,cn=users,dc=example,dc=com 78 | bindPW: admin0! 79 | ``` 80 | 81 | ### Run dex 82 | 83 | ```bash 84 | $ bin/dex serve examples/config-ad-kubelogin.yaml 85 | ``` 86 | 87 | ### Configure kubernetes with oidc 88 | 89 | Copy `openid-ca.pem` to `/etc/ssl/certs/openid-ca.pem` on master node. 90 | 91 | Use the following flags to point your API server(s) at dex. `dex.example.com` should be replaced by whatever DNS name or IP address dex is running under. 92 | 93 | ```bash 94 | --oidc-issuer-url=https://dex.example.com:32000/dex 95 | --oidc-client-id=kubernetes 96 | --oidc-ca-file=/etc/ssl/certs/openid-ca.pem 97 | --oidc-username-claim=email 98 | --oidc-groups-claim=groups 99 | ``` 100 | 101 | Then restart API server(s). 102 | 103 | 104 | See https://kubernetes.io/docs/reference/access-authn-authz/authentication/ for more detail. 105 | 106 | ### Set up kubeconfig 107 | 108 | Add a new user to the kubeconfig for dex authentication: 109 | 110 | ```bash 111 | $ kubectl config set-credentials oidc \ 112 | --exec-api-version=client.authentication.k8s.io/v1beta1 \ 113 | --exec-command=kubectl \ 114 | --exec-arg=oidc-login \ 115 | --exec-arg=get-token \ 116 | --exec-arg=--oidc-issuer-url=https://dex.example.com:32000/dex \ 117 | --exec-arg=--oidc-client-id=kubernetes \ 118 | --exec-arg=--oidc-client-secret=ZXhhbXBsZS1hcHAtc2VjcmV0 \ 119 | --exec-arg=--oidc-extra-scope=profile \ 120 | --exec-arg=--oidc-extra-scope=email \ 121 | --exec-arg=--oidc-extra-scope=groups \ 122 | --exec-arg=--certificate-authority-data=$(base64 -w 0 openid-ca.pem) 123 | ``` 124 | 125 | Please confirm `--oidc-issuer-url`, `--oidc-client-id`, `--oidc-client-secret` and `--certificate-authority-data` are same as values in config-ad-kubelogin.yaml. 126 | 127 | Run the following command: 128 | 129 | ```bash 130 | $ kubectl --user=oidc cluster-info 131 | ``` 132 | 133 | It launches the browser and navigates it to http://localhost:8000. 134 | Please log in with your AD account (eg. test@example.com) and password. 135 | After login and grant, you can access the cluster. 136 | 137 | You can switch the current context to dex authentication. 138 | 139 | ```bash 140 | $ kubectl config set-context --current --user=oidc 141 | ``` 142 | -------------------------------------------------------------------------------- /content/docs/configuration/custom-scopes-claims-clients.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Scopes and Claims" 3 | description: "Custom Scopes, Claims and Client Features" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 1040 8 | --- 9 | 10 | This document describes the set of OAuth2 and OpenID Connect features implemented by dex. 11 | 12 | ## Scopes 13 | 14 | The following is the exhaustive list of scopes supported by dex: 15 | 16 | | Name | Description | 17 | | ---- | ------------| 18 | | `openid` | Required scope for all login requests. | 19 | | `email` | ID token claims should include the end user's email and if that email was verified by an upstream provider. | 20 | | `profile` | ID token claims should include the username of the end user. | 21 | | `groups` | ID token claims should include a list of groups the end user is a member of. | 22 | | `federated:id` | ID token claims should include information from the ID provider. The token will contain the connector ID and the user ID assigned at the provider. | 23 | | `offline_access` | Token response should include a refresh token. Doesn't work in combinations with some connectors, notability the [SAML connector](/docs/connectors/saml/) ignores this scope. | 24 | | `audience:server:client_id:( client-id )` | Dynamic scope indicating that the ID token should be issued on behalf of another client. See the _"Cross-client trust and authorized party"_ section below. | 25 | 26 | ## Custom claims 27 | 28 | Beyond the [required OpenID Connect claims][core-claims], and a handful of [standard claims][standard-claims], dex implements the following non-standard claims. 29 | 30 | | Name | Description | 31 | | ---- | ------------| 32 | | `groups` | A list of strings representing the groups a user is a member of. | 33 | | `federated_claims` | The connector ID and the user ID assigned to the user at the provider. | 34 | | `email` | The email of the user. | 35 | | `email_verified` | If the upstream provider has verified the email. | 36 | | `name` | User's display name. | 37 | | `preferred_username` | Shorthand name by which the End-User wishes to be referred to. | 38 | 39 | 40 | The `federated_claims` claim has the following format: 41 | 42 | ```json 43 | "federated_claims": { 44 | "connector_id": "github", 45 | "user_id": "110272483197731336751" 46 | } 47 | ``` 48 | 49 | ## Cross-client trust and authorized party 50 | 51 | Dex has the ability to issue ID tokens to clients on behalf of other clients. In OpenID Connect terms, this means the ID token's `aud` (audience) claim being a different client ID than the client that performed the login. 52 | 53 | For example, this feature could be used to allow a web app to generate an ID token on behalf of a command line tool: 54 | 55 | ```yaml 56 | staticClients: 57 | - id: web-app 58 | redirectURIs: 59 | - 'https://web-app.example.com/callback' 60 | name: 'Web app' 61 | secret: web-app-secret 62 | # It is also possible to fetch the secret from an injected environment variable 63 | # secretEnv: YOUR_INJECTED_SECRET 64 | 65 | - id: cli-app 66 | redirectURIs: 67 | - 'https://cli-app.example.com/callback' 68 | name: 'Command line tool' 69 | secret: cli-app-secret 70 | # The command line tool lets the web app issue ID tokens on its behalf. 71 | trustedPeers: 72 | - web-app 73 | ``` 74 | 75 | Note that the command line tool must explicitly trust the web app using the `trustedPeers` field. The web app can then use the following scope to request an ID token that's issued for the command line tool. 76 | 77 | ``` 78 | audience:server:client_id:cli-app 79 | ``` 80 | 81 | The ID token claims will then include the following audience and authorized party: 82 | 83 | ```json 84 | { 85 | "aud": "cli-app", 86 | "azp": "web-app", 87 | "email": "foo@bar.com", 88 | // other claims... 89 | } 90 | ``` 91 | 92 | ## Public clients 93 | 94 | Public clients are inspired by Google's [_"Installed Applications"_][installed-apps] and are meant to impose restrictions on applications that don't intend to keep their client secret private. Clients can be declared as public using the `public` config option. 95 | 96 | ```yaml 97 | staticClients: 98 | - id: cli-app 99 | public: true 100 | name: 'CLI app' 101 | redirectURIs: 102 | - ... 103 | ``` 104 | 105 | If no `redirectURIs` are specified, public clients only support redirects that begin with "http://localhost" or a special "out-of-browser" URL "urn:ietf:wg:oauth:2.0:oob". 106 | The latter triggers dex to display the OAuth2 code in the browser, prompting the end user to manually copy it to their app. It's the client's responsibility to either create a screen or a prompt to receive the code, then perform a code exchange for a token response. 107 | 108 | When using the "out-of-browser" flow, an ID Token nonce is strongly recommended. 109 | 110 | [core-claims]: https://openid.net/specs/openid-connect-core-1_0.html#IDToken 111 | [standard-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims 112 | [installed-apps]: https://developers.google.com/api-client-library/python/auth/installed-app 113 | -------------------------------------------------------------------------------- /content/docs/connectors/saml.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication through SAML 2.0" 3 | linkTitle: "SAML 2.0" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2030 9 | --- 10 | 11 | ## WARNING 12 | 13 | The SAML connector is unmaintained, likely vulnerable to authentication bypass vulnerabilities, and is under consideration for deprecation (see [#1884](https://github.com/dexidp/dex/discussions/1884)). Please consider switching to OpenID Connect, OAuth2, or LDAP for identity providers that support these protocols. If you have domain expertise in SAML/XMLDSig and would like to volunteer to maintain the connector please comment on the discussion. 14 | 15 | ## Overview 16 | 17 | The SAML provider allows authentication through the SAML 2.0 HTTP POST binding. The connector maps attribute values in the SAML assertion to user info, such as username, email, and groups. 18 | 19 | The connector uses the value of the `NameID` element as the user's unique identifier which dex assumes is both unique and never changes. Use the `nameIDPolicyFormat` to ensure this is set to a value which satisfies these requirements. 20 | 21 | Unlike some clients which will process unprompted AuthnResponses, dex must send the initial AuthnRequest and validates the response's InResponseTo value. 22 | 23 | ## Caveats 24 | 25 | __The connector doesn't support refresh tokens__ since the SAML 2.0 protocol doesn't provide a way to requery a provider without interaction. If the "offline_access" scope is requested, it will be ignored. 26 | 27 | The connector doesn't support signed AuthnRequests or encrypted attributes. 28 | 29 | ## Group Filtering 30 | 31 | The SAML Connector supports providing a whitelist of SAML Groups to filter access based on, and when the `groupsattr` is set with a scope including groups, Dex will check for membership based on configured groups in the `allowedGroups` config setting for the SAML connector. 32 | 33 | If `filterGroups` is set to true, any groups _not_ part of `allowedGroups` will be excluded. 34 | 35 | ## Configuration 36 | 37 | ```yaml 38 | connectors: 39 | - type: saml 40 | # Required field for connector id. 41 | id: saml 42 | # Required field for connector name. 43 | name: SAML 44 | config: 45 | # SSO URL used for POST value. 46 | ssoURL: https://saml.example.com/sso 47 | 48 | # CA to use when validating the signature of the SAML response. 49 | ca: /path/to/ca.pem 50 | 51 | # Dex's callback URL. 52 | # 53 | # If the response assertion status value contains a Destination element, it 54 | # must match this value exactly. 55 | # 56 | # This is also used as the expected audience for AudienceRestriction elements 57 | # if entityIssuer isn't specified. 58 | redirectURI: https://dex.example.com/callback 59 | 60 | # Name of attributes in the returned assertions to map to ID token claims. 61 | usernameAttr: name 62 | emailAttr: email 63 | groupsAttr: groups # optional 64 | 65 | # List of groups to filter access based on membership 66 | # allowedGroups 67 | # - Admins 68 | 69 | # CA's can also be provided inline as a base64'd blob. 70 | # 71 | # caData: ( RAW base64'd PEM encoded CA ) 72 | 73 | # To skip signature validation, uncomment the following field. This should 74 | # only be used during testing and may be removed in the future. 75 | # 76 | # insecureSkipSignatureValidation: true 77 | 78 | # Optional: Manually specify dex's Issuer value. 79 | # 80 | # When provided dex will include this as the Issuer value during AuthnRequest. 81 | # It will also override the redirectURI as the required audience when evaluating 82 | # AudienceRestriction elements in the response. 83 | entityIssuer: https://dex.example.com/callback 84 | 85 | # Optional: Issuer value expected in the SAML response. 86 | ssoIssuer: https://saml.example.com/sso 87 | 88 | # Optional: Delimiter for splitting groups returned as a single string. 89 | # 90 | # By default, multiple groups are assumed to be represented as multiple 91 | # attributes with the same name. 92 | # 93 | # If "groupsDelim" is provided groups are assumed to be represented as a 94 | # single attribute and the delimiter is used to split the attribute's value 95 | # into multiple groups. 96 | groupsDelim: ", " 97 | 98 | # Optional: Requested format of the NameID. 99 | # 100 | # The NameID value is is mapped to the user ID of the user. This can be an 101 | # abbreviated form of the full URI with just the last component. For example, 102 | # if this value is set to "emailAddress" the format will resolve to: 103 | # 104 | # urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress 105 | # 106 | # If no value is specified, this value defaults to: 107 | # 108 | # urn:oasis:names:tc:SAML:2.0:nameid-format:persistent 109 | # 110 | nameIDPolicyFormat: persistent 111 | ``` 112 | 113 | A minimal working configuration might look like: 114 | 115 | ```yaml 116 | connectors: 117 | - type: saml 118 | id: okta 119 | name: Okta 120 | config: 121 | ssoURL: https://dev-111102.oktapreview.com/app/foo/exk91cb99lKkKSYoy0h7/sso/saml 122 | ca: /etc/dex/saml-ca.pem 123 | redirectURI: http://127.0.0.1:5556/dex/callback 124 | usernameAttr: name 125 | emailAttr: email 126 | groupsAttr: groups 127 | ``` 128 | -------------------------------------------------------------------------------- /content/docs/configuration/tokens.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Tokens" 3 | linkTitle: "Tokens" 4 | description: "Types of tokens and expiration settings" 5 | date: 2020-10-21 6 | draft: false 7 | toc: true 8 | weight: 1013 9 | --- 10 | 11 | ## Overview 12 | 13 | ID Tokens are an OAuth2 extension introduced by OpenID Connect and Dex's primary feature. ID Tokens are [JSON Web Tokens][jwt-io] (JWTs) signed by Dex and returned as part of the OAuth2 response that attest to the end user's identity. An example JWT might look like: 14 | 15 | ```bash 16 | eyJhbGciOiJSUzI1NiIsImtpZCI6IjlkNDQ3NDFmNzczYjkzOGNmNjVkZDMyNjY4NWI4NjE4MGMzMjRkOTkifQ.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjU1NTYvZGV4Iiwic3ViIjoiQ2djeU16UXlOelE1RWdabmFYUm9kV0kiLCJhdWQiOiJleGFtcGxlLWFwcCIsImV4cCI6MTQ5Mjg4MjA0MiwiaWF0IjoxNDkyNzk1NjQyLCJhdF9oYXNoIjoiYmk5NmdPWFpTaHZsV1l0YWw5RXFpdyIsImVtYWlsIjoiZXJpYy5jaGlhbmdAY29yZW9zLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJncm91cHMiOlsiYWRtaW5zIiwiZGV2ZWxvcGVycyJdLCJuYW1lIjoiRXJpYyBDaGlhbmcifQ.OhROPq_0eP-zsQRjg87KZ4wGkjiQGnTi5QuG877AdJDb3R2ZCOk2Vkf5SdP8cPyb3VMqL32G4hLDayniiv8f1_ZXAde0sKrayfQ10XAXFgZl_P1yilkLdknxn6nbhDRVllpWcB12ki9vmAxklAr0B1C4kr5nI3-BZLrFcUR5sQbxwJj4oW1OuG6jJCNGHXGNTBTNEaM28eD-9nhfBeuBTzzO7BKwPsojjj4C9ogU4JQhGvm_l4yfVi0boSx8c0FX3JsiB0yLa1ZdJVWVl9m90XmbWRSD85pNDQHcWZP9hR6CMgbvGkZsgjG32qeRwUL_eNkNowSBNWLrGNPoON1gMg 17 | ``` 18 | 19 | ID Tokens contains standard claims assert which client app logged the user in, when the token expires, and the identity of the user. 20 | 21 | ```json 22 | { 23 | "iss": "http://127.0.0.1:5556/dex", 24 | "sub": "CgcyMzQyNzQ5EgZnaXRodWI", 25 | "aud": "example-app", 26 | "exp": 1492882042, 27 | "iat": 1492795642, 28 | "at_hash": "bi96gOXZShvlWYtal9Eqiw", 29 | "email": "jane.doe@coreos.com", 30 | "email_verified": true, 31 | "groups": [ 32 | "admins", 33 | "developers" 34 | ], 35 | "name": "Jane Doe" 36 | } 37 | ``` 38 | 39 | Because these tokens are signed by Dex and [contain standard-based claims][standard-claims] other services can consume them as service-to-service credentials. Systems that can already consume OpenID Connect ID Tokens issued by Dex include: 40 | 41 | * [Kubernetes][kubernetes] 42 | * [AWS STS][aws-sts] 43 | 44 | For details on how to request or validate an ID Token, see [“_Writing apps that use Dex_.”][using-dex] 45 | 46 | ## Refresh tokens 47 | Refresh tokens are credentials used to obtain access tokens. Refresh tokens are issued to the client by the authorization server and are used to obtain 48 | a new id token when the current id token becomes invalid or expires. Issuing a refresh token is optional and is provided by passing `offline_access` scope to Dex server. 49 | 50 | __NOTE__: Some connectors do not support `offline_access` scope. You can find out which connectors support refresh tokens by looking into the [_connectors list_][connectors]. 51 | 52 | Example of a server response with refresh token: 53 | ```json 54 | { 55 | "access_token": "eyJhbGciOiJSUzI1N...", 56 | "token_type": "Bearer", 57 | "refresh_token": "lxzzsvasxho5exvwkfa5zhefl", 58 | "expires_in": 3600, 59 | "id_token": "eyJhbGciO..." 60 | } 61 | ``` 62 | 63 | __NOTE__: For every refresh of an id token, Dex issues a new refresh token. This security measure is called _refresh token rotation_ 64 | and prevents someone stealing it. The idea is described in detail in the corresponding [RFC][rfc6819-5.2.2.3]. 65 | 66 | ## Expiration and rotation settings 67 | 68 | Dex has a section in the config file where you can specify expiration and rotation settings for id tokens and refresh tokens. 69 | __NOTE__: All duration options should be set in the format: number + time unit (s, m, h), e.g., `10m`. 70 | 71 | * `expiry` - section for various expiration settings, including token settings: 72 | * `idTokens` - the lifetime of if tokens. It is preferable to use short-lived id tokens, e.g., 10 minutes. 73 | * `authRequests` - the time frame in which users can exchange a code for an access or id token. 74 | * `deviceRequests` - the time frame in which users can authorize a device to receive an access or id token. 75 | * `signingKeys` - the period of time after which the signing keys are rotated. It is recommended to rotate keys regularly. If the `idTokens` lifetime exceeds, public parts of signing keys will be kept for validation for the extra time. 76 | * `refreshTokens` - section for various refresh token settings: 77 | * `validIfNotUsedFor` - invalidate a refresh token if it is not used for a specified amount of time. 78 | * `absoluteLifetime` - a stricter variant of the previous option, absolute lifetime of a refresh token. It forces users to reauthenticate and obtain a new refresh token. 79 | * `disableRotation` - completely disables every-request rotation. The user will also have to specify one of the previous refresh token options to keep refresh tokens secure when toggling this. 80 | * `reuseInterval` - allows getting the same refresh token from refresh endpoint within a specified interval, but only if the user's request contains the previous refresh token. 81 | 82 | __NOTE__: `disableRotation` and `reuseInterval` options help effectively deal with network lags, concurrent requests, and so on in tradeoff for security. Use them with caution. 83 | 84 | [aws-sts]: https://docs.aws.amazon.com/STS/latest/APIReference/Welcome.html 85 | [connectors]: /docs/connectors 86 | [jwt-io]: https://jwt.io/ 87 | [kubernetes]: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens 88 | [rfc6819-5.2.2.3]: https://tools.ietf.org/html/rfc6819#section-5.2.2.3 89 | [standard-claims]: https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims 90 | [using-dex]: /docs/guides/using-dex 91 | -------------------------------------------------------------------------------- /assets/sass/style.sass: -------------------------------------------------------------------------------- 1 | @charset "utf-8" 2 | {{ $extraColors := site.Params.colors.extra }} 3 | {{ $fontAwesomeVersion := site.Params.font_awesome_version }} 4 | {{ $fonts := site.Params.fonts }} 5 | {{ if $fonts }} 6 | {{ $fontSlice := (slice) }} 7 | {{ range $fonts }} 8 | {{ $fontSlice = $fontSlice | append (printf "%s:%s" (replace .name " " "+") (delimit .sizes ",")) }} 9 | {{ end }} 10 | {{ $fontsUrl := printf "https://fonts.googleapis.com/css?family=%s" (delimit $fontSlice "|") }} 11 | @import url("{{ $fontsUrl }}") 12 | {{ end }} 13 | 14 | {{ with $fontAwesomeVersion }} 15 | {{ $fontAwesomeUrl := printf "https://use.fontawesome.com/releases/v%s/css/all.css" . }} 16 | @import url("{{ $fontAwesomeUrl }}") 17 | {{ end }} 18 | 19 | // Site-specific variables here 20 | 21 | // colors 22 | // 1 = lightest, 10 = darkest. These are an optical gradient - no opportunity for Sass color math 23 | $cncf-blue: #426cab 24 | $cncf-green: #76c5d5 25 | 26 | $cncf-blue-1: #F0F5F7 27 | $cncf-blue-2: #E4F2F4 28 | $cncf-blue-3: #CDEEF2 29 | $cncf-blue-4: #B2E0EA 30 | $cncf-blue-5: $cncf-green 31 | $cncf-blue-6: #5BAECE 32 | $cncf-blue-7: #4583BB 33 | $cncf-blue-8: $cncf-blue 34 | $cncf-blue-9: #1E4D94 35 | $cncf-blue-10: #072C63 36 | 37 | $cncf-violet-1: #FFF5FA 38 | $cncf-violet-2: #FCE2ED 39 | $cncf-violet-3: #FAC6DD 40 | $cncf-violet-4: #F492BE 41 | $cncf-violet-5: #E70266 42 | $cncf-violet-6: #B30163 43 | $cncf-violet-7: #840363 44 | $cncf-violet-8: #521A60 45 | $cncf-violet-9: #32225E 46 | $cncf-violet-10: #0F1433 47 | 48 | // Extra colors specified in config 49 | {{ with $extraColors }} 50 | {{ range . }} 51 | ${{ .name }}: '{{ .hex }}' 52 | {{ end }} 53 | {{ end }} 54 | 55 | // Initial Bulma imports 56 | @import "bulma/sass/utilities/initial-variables" 57 | @import "bulma/sass/utilities/functions" 58 | 59 | // Bulma-specific overrides 60 | $primary: $cncf-blue 61 | $link: $cncf-blue-8 62 | $info: $cncf-blue-6 63 | 64 | .card 65 | height: 100% 66 | 67 | // Type scale – major third (multiply by 1.25) 68 | $size-1: 3.052rem 69 | $size-2: 2.441rem 70 | $size-3: 1.953rem 71 | $size-4: 1.563rem 72 | $size-5: 1.25rem 73 | $size-6: 1rem 74 | $size-7: 0.833rem 75 | 76 | $weight-light: 200 77 | $weight-normal: $weight-medium 78 | $weight-medium: 400 79 | $weight-bold: 600 80 | 81 | // Font overrides 82 | {{ if $fonts }} 83 | // Sans-serif font 84 | {{ with (index (where $fonts ".type" "sans_serif") 0).name }} 85 | $family-sans-serif: "{{ . }}", BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif 86 | {{ end }} 87 | 88 | // Monospace font 89 | {{ with (index (where $fonts ".type" "monospace") 0).name }} 90 | $family-monospace: "{{ . }}", monospace 91 | {{ end }} 92 | {{ end }} 93 | 94 | $font-heading: {{ $.Site.Params.heading_font | default "'Fira Sans', sans-serif" }} 95 | 96 | @for $i from 1 through 6 97 | h#{$i} 98 | font-family: $font-heading 99 | 100 | .container 101 | h1 102 | font-size: $size-1 103 | font-weight: 200 104 | h2 105 | font-size: $size-2 106 | font-weight: 100 107 | h3 108 | font-size: $size-3 109 | font-weight: 300 110 | h4 111 | font-size: $size-4 112 | font-weight: 500 113 | h5 114 | font-size: $size-5 115 | font-weight: 600 116 | h6 117 | font-size: $size-6 118 | font-weight: 700 119 | 120 | // Final Bulma imports 121 | @import "bulma/sass/utilities/derived-variables" 122 | 123 | // Bulma variable overrides that require derived variables like $dark 124 | $footer-background-color: $dark 125 | $menu-list-border-left: 0px 126 | 127 | {{ with $extraColors }} 128 | {{ range . }} 129 | $colors: mergeColorMaps(("{{ .name }}": ({{ .hex }}, $white)), $colors) 130 | {{ end }} 131 | {{ end }} 132 | 133 | // Bulma core 134 | @import "bulma/sass/utilities/_all" 135 | @import "bulma/sass/base/_all" 136 | @import "bulma/sass/elements/container" 137 | @import "bulma/sass/grid/columns" 138 | @import "bulma/sass/grid/tiles" 139 | @import "bulma/sass/layout/hero" 140 | @import "bulma/sass/layout/section" 141 | @import "bulma/sass/layout/footer" 142 | 143 | // Elements 144 | 145 | // @import "bulma/sass/elements/box" 146 | @import "bulma/sass/elements/button" 147 | // @import "bulma/sass/elements/content" 148 | @import "bulma/sass/elements/icon" 149 | // @import "bulma/sass/elements/image" 150 | // @import "bulma/sass/elements/notification" 151 | // @import "bulma/sass/elements/progress" 152 | // @import "bulma/sass/elements/table" 153 | // @import "bulma/sass/elements/tag" 154 | @import "bulma/sass/elements/title" 155 | // @import "bulma/sass/elements/other" 156 | 157 | // Forms 158 | // @import "bulma/sass/form/shared" 159 | // @import "bulma/sass/form/input-textarea" 160 | // @import "bulma/sass/form/checkbox-radio" 161 | // @import "bulma/sass/form/select" 162 | // @import "bulma/sass/form/file" 163 | // @import "bulma/sass/form/tools" 164 | 165 | // Components 166 | // @import "bulma/sass/components/breadcrumb" 167 | // @import "bulma/sass/components/card" 168 | // @import "bulma/sass/components/dropdown" 169 | // @import "bulma/sass/components/level" 170 | // @import "bulma/sass/components/list" 171 | // @import "bulma/sass/components/media" 172 | @import "bulma/sass/components/menu" 173 | // @import "bulma/sass/components/message" 174 | // @import "bulma/sass/components/modal" 175 | @import "bulma/sass/components/navbar" 176 | // @import "bulma/sass/components/pagination" 177 | // @import "bulma/sass/components/panel" 178 | // @import "bulma/sass/components/tabs" 179 | 180 | // Grid 181 | 182 | // Custom Sass imports 183 | @import "content" 184 | @import "helpers" 185 | @import "docs" 186 | -------------------------------------------------------------------------------- /content/docs/connectors/authproxy.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authenticating Proxy" 3 | linkTitle: "AuthProxy" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2090 9 | --- 10 | 11 | NOTE: This connector is experimental and may change in the future. 12 | 13 | ## Overview 14 | 15 | The `authproxy` connector returns identities based on authentication which your 16 | front-end web server performs. Dex consumes the `X-Remote-User` header set by 17 | the proxy, which is then used as the user's email address. 18 | 19 | It also consumes the `X-Remote-Group` header to use as the user's group. 20 | 21 | Header's names can be configured via the `userHeader` and `groupHeader` config. 22 | 23 | Additional static groups can also be defined in the connector's configuration. 24 | 25 | __The proxy MUST remove any `X-Remote-*` headers set by the client, for any URL 26 | path, before the request is forwarded to dex.__ 27 | 28 | The connector does not support refresh tokens. 29 | 30 | ## Configuration 31 | 32 | The `authproxy` connector is used by proxies to implement login strategies not 33 | supported by dex. For example, a proxy could handle a different OAuth2 strategy 34 | such as Slack: 35 | 36 | ```yaml 37 | connectors: 38 | # Slack login implemented by an authenticating proxy, not by dex. 39 | - type: authproxy 40 | id: slack 41 | name: Slack 42 | ``` 43 | 44 | The proxy only needs to authenticate the user when they attempt to visit the 45 | callback URL path: 46 | 47 | ``` 48 | ( dex issuer URL )/callback/( connector id )?( url query ) 49 | ``` 50 | 51 | For example, if dex is running at `https://auth.example.com/dex` and the connector 52 | ID is `slack`, the callback URL would look like: 53 | 54 | ``` 55 | https://auth.example.com/dex/callback/slack?state=xdg3z6quhrhwaueo5iysvliqf 56 | ``` 57 | 58 | The proxy should login the user then return them to the exact URL (including the 59 | query), setting `X-Remote-User` to the user's email before proxying the request 60 | to dex. 61 | 62 | ## Configuration example - Apache 2 63 | 64 | The following is an example config file that can be used by the external 65 | connector to authenticate a user. 66 | 67 | ```yaml 68 | connectors: 69 | - type: authproxy 70 | id: myBasicAuth 71 | name: HTTP Basic Auth 72 | config: 73 | userHeader: X-Forwarded-User # default is X-Remote-User 74 | groupHeader: X-Forwarded-Group # default is X-Remote-Group 75 | staticGroups: 76 | - default 77 | ``` 78 | 79 | The authproxy connector assumes that you configured your front-end web server 80 | such that it performs authentication for the `/dex/callback/myBasicAuth` 81 | location and provides the result in the HTTP headers. 82 | 83 | In this example, the configured headers are `X-Forwarded-User` for the user's mail 84 | and `X-Forwarded-Group` for the user's group. 85 | Dex authproxy connector will return a list of groups containing both 86 | configured `staticGroups` and return the group header. 87 | 88 | The following configuration will work for Apache 2.4.10+: 89 | 90 | ```bash 91 | 92 | ProxyPass "http://localhost:5556/dex/" 93 | ProxyPassReverse "http://localhost:5556/dex/" 94 | 95 | # Strip the X-Remote-User header from all requests except for the ones 96 | # where we override it. 97 | RequestHeader unset X-Remote-User 98 | 99 | 100 | 101 | AuthType Basic 102 | AuthName "db.debian.org webPassword" 103 | AuthBasicProvider file 104 | AuthUserFile "/etc/apache2/debian-web-pw.htpasswd" 105 | Require valid-user 106 | 107 | # Defense in depth: clear the Authorization header so that 108 | # Debian Web Passwords never even reach dex. 109 | RequestHeader unset Authorization 110 | 111 | # Requires Apache 2.4.10+ 112 | RequestHeader set X-Remote-User expr=%{REMOTE_USER}@debian.org 113 | 114 | ProxyPass "http://localhost:5556/dex/callback/myBasicAuth" 115 | ProxyPassReverse "http://localhost:5556/dex/callback/myBasicAuth" 116 | 117 | ``` 118 | 119 | ## Full Apache2 setup 120 | 121 | After installing your Linux distribution’s Apache2 package, place the following 122 | virtual host configuration in e.g. `/etc/apache2/sites-available/sso.conf`: 123 | 124 | ```bash 125 | 126 | ServerName sso.example.net 127 | 128 | ServerAdmin webmaster@localhost 129 | DocumentRoot /var/www/html 130 | 131 | ErrorLog ${APACHE_LOG_DIR}/error.log 132 | CustomLog ${APACHE_LOG_DIR}/access.log combined 133 | 134 | 135 | ProxyPass "http://localhost:5556/dex/" 136 | ProxyPassReverse "http://localhost:5556/dex/" 137 | 138 | # Strip the X-Remote-User header from all requests except for the ones 139 | # where we override it. 140 | RequestHeader unset X-Remote-User 141 | 142 | 143 | 144 | AuthType Basic 145 | AuthName "db.debian.org webPassword" 146 | AuthBasicProvider file 147 | AuthUserFile "/etc/apache2/debian-web-pw.htpasswd" 148 | Require valid-user 149 | 150 | # Defense in depth: clear the Authorization header so that 151 | # Debian Web Passwords never even reach dex. 152 | RequestHeader unset Authorization 153 | 154 | # Requires Apache 2.4.10+ 155 | RequestHeader set X-Remote-User expr=%{REMOTE_USER}@debian.org 156 | 157 | ProxyPass "http://localhost:5556/dex/callback/myBasicAuth" 158 | ProxyPassReverse "http://localhost:5556/dex/callback/myBasicAuth" 159 | 160 | 161 | ``` 162 | 163 | Then, enable it using `a2ensite sso.conf`, followed by a restart of Apache2. 164 | -------------------------------------------------------------------------------- /content/docs/configuration/api.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The Dex API" 3 | linkTitle: "gRPC API" 4 | description: "Configure Dex dynamically with the gRPC API" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 1060 9 | --- 10 | 11 | Dex provides a [gRPC](http://www.grpc.io/) service for programmatic modification of dex's state. 12 | The API is intended to expose hooks for management applications and is not expected to be used by most installations. 13 | 14 | This document is an overview of how to interact with the API. 15 | 16 | 17 | ## Configuration 18 | 19 | Admins that wish to expose the gRPC service must add the following entry to the dex config file. This option is off by default. 20 | 21 | ```yaml 22 | grpc: 23 | # Cannot be the same address as an HTTP(S) service. 24 | addr: 127.0.0.1:5557 25 | 26 | # Server certs. If TLS credentials aren't provided dex will run in plaintext (HTTP) mode. 27 | tlsCert: /etc/dex/grpc.crt 28 | tlsKey: /etc/dex/grpc.key 29 | 30 | # Client auth CA. 31 | tlsClientCA: /etc/dex/client.crt 32 | 33 | # enable reflection 34 | reflection: true 35 | ``` 36 | 37 | 38 | ## Clients 39 | 40 | gRPC is a suite of tools for generating client and server bindings from a common declarative language. 41 | The canonical schema for Dex's API can be found in the source tree at [`api/v2/api.proto`](https://github.com/dexidp/dex/blob/master/api/v2/api.proto). 42 | Go bindings are generated and maintained in the same directory for both public and internal use. 43 | 44 | 45 | ### Go 46 | 47 | A Go project can import the API module directly, without having to import the entire project: 48 | 49 | ```bash 50 | go get github.com/dexidp/dex/api/v2 51 | ``` 52 | 53 | The client then can be used as follows: 54 | 55 | ```go 56 | package main 57 | 58 | import ( 59 | "context" 60 | "fmt" 61 | "log" 62 | 63 | "github.com/dexidp/dex/api/v2" 64 | "google.golang.org/grpc" 65 | "google.golang.org/grpc/credentials" 66 | ) 67 | 68 | func newDexClient(hostAndPort, caPath string) (api.DexClient, error) { 69 | creds, err := credentials.NewClientTLSFromFile(caPath, "") 70 | if err != nil { 71 | return nil, fmt.Errorf("load dex cert: %v", err) 72 | } 73 | 74 | conn, err := grpc.Dial(hostAndPort, grpc.WithTransportCredentials(creds)) 75 | if err != nil { 76 | return nil, fmt.Errorf("dial: %v", err) 77 | } 78 | return api.NewDexClient(conn), nil 79 | } 80 | 81 | func main() { 82 | client, err := newDexClient("127.0.0.1:5557", "/etc/dex/grpc.crt") 83 | if err != nil { 84 | log.Fatalf("failed creating dex client: %v ", err) 85 | } 86 | 87 | req := &api.CreateClientReq{ 88 | Client: &api.Client{ 89 | Id: "example-app", 90 | Name: "Example App", 91 | Secret: "ZXhhbXBsZS1hcHAtc2VjcmV0", 92 | RedirectUris: []string{"http://127.0.0.1:5555/callback"}, 93 | }, 94 | } 95 | 96 | if _, err := client.CreateClient(context.TODO(), req); err != nil { 97 | log.Fatalf("failed creating oauth2 client: %v", err) 98 | } 99 | } 100 | ``` 101 | 102 | A clear working example of the Dex gRPC client for Go can be found [here](https://github.com/dexidp/dex/tree/master/examples/grpc-client/README.md). 103 | 104 | 105 | ### Other languages 106 | 107 | To generate a client for your own project install [`protoc`](https://github.com/google/protobuf/releases), 108 | install a protobuf generator for your project's language, and download the `api.proto` file. 109 | 110 | Here is an example: 111 | 112 | ```bash 113 | # Download api.proto for a given version. 114 | $ DEX_VERSION=v2.24.0 115 | $ wget https://raw.githubusercontent.com/dexidp/dex/${DEX_VERSION}/api/v2/api.proto 116 | 117 | # Generate the client bindings. 118 | $ protoc [YOUR LANG PARAMS] api.proto 119 | ``` 120 | 121 | Client programs can then be written using the generated code. 122 | 123 | 124 | ## Authentication and access control 125 | 126 | The Dex API does not provide any authentication or authorization beyond TLS client auth. 127 | 128 | Projects that wish to add access controls on top of the existing API should build apps which perform such checks. 129 | For example to provide a "Change password" screen, a client app could use Dex's OpenID Connect flow to authenticate an end user, 130 | then call Dex's API to update that user's password. 131 | 132 | 133 | ## dexctl? 134 | 135 | Dex does not ship with a command line tool for interacting with the API. 136 | Command line tools are useful but hard to version, easy to design poorly, 137 | and expose another interface which can never be changed in the name of compatibility. 138 | 139 | While the Dex team would be open to re-implementing `dexctl` for v2 a majority of the work is writing a design document, 140 | not the actual programming effort. 141 | 142 | 143 | ## Why not REST or gRPC Gateway? 144 | 145 | Between v1 and v2, Dex switched from REST to gRPC. This largely stemmed from problems generating documentation, 146 | client bindings, and server frameworks that adequately expressed REST semantics. 147 | While [Google APIs](https://github.com/google/apis-client-generator), [Open API/Swagger](https://openapis.org/), 148 | and [gRPC Gateway](https://github.com/grpc-ecosystem/grpc-gateway) were evaluated, 149 | they often became clunky when trying to use specific HTTP error codes or complex request bodies. 150 | As a result, v2's API is entirely gRPC. 151 | 152 | Many arguments _against_ gRPC cite short term convenience rather than production use cases. 153 | Though this is a recognized shortcoming, Dex already implements many features for developer convenience. 154 | For instance, users who wish to manually edit clients during testing can use the `staticClients` config field instead of the API. 155 | -------------------------------------------------------------------------------- /content/docs/openid-connect.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "An Overview of OpenID Connect" 3 | linkTitle: "Intro to OpenID Connect" 4 | description: "Intro to OpenID Connect (basics)" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | type: "docs" 9 | weight: 1020 10 | --- 11 | 12 | This document attempts to provide a general overview of the [OpenID Connect protocol](https://openid.net/connect/), a flavor of OAuth2 that dex implements. While this document isn't complete, we hope it provides enough information to get users up and running. 13 | 14 | For an overview of custom claims, scopes, and client features implemented by dex, see [this document](/docs/configuration/custom-scopes-claims-clients). 15 | 16 | ## OAuth2 17 | 18 | OAuth2 should be familiar to anyone who's used something similar to a "Login 19 | with Google" button. In these cases an application has chosen to let an 20 | outside provider, in this case Google, attest to your identity instead of 21 | having you set a username and password with the app itself. 22 | 23 | The general flow for server side apps is: 24 | 25 | 1. A new user visits an application. 26 | 1. The application redirects the user to Google. 27 | 1. The user logs into Google, then is asked if it's okay to let the 28 | application view the user's profile, post on their behalf, etc. 29 | 1. If the user clicks okay, Google redirects the user back to the application 30 | with a code. 31 | 1. The application redeems that code with provider for a token that can be used 32 | to access the authorized actions, such as viewing a users profile or posting on 33 | their wall. 34 | 35 | In these cases, dex is acting as Google (called the "provider" in OpenID 36 | Connect) while clients apps redirect to it for the end user's identity. 37 | 38 | ## ID Tokens 39 | 40 | Unfortunately the access token applications get from OAuth2 providers is 41 | completely opaque to the client and unique to the provider. The token you 42 | receive from Google will be completely different from the one you'd get from 43 | Twitter or GitHub. 44 | 45 | OpenID Connect's primary extension of OAuth2 is an additional token returned in 46 | the token response called the ID Token. This token is a [JSON Web Token]( 47 | https://tools.ietf.org/html/rfc7519) signed by the OpenID Connect server, with 48 | well known fields for user ID, name, email, etc. A typical token response from 49 | an OpenID Connect looks like (with less whitespace): 50 | 51 | ```json 52 | HTTP/1.1 200 OK 53 | Content-Type: application/json 54 | Cache-Control: no-store 55 | Pragma: no-cache 56 | 57 | { 58 | "access_token": "SlAV32hkKG", 59 | "token_type": "Bearer", 60 | "refresh_token": "8xLOxBtZp8", 61 | "expires_in": 3600, 62 | "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg" 63 | } 64 | ``` 65 | 66 | That ID Token is a JWT with three base64'd fields separated by dots. The first 67 | is a header, the second is a payload, and the third is a signature of the first 68 | two fields. When parsed we can see the payload of this value is. 69 | 70 | ```json 71 | { 72 | "iss": "http://server.example.com", 73 | "sub": "248289761001", 74 | "aud": "s6BhdRkqt3", 75 | "nonce": "n-0S6_WzA2Mj", 76 | "exp": 1311281970, 77 | "iat": 1311280970 78 | } 79 | ``` 80 | 81 | This has a few interesting fields such as 82 | 83 | * The server that issued this token (`iss`). 84 | * The token's subject (`sub`). In this case a unique ID of the end user. 85 | * The token's audience (`aud`). The ID of the OAuth2 client this was issued for. 86 | 87 | A real world token would have additional claims like the user's name, email, groups, etc. 88 | 89 | ```json 90 | { 91 | "iss": "https://dex.example.com/", 92 | "sub": "R29vZCBqb2IhIEdpdmUgdXMgYSBzdGFyIG9uIGdpdGh1Yg", 93 | "aud": [ 94 | "kubernetes", 95 | "kubeconfig-generator" 96 | ], 97 | "exp": 1712945837, 98 | "iat": 1712945237, 99 | "azp": "kubeconfig-generator", 100 | "at_hash": "OamCo8c60Zdj3dVho3Km5oxA", 101 | "c_hash": "HT04XtwtlUhfHvm7zf19qsGw", 102 | "email": "maksim.nabokikh@palark.com", 103 | "email_verified": true, 104 | "groups": [ 105 | "administrators", 106 | "developers" 107 | ], 108 | "name": "Maksim Nabokikh", 109 | "preferred_username": "maksim.nabokikh" 110 | } 111 | ``` 112 | 113 | ## Discovery 114 | 115 | OpenID Connect servers have a discovery mechanism for OAuth2 endpoints, scopes 116 | supported, and indications of various other OpenID Connect features. 117 | 118 | ```bash 119 | $ curl http://127.0.0.1:5556/dex/.well-known/openid-configuration 120 | { 121 | "issuer": "http://127.0.0.1:5556", 122 | "authorization_endpoint": "http://127.0.0.1:5556/auth", 123 | "token_endpoint": "http://127.0.0.1:5556/token", 124 | "jwks_uri": "http://127.0.0.1:5556/keys", 125 | "response_types_supported": [ 126 | "code" 127 | ], 128 | "subject_types_supported": [ 129 | "public" 130 | ], 131 | "id_token_signing_alg_values_supported": [ 132 | "RS256" 133 | ], 134 | "scopes_supported": [ 135 | "openid", 136 | "email", 137 | "profile" 138 | ] 139 | } 140 | ``` 141 | 142 | Importantly, we've discovered the authorization endpoint, token endpoint, and 143 | the location of the server's public keys. OAuth2 clients should be able to use 144 | the token and auth endpoints immediately, while a JOSE library can be used to 145 | parse the keys. The keys endpoint returns a [JSON Web Key]( 146 | https://tools.ietf.org/html/rfc7517) Set of public keys that will look 147 | something like this: 148 | 149 | ```bash 150 | $ curl http://127.0.0.1:5556/dex/keys 151 | { 152 | "keys": [ 153 | { 154 | "use": "sig", 155 | "kty": "RSA", 156 | "kid": "5d19a0fde5547960f4edaa1e1e8293e5534169ba", 157 | "alg": "RS256", 158 | "n": "5TAXCxkAQqHEqO0InP81z5F59PUzCe5ZNaDsD1SXzFe54BtXKn_V2a3K-BUNVliqMKhC2LByWLuI-A5ZlA5kXkbRFT05G0rusiM0rbkN2uvRmRCia4QlywE02xJKzeZV3KH6PldYqV_Jd06q1NV3WNqtcHN6MhnwRBfvkEIm7qWdPZ_mVK7vayfEnOCFRa7EZqr-U_X84T0-50wWkHTa0AfnyVvSMK1eKL-4yc26OWkmjh5ALfQFtnsz30Y2TOJdXtEfn35Y_882dNBDYBxtJV4PaSjXCxhiaIuBHp5uRS1INyMXCx2ve22ASNx_ERorv6BlXQoMDqaML2bSiN9N8Q", 159 | "e": "AQAB" 160 | } 161 | ] 162 | } 163 | ``` 164 | -------------------------------------------------------------------------------- /content/docs/development/integration-tests.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Running Integration Tests" 3 | description: "" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 3100 8 | --- 9 | 10 | ## Postgres 11 | 12 | Running database tests locally requires: 13 | 14 | * Docker 15 | 16 | To run the database integration tests: 17 | 18 | - start a postgres container: 19 | 20 | ```bash 21 | docker run --name dex-postgres -e POSTGRES_USER=postgres -e POSTGRES_DB=dex -p 5432:5432 -d postgres:11 22 | ``` 23 | 24 | - export the required environment variables: 25 | 26 | ```bash 27 | export DEX_POSTGRES_DATABASE=dex DEX_POSTGRES_USER=postgres DEX_POSTGRES_PASSWORD=postgres DEX_POSTGRES_HOST=127.0.0.1:5432 28 | ``` 29 | 30 | - run the storage/sql tests: 31 | 32 | ```bash 33 | $ # sqlite3 takes forever to compile, be sure to install test dependencies 34 | $ go test -v -i ./storage/sql 35 | $ go test -v ./storage/sql 36 | ``` 37 | 38 | - clean up the postgres container: 39 | 40 | ```bash 41 | docker rm -f dex-postgres 42 | ``` 43 | 44 | ## Etcd 45 | 46 | These tests can also be executed using docker: 47 | 48 | - start the container (where `NODE1` is set to the host IP address): 49 | 50 | ```bash 51 | $ export NODE1=0.0.0.0 52 | $ docker run --name dex-etcd -p 2379:2379 -p 2380:2380 gcr.io/etcd-development/etcd:v3.3.10 \ 53 | /usr/local/bin/etcd --name node1 \ 54 | --initial-advertise-peer-urls http://${NODE1}:2380 --listen-peer-urls http://${NODE1}:2380 \ 55 | --advertise-client-urls http://${NODE1}:2379 --listen-client-urls http://${NODE1}:2379 \ 56 | --initial-cluster node1=http://${NODE1}:2380 57 | ``` 58 | 59 | - run the tests, passing the correct endpoint for this etcd instance in `DEX_ETCD_ENDPOINTS`: 60 | 61 | ```bash 62 | DEX_ETCD_ENDPOINTS=http://localhost:2379 go test -v ./storage/etcd 63 | ``` 64 | - clean up the etcd container: `docker rm -f dex-etcd` 65 | 66 | ## Kubernetes 67 | 68 | Running integration tests for Kubernetes storage requires the `DEX_KUBERNETES_CONFIG_PATH` environment variable 69 | be set with the path to kubeconfig file of the existing cluster. For tests, it is ok to use "mini" Kubernetes distributive, e.g., [KinD][kind], [Microk8s][microk8s]. 70 | 71 | Example KinD cluster test run: 72 | 73 | * Install KinD using the instructions from the [official website][kind-install]. 74 | 75 | * Run tests by executing the following commands: 76 | ```bash 77 | export DEX_KUBERNETES_CONFIG_PATH=$(mktemp /tmp/kubeconfig.XXXXXXXX) 78 | kind create cluster --kubeconfig "$DEX_KUBERNETES_CONFIG_PATH" 79 | 80 | go test -v ./storage/kubernetes 81 | ``` 82 | * To clean up, run: 83 | ```bash 84 | rm -f "$DEX_KUBERNETES_CONFIG_PATH" 85 | unset DEX_KUBERNETES_CONFIG_PATH 86 | 87 | kind delete cluster 88 | ``` 89 | 90 | ## LDAP 91 | 92 | The LDAP integration tests require [OpenLDAP][openldap] installed on the host machine. To run them, use `go test`: 93 | 94 | ```bash 95 | export DEX_LDAP_TESTS=1 96 | go test -v ./connector/ldap/ 97 | ``` 98 | 99 | To quickly stand up a LDAP server for development, see the LDAP [_"Getting started"_](/docs/connectors/ldap/#getting-started) example. This also requires OpenLDAP installed on the host. 100 | 101 | To stand up a containerized LDAP server run the OpenLDAP docker image: 102 | 103 | ```bash 104 | $ sudo docker run --hostname ldap.example.org --name openldap-container --detach osixia/openldap:1.1.6 105 | ``` 106 | 107 | By default TLS is enabled and a certificate is created with the container hostname, which in this case is "ldap.example.org". It will create an empty LDAP for the company Example Inc. and the domain example.org. By default the admin has the password admin. 108 | 109 | Add new users and groups (sample .ldif file included at the end): 110 | 111 | ```bash 112 | $ sudo docker exec openldap-container ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f -h ldap.example.org -ZZ 113 | ``` 114 | 115 | Verify that the added entries are in your directory with ldapsearch : 116 | 117 | ```bash 118 | $ sudo docker exec openldap-container ldapsearch -x -h localhost -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin 119 | ``` 120 | The .ldif file should contain seed data. Example file contents: 121 | 122 | ```bash 123 | dn: cn=Test1,dc=example,dc=org 124 | objectClass: organizationalRole 125 | cn: Test1 126 | 127 | dn: cn=Test2,dc=example,dc=org 128 | objectClass: organizationalRole 129 | cn: Test2 130 | 131 | dn: ou=groups,dc=example,dc=org 132 | ou: groups 133 | objectClass: top 134 | objectClass: organizationalUnit 135 | 136 | dn: cn=tstgrp,ou=groups,dc=example,dc=org 137 | objectClass: top 138 | objectClass: groupOfNames 139 | member: cn=Test1,dc=example,dc=org 140 | cn: tstgrp 141 | ``` 142 | 143 | ## SAML 144 | 145 | ### Okta 146 | 147 | The Okta identity provider supports free accounts for developers to test their implementation against. This document describes configuring an Okta application to test dex's SAML connector. 148 | 149 | First, [sign up for a developer account][okta-sign-up]. Then, to create a SAML application: 150 | 151 | * Go to the admin screen. 152 | * Click "Add application" 153 | * Click "Create New App" 154 | * Choose "SAML 2.0" and press "Create" 155 | * Configure SAML 156 | * Enter `http://127.0.0.1:5556/dex/callback` for "Single sign on URL" 157 | * Enter `http://127.0.0.1:5556/dex/callback` for "Audience URI (SP Entity ID)" 158 | * Under "ATTRIBUTE STATEMENTS (OPTIONAL)" add an "email" and "name" attribute. The values should be something like `user:email` and `user:firstName`, respectively. 159 | * Under "GROUP ATTRIBUTE STATEMENTS (OPTIONAL)" add a "groups" attribute. Use the "Regexp" filter `.*`. 160 | 161 | After the application's created, assign yourself to the app. 162 | 163 | * "Applications" > "Applications" 164 | * Click on your application then under the "People" tab press the "Assign to People" button and add yourself. 165 | 166 | At the app, go to the "Sign On" tab and then click "View Setup Instructions". Use those values to fill out the following connector in `examples/config-dev.yaml`. 167 | 168 | ```yaml 169 | connectors: 170 | - type: saml 171 | id: saml 172 | name: Okta 173 | config: 174 | ssoURL: ( "Identity Provider Single Sign-On URL" ) 175 | caData: ( base64'd value of "X.509 Certificate" ) 176 | redirectURI: http://127.0.0.1:5556/dex/callback 177 | usernameAttr: name 178 | emailAttr: email 179 | groupsAttr: groups 180 | ``` 181 | 182 | Start both dex and the example app, and try logging in (requires not requesting a refresh token). 183 | 184 | [kind]: https://github.com/kubernetes-sigs/kind/ 185 | [kind-install]: https://kind.sigs.k8s.io/docs/user/quick-start/#installation 186 | [microk8s]: https://github.com/ubuntu/microk8s 187 | [okta-sign-up]: https://www.okta.com/developer/signup/ 188 | [openldap]: https://www.openldap.org/ 189 | -------------------------------------------------------------------------------- /content/docs/archive/proposals/user-object.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Proposal: User Objects for Revoking Refresh Tokens and Merging Accounts" 3 | linkTitle: "User Objects for Revoking Refresh Tokens and Merging Accounts" 4 | description: "" 5 | date: 2020-09-30 6 | draft: true 7 | toc: true 8 | weight: 20 9 | --- 10 | 11 | Certain operations require tracking users the have logged in through the server 12 | and storing them in the backend. Namely, allowing end users to revoke refresh 13 | tokens and merging existing accounts with upstream providers. 14 | 15 | While revoking refresh tokens is relatively easy, merging accounts is a 16 | difficult problem. What if display names or emails are different? What happens 17 | to a user with two remote identities with the same upstream service? Should 18 | this be presented differently for a user with remote identities for different 19 | upstream services? This proposal only covers a minimal merging implementation 20 | by guaranteeing that merged accounts will always be presented to clients with 21 | the same user ID. 22 | 23 | This proposal defines the following objects and methods to be added to the 24 | storage package to allow user information to be persisted. 25 | 26 | ```go 27 | // User is an end user which has logged into the server. 28 | // 29 | // Users do not hold additional data, such as emails, because claim information 30 | // is always supplied by an upstream provider during the auth flow. The ID is 31 | // the only information from this object which overrides the claims produced by 32 | // connectors. 33 | // 34 | // Clients which wish to associate additional data with a user must do so on 35 | // their own. The server only guarantees that IDs will be constant for an end 36 | // user, no matter what backend they use to login. 37 | type User struct { 38 | // A string which uniquely identifies the user for the server. This overrides 39 | // the ID provided by the connector in the ID Token claims. 40 | ID string 41 | 42 | // A list of clients who have been issued refresh tokens for this user. 43 | // 44 | // When a refresh token is redeemed, the server will check this field to 45 | // ensure that the client is still on this list. To revoke a client, 46 | // remove it from here. 47 | AuthorizedClients []AuthorizedClient 48 | 49 | // A set of remote identities which are able to login as this user. 50 | RemoteIdentities []RemoteIdentity 51 | } 52 | 53 | // AuthorizedClient is a client that has a refresh token out for this user. 54 | type AuthorizedClient struct { 55 | // The ID of the client. 56 | ClientID string 57 | // The last time a token was refreshed. 58 | LastRefreshed time.Time 59 | } 60 | 61 | // RemoteIdentity is the smallest amount of information that identifies a user 62 | // with a remote service. It indicates which remote identities should be able 63 | // to login as a specific user. 64 | // 65 | // RemoteIdentity contains an username so an end user can be displayed this 66 | // object and reason about what upstream profile it represents. It is not used 67 | // to cache claims, such as groups or emails, because these are always provided 68 | // by the upstream identity system during login. 69 | type RemoteIdentity struct { 70 | // The ID of the connector used to login the user. 71 | ConnectorID string 72 | // A string which uniquely identifies the user with the remote system. 73 | ConnectorUserID string 74 | 75 | // Optional, human readable name for this remote identity. Only used when 76 | // displaying the remote identity to the end user (e.g. when merging 77 | // accounts). NOT used for determining ID Token claims. 78 | Username string 79 | } 80 | ``` 81 | 82 | `UserID` fields will be added to the `AuthRequest`, `AuthCode` and `RefreshToken` 83 | structs. When a user logs in successfully through a connector 84 | [here](https://github.com/dexidp/dex/blob/95a61454b522edd6643ced36b9d4b9baa8059556/server/handlers.go#L227), 85 | the server will attempt to either get the user, or create one if none exists with 86 | the remote identity. 87 | 88 | `AuthorizedClients` serves two roles. First is makes displaying the set of 89 | clients a user is logged into easy. Second, because we don't assume multi-object 90 | transactions, we can't ensure deleting all refresh tokens a client has for a 91 | user. Between listing the set of refresh tokens and deleting a token, a client 92 | may have already redeemed the token and created a new one. 93 | 94 | When an OAuth2 client exchanges a code for a token, the following steps are 95 | taken to populate the `AuthorizedClients`: 96 | 97 | 1. Get token where the user has authorized the `offline_access` scope. 98 | 1. Update the user checking authorized clients. If client is not in the list, 99 | add it. 100 | 1. Create a refresh token and return the token. 101 | 102 | When a OAuth2 client attempts to renew a refresh token, the server ensures that 103 | the token hasn't been revoked. 104 | 105 | 1. Check authorized clients and update the `LastRefreshed` timestamp. If client 106 | isn't in list error out and delete the refresh token. 107 | 1. Continue renewing the refresh token. 108 | 109 | When the end user revokes a client, the following steps are used to. 110 | 111 | 1. Update the authorized clients by removing the client from the list. This 112 | atomic action causes any renew attempts to fail. 113 | 1. Iterate through list of refresh tokens and garbage collect any tokens issued 114 | by the user for the client. This isn't atomic, but exists so a user can 115 | re-authorize a client at a later time without authorizing old refresh tokens. 116 | 117 | This is clunky due to the lack of multi-object transactions. E.g. we can't delete 118 | all the refresh tokens at once because we don't have that guarantee. 119 | 120 | Merging accounts becomes extremely simple. Just add another remote identity to 121 | the user object. 122 | 123 | We hope to provide a web interface that a user can login to to perform these 124 | actions. Perhaps using a well known client issued exclusively for the server. 125 | 126 | The new `User` object requires adding the following methods to the storage 127 | interface, and (as a nice side effect) deleting the `ListRefreshTokens()` method. 128 | 129 | ```go 130 | type Storage interface { 131 | // ... 132 | 133 | CreateUser(u User) error 134 | 135 | DeleteUser(id string) error 136 | 137 | GetUser(id string) error 138 | GetUserByRemoteIdentity(connectorID, connectorUserID string) (User, error) 139 | 140 | // Updates are assumed to be atomic. 141 | // 142 | // When a UpdateUser is called, if clients are removed from the 143 | // AuthorizedClients list, the underlying storage SHOULD clean up refresh 144 | // tokens issued for the removed clients. This allows backends with 145 | // multi-transactional capabilities to utilize them, while key-value stores 146 | // only guarantee best effort. 147 | UpdateUser(id string, updater func(old User) (User, error)) error 148 | } 149 | ``` 150 | 151 | Importantly, this will be the first object which has a secondary index. 152 | The Kubernetes client will simply list all the users in memory then iterate over 153 | them to support this (possibly followed by a "watch" based optimization). SQL 154 | implementations will have an easier time. 155 | -------------------------------------------------------------------------------- /content/docs/archive/proposals/upstream-refreshing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Proposal: Upstream Refreshing" 3 | linkTitle: "Upstream Refreshing" 4 | description: "" 5 | date: 2020-09-30 6 | draft: true 7 | toc: true 8 | weight: 20 9 | --- 10 | 11 | ## TL;DR 12 | 13 | Today, if a user deletes their GitHub account, dex will keep allowing clients to 14 | refresh tokens on that user's behalf because dex never checks back in with 15 | GitHub. 16 | 17 | This is a proposal to change the connector package so the dex can check back 18 | in with GitHub. 19 | 20 | ## The problem 21 | 22 | When dex is federating to an upstream identity provider (IDP), we want to ensure 23 | claims being passed onto clients remain fresh. This includes data such as Google 24 | accounts display names, LDAP group membership, account deactivations. Changes to 25 | these on an upstream IDP should always be reflected in the claims dex passes to 26 | its own clients. 27 | 28 | Refresh tokens make this complicated. When refreshing a token, unlike normal 29 | logins, dex doesn't have the opportunity to prompt for user interaction. For 30 | example, if dex is proxying to a LDAP server, it won't have the user's username 31 | and passwords. 32 | 33 | Dex can't do this today because connectors have no concept of checking back in 34 | with an upstream provider (with the sole exception of groups). They're only 35 | called during the initial login, and never consulted when dex needs to mint a 36 | new refresh token for a client. Additionally, connectors aren't actually aware 37 | of the scopes being requested by the client, so they don't know when they should 38 | setup the ability to check back in and have to treat every request identically. 39 | 40 | ## Changes to the connector package 41 | 42 | The biggest changes proposed impact the connector package and connector 43 | implementations. 44 | 45 | 1. Connectors should be consulted when dex attempts to refresh a token. 46 | 2. Connectors should be aware of the scopes requested by the client. 47 | 48 | The second bullet is important because of the first. If a client isn't 49 | requesting a refresh token, the connector shouldn't do the extra work, such as 50 | requesting additional upstream scopes. 51 | 52 | to address the first point, a top level `Scopes` object will be added to the 53 | connector package to express the scopes requested by the client. The 54 | `CallbackConnector` and `PasswordConnector` will be updated accordingly. 55 | 56 | ```go 57 | // Scopes represents additional data requested by the clients about the end user. 58 | type Scopes struct{ 59 | // The client has requested a refresh token from the server. 60 | OfflineAccess bool 61 | 62 | // The client has requested group information about the end user. 63 | Groups bool 64 | } 65 | 66 | // CallbackConnector is an interface implemented by connectors which use an OAuth 67 | // style redirect flow to determine user information. 68 | type CallbackConnector interface { 69 | // The initial URL to redirect the user to. 70 | // 71 | // OAuth2 implementations should request different scopes from the upstream 72 | // identity provider based on the scopes requested by the downstream client. 73 | // For example, if the downstream client requests a refresh token from the 74 | // server, the connector should also request a token from the provider. 75 | LoginURL(s Scopes, callbackURL, state string) (string, error) 76 | 77 | // Handle the callback to the server and return an identity. 78 | HandleCallback(s Scopes, r *http.Request) (identity Identity, state string, err error) 79 | } 80 | 81 | // PasswordConnector is an interface implemented by connectors which take a 82 | // username and password. 83 | type PasswordConnector interface { 84 | Login(s Scopes, username, password string) (identity Identity, validPassword bool, err error) 85 | } 86 | ``` 87 | 88 | The existing `GroupsConnector` plays two roles. 89 | 90 | 1. The connector only attempts to grab groups when the downstream client requests it. 91 | 2. Allow group information to be refreshed. 92 | 93 | The first issue is remedied by the added `Scopes` struct. This proposal also 94 | hopes to generalize the need of the second role by adding a more general 95 | `RefreshConnector`: 96 | 97 | ```go 98 | type Identity struct { 99 | // Existing fields... 100 | 101 | // Groups are added to the identity object, since connectors are now told 102 | // if they're being requested. 103 | 104 | // The set of groups a user is a member of. 105 | Groups []string 106 | } 107 | 108 | 109 | // RefreshConnector is a connector that can update the client claims. 110 | type RefreshConnector interface { 111 | // Refresh is called when a client attempts to claim a refresh token. The 112 | // connector should attempt to update the identity object to reflect any 113 | // changes since the token was last refreshed. 114 | Refresh(s Scopes, identity Identity) (Identity, error) 115 | 116 | // TODO(ericchiang): Should we allow connectors to indicate that the user has 117 | // been delete or an upstream token has been revoked? This would allow us to 118 | // know when we should remove the downstream refresh token, and when there was 119 | // just a server error, but might be hard to determine for certain protocols. 120 | // Might be safer to always delete the downstream token if the Refresh() 121 | // method returns an error. 122 | } 123 | ``` 124 | 125 | ## Example changes to the "passwordDB" connector 126 | 127 | The `passwordDB` connector is the internal connector maintained by the server. 128 | As an example, these are the changes to that connector if this change was 129 | accepted. 130 | 131 | ```go 132 | func (db passwordDB) Login(s connector.Scopes, username, password string) (connector.Identity, bool, error) { 133 | // No change to existing implementation. Scopes can be ignored since we'll 134 | // always have access to the password objects. 135 | 136 | } 137 | 138 | func (db passwordDB) Refresh(s connector.Scopes, identity connector.Identity) (connector.Identity, error) { 139 | // If the user has been deleted, the refresh token will be rejected. 140 | p, err := db.s.GetPassword(identity.Email) 141 | if err != nil { 142 | if err == storage.ErrNotFound { 143 | return connector.Identity{}, errors.New("user not found") 144 | } 145 | return connector.Identity{}, fmt.Errorf("get password: %v", err) 146 | } 147 | 148 | // User removed but a new user with the same email exists. 149 | if p.UserID != identity.UserID { 150 | return connector.Identity{}, errors.New("user not found") 151 | } 152 | 153 | // If a user has updated their username, that will be reflected in the 154 | // refreshed token. 155 | identity.Username = p.Username 156 | return identity, nil 157 | } 158 | ``` 159 | 160 | ## Caveats 161 | 162 | Certain providers, such as Google, will only grant a single refresh token for each 163 | client + end user pair. The second time one's requested, no refresh token is 164 | returned. This means refresh tokens must be stored by dex as objects on an 165 | upstream identity rather than part of a downstream refresh even. 166 | 167 | Right now `ConnectorData` is too general for this since it is only stored with a 168 | refresh token and can't be shared between sessions. This should be rethought in 169 | combination with the [`user-object.md`](./user-object.md) proposal to see if 170 | there are reasonable ways for us to do this. 171 | 172 | This isn't a problem for providers like GitHub because they return the same 173 | refresh token every time. We don't need to track a token per client. 174 | -------------------------------------------------------------------------------- /content/docs/connectors/oidc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through an OpenID Connect Provider" 3 | linkTitle: "OpenID Connect" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2050 9 | --- 10 | 11 | ## Overview 12 | 13 | Dex is able to use another OpenID Connect provider as an authentication source. When logging in, dex will redirect to the upstream provider and perform the necessary OAuth2 flows to determine the end users email, username, etc. More details on the OpenID Connect protocol can be found in [_An overview of OpenID Connect_](../openid-connect.md). 14 | 15 | Prominent examples of OpenID Connect providers include Google Accounts, Salesforce, and Azure AD v2 ([not v1][azure-ad-v1]). 16 | 17 | ## Configuration 18 | 19 | ```yaml 20 | connectors: 21 | - type: oidc 22 | id: google 23 | name: Google 24 | config: 25 | # Canonical URL of the provider, also used for configuration discovery. 26 | # This value MUST match the value returned in the provider config discovery. 27 | # 28 | # See: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig 29 | issuer: https://accounts.google.com 30 | 31 | # Some offspec providers like Azure, Oracle IDCS have oidc discovery url 32 | # different from issuer url which causes issuerValidation to fail 33 | # issuerAlias provides a way to override the Issuer url 34 | # from the .well-known/openid-configuration issuer 35 | # issuerAlias: https://accounts.google.com 36 | 37 | # Connector config values starting with a "$" will read from the environment. 38 | clientID: $GOOGLE_CLIENT_ID 39 | clientSecret: $GOOGLE_CLIENT_SECRET 40 | 41 | # Dex's issuer URL + "/callback" 42 | redirectURI: http://127.0.0.1:5556/dex/callback 43 | 44 | 45 | # Some providers require passing client_secret via POST parameters instead 46 | # of basic auth, despite the OAuth2 RFC discouraging it. Many of these 47 | # cases are caught internally, but some may need to uncomment the 48 | # following field. 49 | # 50 | # basicAuthUnsupported: true 51 | 52 | # List of additional scopes to request in token response 53 | # Default is profile and email 54 | # Full list at https://dexidp.io/docs/custom-scopes-claims-clients/ 55 | # scopes: 56 | # - profile 57 | # - email 58 | # - groups 59 | 60 | # Some providers return claims without "email_verified", when they had no usage of emails verification in enrollment process 61 | # or if they are acting as a proxy for another IDP etc AWS Cognito with an upstream SAML IDP 62 | # This can be overridden with the below option 63 | # insecureSkipEmailVerified: true 64 | 65 | # Groups claims (like the rest of oidc claims through dex) only refresh when the id token is refreshed 66 | # meaning the regular refresh flow doesn't update the groups claim. As such by default the oidc connector 67 | # doesn't allow groups claims. If you are okay with having potentially stale group claims you can use 68 | # this option to enable groups claims through the oidc connector on a per-connector basis. 69 | # This can be overridden with the below option 70 | # insecureEnableGroups: true 71 | 72 | # Filter users based on membership in the given groups. Authentication will be successful it the user is a member in a least 73 | # one of the specified groups. 74 | # allowedGroups: 75 | # - 76 | 77 | # When enabled, the OpenID Connector will query the UserInfo endpoint for additional claims. UserInfo claims 78 | # take priority over claims returned by the IDToken. This option should be used when the IDToken doesn't contain 79 | # all the claims requested. 80 | # https://openid.net/specs/openid-connect-core-1_0.html#UserInfo 81 | # getUserInfo: true 82 | 83 | # The set claim is used as user id. 84 | # Claims list at https://openid.net/specs/openid-connect-core-1_0.html#Claims 85 | # Default: sub 86 | # userIDKey: nickname 87 | 88 | # The set claim is used as user name. 89 | # Default: name 90 | # userNameKey: nickname 91 | 92 | # The acr_values variable specifies the Authentication Context Class Values within 93 | # the Authentication Request that the Authorization Server is being requested to process 94 | # from this Client. 95 | # acrValues: 96 | # - 97 | # - 98 | 99 | # For offline_access, the prompt parameter is set by default to "prompt=consent". 100 | # However this is not supported by all OIDC providers, some of them support different 101 | # value for prompt, like "prompt=login" or "prompt=none" 102 | # promptType: consent 103 | 104 | # Some providers return non-standard claims (eg. mail). 105 | # Use claimMapping to map those claims to standard claims: 106 | # https://openid.net/specs/openid-connect-core-1_0.html#Claims 107 | # claimMapping can only map a non-standard claim to a standard one if it's not returned in the id_token. 108 | claimMapping: 109 | # The set claim is used as preferred username. 110 | # Default: preferred_username 111 | # preferred_username: other_user_name 112 | 113 | # The set claim is used as email. 114 | # Default: email 115 | # email: mail 116 | 117 | # The set claim is used as groups. 118 | # Default: groups 119 | # groups: "cognito:groups" 120 | 121 | # claimModifications can change claims during the login 122 | claimModifications: 123 | # newGroupFromClaims allows to create a new group, based on other claims 124 | # they are concatenated using the delimiter. 125 | # Currently only string claims are supported, and other claims are skipped 126 | # The new group name is added to the groups claims, passed to the clients. 127 | # For this example, the resulting group would be: `example::organization::email` 128 | # newGroupFromClaims: 129 | # - prefix: example 130 | # delimiter: "::" 131 | # clearDelimiter: false 132 | # claims: 133 | # - organization 134 | # - email 135 | 136 | # filterGroupClaims allows to filter the groups, using a regex. 137 | # The regex must conform to the RE2 regex specification used in go regexp. 138 | # Groups added using the newGroupFromClaims modification, are not passed through the filterGroupClaims 139 | # filterGroupClaims: 140 | # groupsFilter: "" 141 | 142 | # modifyGroupNames allows to add a prefix or suffix to all groups 143 | # Either one, or both fields can be specified, and they will be pre-/appended directly to the group-name as provided by the oidc issuer 144 | # The modifications are applied to all groups, not filtered by filterGroupClaims, and before Groups from newGroupFromClaims are created 145 | # For example, if the connector provides a group called "regular-users", 146 | # this modification would convert it to "example-prefix-regular-usersexample-suffix" 147 | # modifyGroupNames: 148 | # prefix: example-prefix- # note the delimiter at the end 149 | # suffix: example-suffix 150 | 151 | 152 | # overrideClaimMapping will be used to override the options defined in claimMappings. 153 | # i.e. if there are 'email' and `preferred_email` claims available, by default Dex will always use the `email` claim independent of the claimMapping.email. 154 | # This setting allows you to override the default behavior of Dex and enforce the mappings defined in `claimMapping`. 155 | overrideClaimMapping: false 156 | 157 | # The section to override options discovered automatically from 158 | # the providers' discovery URL (.well-known/openid-configuration). 159 | providerDiscoveryOverrides: 160 | # tokenURL provides a way to user overwrite the token URL 161 | # from the .well-known/openid-configuration 'token_endpoint'. 162 | # tokenURL: "" 163 | # 164 | # authURL provides a way to user overwrite the authorization URL 165 | # from the .well-known/openid-configuration 'authorization_endpoint'. 166 | # authURL: "" 167 | ``` 168 | 169 | [oidc-doc]: openid-connect.md 170 | [issue-863]: https://github.com/dexidp/dex/issues/863 171 | [azure-ad-v1]: https://github.com/coreos/go-oidc/issues/133 172 | -------------------------------------------------------------------------------- /content/docs/connectors/github.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through GitHub" 3 | linkTitle: "GitHub" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2020 9 | --- 10 | 11 | ## Overview 12 | 13 | One of the login options for dex uses the GitHub OAuth2 flow to identify the end user through their GitHub account. 14 | 15 | When a client redeems a refresh token through dex, dex will re-query GitHub to update user information in the ID Token. To do this, __dex stores a readonly GitHub access token in its backing datastore.__ Users that reject dex's access through GitHub will also revoke all dex clients which authenticated them through GitHub. 16 | 17 | ## Caveats 18 | 19 | * A user must explicitly [request][github-request-org-access] an [organization][github-orgs] give dex [resource access][github-approve-org-access]. Dex will not have the correct permissions to determine if the user is in that organization otherwise, and the user will not be able to log in. This request mechanism is a feature of the GitHub API. 20 | 21 | ## Configuration 22 | 23 | Register a new application with [GitHub][github-oauth2] ensuring the callback URL is `(dex issuer)/callback`. For example if dex is listening at the non-root path `https://auth.example.com/dex` the callback would be `https://auth.example.com/dex/callback`. 24 | 25 | The following is an example of a configuration for `examples/config-dev.yaml`: 26 | 27 | ```yaml 28 | connectors: 29 | - type: github 30 | # Required field for connector id. 31 | id: github 32 | # Required field for connector name. 33 | name: GitHub 34 | config: 35 | # Credentials can be string literals or pulled from the environment. 36 | clientID: $GITHUB_CLIENT_ID 37 | clientSecret: $GITHUB_CLIENT_SECRET 38 | redirectURI: http://127.0.0.1:5556/dex/callback 39 | 40 | # Legacy 'org' field. 41 | # - A user MUST be a member of the following org to authenticate with dex. 42 | # - Both 'org' and 'orgs' can NOT be used simultaneously. 43 | #org: my-organization 44 | 45 | # List of org and team names. 46 | # - If specified, a user MUST be a member of at least ONE of these orgs 47 | # and teams (if set) to authenticate with dex. 48 | # - Dex queries the following organizations for group information if the 49 | # "groups" scope is requested. Group claims are formatted as "(org):(team)". 50 | # For example if a user is part of the "engineering" team of the "coreos" org, 51 | # the group claim would include "coreos:engineering". 52 | # - If teams are specified, dex only returns group claims for those teams. 53 | orgs: 54 | - name: my-organization 55 | - name: my-organization-with-teams 56 | teams: 57 | - red-team 58 | - blue-team 59 | 60 | # Flag which indicates that all the user's orgs and teams should be loaded. 61 | # Only works if neither 'org' nor 'orgs' are specified in the config. 62 | loadAllGroups: false 63 | 64 | # How the team names are formatted. 65 | # - Options: 'name' (default), 'slug', 'both'. 66 | # - Examples: 67 | # - 'name': 'acme:Site Reliability Engineers' 68 | # - 'slug': 'acme:site-reliability-engineers' 69 | # - 'both': 'acme:Site Reliability Engineers', 'acme:site-reliability-engineers' 70 | teamNameField: slug 71 | 72 | # Flag which will switch from using the internal GitHub id to the users handle (@mention) as the user id. 73 | # It is possible for a user to change their own username, but it is very rare for them to do so 74 | useLoginAsID: false 75 | 76 | # A preferred email domain to use when returning the user's email. 77 | # - If the user has a PUBLIC email, it is ALWAYS returned in the email claim, 78 | # so this field would have NO effect (this may change in the future). 79 | # - By default, if the user does NOT have a public email, their primary email is returned. 80 | # - When 'preferredEmailDomain' is set, the first email matching this domain is returned, 81 | # we fall back to the primary email if no match is found. 82 | # - To allow multiple subdomains, you may specify a wildcard like "*.example.com" 83 | # which will match "aaaa.example.com" and "bbbb.example.com", but NOT "example.com". 84 | # - To return the user's no-reply email, set this field to "users.noreply.github.com", 85 | # this is a mostly static email that GitHub assigns to the user. These emails 86 | # are formatted like 'ID+USERNAME@users.noreply.github.com' for newer accounts 87 | # and 'USERNAME@users.noreply.github.com' for older accounts. 88 | #preferredEmailDomain: "example.com" 89 | ``` 90 | 91 | ## GitHub Enterprise 92 | 93 | Users can use their GitHub Enterprise account to login to dex. The following configuration can be used to enable a GitHub Enterprise connector on dex: 94 | 95 | ```yaml 96 | connectors: 97 | - type: github 98 | # Required field for connector id. 99 | id: github 100 | # Required field for connector name. 101 | name: GitHub 102 | config: 103 | # Required fields. Dex must be pre-registered with GitHub Enterprise 104 | # to get the following values. 105 | # Credentials can be string literals or pulled from the environment. 106 | clientID: $GITHUB_CLIENT_ID 107 | clientSecret: $GITHUB_CLIENT_SECRET 108 | redirectURI: http://127.0.0.1:5556/dex/callback 109 | 110 | # List of org and team names. 111 | # - If specified, a user MUST be a member of at least ONE of these orgs 112 | # and teams (if set) to authenticate with dex. 113 | # - Dex queries the following organizations for group information if the 114 | # "groups" scope is requested. Group claims are formatted as "(org):(team)". 115 | # For example if a user is part of the "engineering" team of the "coreos" org, 116 | # the group claim would include "coreos:engineering". 117 | # - If teams are specified, dex only returns group claims for those teams. 118 | orgs: 119 | - name: my-organization 120 | - name: my-organization-with-teams 121 | teams: 122 | - red-team 123 | - blue-team 124 | 125 | # Flag which indicates that all the user's orgs and teams should be loaded. 126 | # Only works if neither 'org' nor 'orgs' are specified in the config. 127 | loadAllGroups: false 128 | 129 | # How the team names are formatted 130 | # - Options: 'name' (default), 'slug', 'both'. 131 | # - Examples: 132 | # - 'name': 'acme:Site Reliability Engineers' 133 | # - 'slug': 'acme:site-reliability-engineers' 134 | # - 'both': 'acme:Site Reliability Engineers', 'acme:site-reliability-engineers' 135 | teamNameField: slug 136 | 137 | # Required ONLY for GitHub Enterprise. 138 | # This is the Hostname of the GitHub Enterprise account listed on the 139 | # management console. Ensure this domain is routable on your network. 140 | hostName: git.example.com 141 | 142 | # ONLY for GitHub Enterprise. Optional field. 143 | # Used to support self-signed or untrusted CA root certificates. 144 | rootCA: /etc/dex/ca.crt 145 | ``` 146 | 147 | ### Generate TLS assets 148 | 149 | Running Dex with HTTPS enabled requires a valid SSL certificate, and the API server needs to trust the certificate of the signing CA using the `--oidc-ca-file` flag. 150 | 151 | For our example use case, the TLS assets can be created using the following command: 152 | 153 | ```bash 154 | $ ./examples/k8s/gencert.sh 155 | ``` 156 | 157 | This will generate several files under the `ssl` directory, the important ones being `cert.pem` ,`key.pem` and `ca.pem`. The generated SSL certificate is for 'dex.example.com', although you could change this by editing `gencert.sh` if required. 158 | 159 | ### Run example client app with GitHub config 160 | 161 | ```bash 162 | ./bin/example-app --issuer-root-ca examples/k8s/ssl/ca.pem 163 | ``` 164 | 165 | 1. Open browser to http://127.0.0.1:5555 166 | 2. Click Login 167 | 3. Select Log in with GitHub and grant access to dex to view your profile 168 | 169 | [github-oauth2]: https://github.com/settings/applications/new 170 | [github-orgs]: https://developer.github.com/v3/orgs/ 171 | [github-request-org-access]: https://help.github.com/articles/requesting-organization-approval-for-oauth-apps/ 172 | [github-approve-org-access]: https://help.github.com/articles/approving-oauth-apps-for-your-organization/ 173 | -------------------------------------------------------------------------------- /content/docs/guides/using-dex.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Writing Apps That Use Dex" 3 | description: "" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 1017 8 | --- 9 | 10 | Once you have dex up and running, the next step is to write applications that use dex to drive authentication. Apps that interact with dex generally fall into one of two categories: 11 | 12 | 1. Apps that request OpenID Connect ID tokens to authenticate users. 13 | * Used for authenticating an end user. 14 | * Must be web based. 15 | 2. Apps that consume ID tokens from other apps. 16 | * Needs to verify that a client is acting on behalf of a user. 17 | 18 | The first category of apps are standard OAuth2 clients. Users show up at a website, and the application wants to authenticate those end users by pulling claims out of the ID token. 19 | 20 | The second category of apps consume ID tokens as credentials. This lets another service handle OAuth2 flows, then use the ID token retrieved from dex to act on the end user's behalf with the app. An example of an app that falls into this category is the [Kubernetes API server][api-server]. 21 | 22 | ## Requesting an ID token from dex 23 | 24 | Apps that directly use dex to authenticate a user use OAuth2 code flows to request a token response. The exact steps taken are: 25 | 26 | * User visits client app. 27 | * Client app redirects user to dex with an OAuth2 request. 28 | * Dex determines user's identity. 29 | * Dex redirects user to client with a code. 30 | * Client exchanges code with dex for an id_token. 31 | 32 | ![Dex flow](/img/dex-flow.png) 33 | 34 | The dex repo contains a small [example app][example-app] as a working, self contained app that performs this flow. 35 | 36 | The rest of this section explores the code sections which help explain how to implement this logic in your own app. 37 | 38 | ### Configuring your app 39 | 40 | The example app uses the following Go packages to perform the code flow: 41 | 42 | * [github.com/coreos/go-oidc][go-oidc] 43 | * [golang.org/x/oauth2][go-oauth2] 44 | 45 | First, client details should be present in the dex configuration. For example, we could register an app with dex with the following section: 46 | 47 | ```yaml 48 | staticClients: 49 | - id: example-app 50 | secret: example-app-secret 51 | name: 'Example App' 52 | # Where the app will be running. 53 | redirectURIs: 54 | - 'http://127.0.0.1:5555/callback' 55 | ``` 56 | 57 | In this case, the Go code would be configured as: 58 | 59 | ```go 60 | // Initialize a provider by specifying dex's issuer URL. 61 | provider, err := oidc.NewProvider(ctx, "https://dex-issuer-url.com") 62 | if err != nil { 63 | // handle error 64 | } 65 | 66 | // Configure the OAuth2 config with the client values. 67 | oauth2Config := oauth2.Config{ 68 | // client_id and client_secret of the client. 69 | ClientID: "example-app", 70 | ClientSecret: "example-app-secret", 71 | 72 | // The redirectURL. 73 | RedirectURL: "http://127.0.0.1:5555/callback", 74 | 75 | // Discovery returns the OAuth2 endpoints. 76 | Endpoint: provider.Endpoint(), 77 | 78 | // "openid" is a required scope for OpenID Connect flows. 79 | // 80 | // Other scopes, such as "groups" can be requested. 81 | Scopes: []string{oidc.ScopeOpenID, "profile", "email", "groups"}, 82 | } 83 | 84 | // Create an ID token parser. 85 | idTokenVerifier := provider.Verifier(&oidc.Config{ClientID: "example-app"}) 86 | ``` 87 | 88 | The HTTP server should then redirect unauthenticated users to dex to initialize the OAuth2 flow. 89 | 90 | ```go 91 | // handleRedirect is used to start an OAuth2 flow with the dex server. 92 | func handleRedirect(w http.ResponseWriter, r *http.Request) { 93 | state := newState() 94 | http.Redirect(w, r, oauth2Config.AuthCodeURL(state), http.StatusFound) 95 | } 96 | ``` 97 | 98 | After dex verifies the user's identity it redirects the user back to the client app with a code that can be exchanged for an ID token. The ID token can then be parsed by the verifier created above. This immediately 99 | 100 | ```go 101 | func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) { 102 | state := r.URL.Query().Get("state") 103 | 104 | // Verify state. 105 | 106 | oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code")) 107 | if err != nil { 108 | // handle error 109 | } 110 | 111 | // Extract the ID Token from OAuth2 token. 112 | rawIDToken, ok := oauth2Token.Extra("id_token").(string) 113 | if !ok { 114 | // handle missing token 115 | } 116 | 117 | // Parse and verify ID Token payload. 118 | idToken, err := idTokenVerifier.Verify(ctx, rawIDToken) 119 | if err != nil { 120 | // handle error 121 | } 122 | 123 | // Extract custom claims. 124 | var claims struct { 125 | Email string `json:"email"` 126 | Verified bool `json:"email_verified"` 127 | Groups []string `json:"groups"` 128 | } 129 | if err := idToken.Claims(&claims); err != nil { 130 | // handle error 131 | } 132 | } 133 | ``` 134 | 135 | ### State tokens 136 | 137 | The state parameter is an arbitrary string that dex will always return with the callback. It plays a security role, preventing certain kinds of OAuth2 attacks. Specifically it can be used by clients to ensure: 138 | 139 | * The user who started the flow is the one who finished it, by linking the user's session with the state token. For example, by setting the state as an HTTP cookie, then comparing it when the user returns to the app. 140 | * The request hasn't been replayed. This could be accomplished by associating some nonce in the state. 141 | 142 | A more thorough discussion of these kinds of best practices can be found in the [_"OAuth 2.0 Threat Model and Security Considerations"_][oauth2-threat-model] RFC. 143 | 144 | ## Consuming ID tokens 145 | 146 | Apps can also choose to consume ID tokens, letting other trusted clients handle the web flows for login. Clients pass along the ID tokens they receive from dex, usually as a bearer token, letting them act as the user to the backend service. 147 | 148 | ![Dex backend flow](/img/dex-backend-flow.png) 149 | 150 | To accept ID tokens as user credentials, an app would construct an OpenID Connect verifier similarly to the above example. The verifier validates the ID token's signature, ensures it hasn't expired, etc. An important part of this code is that the verifier only trusts the example app's client. This ensures the example app is the one who's using the ID token, and not another, untrusted client. 151 | 152 | ```go 153 | // Initialize a provider by specifying dex's issuer URL. 154 | provider, err := oidc.NewProvider(ctx, "https://dex-issuer-url.com") 155 | if err != nil { 156 | // handle error 157 | } 158 | // Create an ID token parser, but only trust ID tokens issued to "example-app" 159 | idTokenVerifier := provider.Verifier(&oidc.Config{ClientID: "example-app"}) 160 | ``` 161 | 162 | The verifier can then be used to pull user info out of tokens: 163 | 164 | ```go 165 | type user struct { 166 | email string 167 | groups []string 168 | } 169 | 170 | // authorize verifies a bearer token and pulls user information form the claims. 171 | func authorize(ctx context.Context, bearerToken string) (*user, error) { 172 | idToken, err := idTokenVerifier.Verify(ctx, bearerToken) 173 | if err != nil { 174 | return nil, fmt.Errorf("could not verify bearer token: %v", err) 175 | } 176 | // Extract custom claims. 177 | var claims struct { 178 | Email string `json:"email"` 179 | Verified bool `json:"email_verified"` 180 | Groups []string `json:"groups"` 181 | } 182 | if err := idToken.Claims(&claims); err != nil { 183 | return nil, fmt.Errorf("failed to parse claims: %v", err) 184 | } 185 | if !claims.Verified { 186 | return nil, fmt.Errorf("email (%q) in returned claims was not verified", claims.Email) 187 | } 188 | return &user{claims.Email, claims.Groups}, nil 189 | } 190 | ``` 191 | 192 | [api-server]: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens 193 | [dex-flow]: img/dex-flow.png 194 | [dex-backend-flow]: img/dex-backend-flow.png 195 | [example-app]: https://github.com/dexidp/dex/tree/master/examples/example-app 196 | [oauth2-threat-model]: https://tools.ietf.org/html/rfc6819 197 | [go-oidc]: https://godoc.org/github.com/coreos/go-oidc 198 | [go-oauth2]: https://godoc.org/golang.org/x/oauth2 199 | -------------------------------------------------------------------------------- /hugo.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://dexidp.io/" 2 | copyright = "Dex IdP Contributors" 3 | theme = "docsy" 4 | 5 | # Language settings 6 | contentDir = "content" 7 | defaultContentLanguage = "en" 8 | defaultContentLanguageInSubdir = false 9 | # Useful when translating. 10 | enableMissingTranslationPlaceholders = true 11 | 12 | enableRobotsTXT = true 13 | 14 | # Will give values to .Lastmod etc. 15 | enableGitInfo = false 16 | 17 | # Comment out to enable taxonomies in Docsy 18 | # disableKinds = ["taxonomy", "taxonomyTerm"] 19 | 20 | # You can add your own taxonomies 21 | [taxonomies] 22 | tag = "tags" 23 | category = "categories" 24 | 25 | [params.taxonomy] 26 | # set taxonomyCloud = [] to hide taxonomy clouds 27 | taxonomyCloud = ["tags", "categories"] 28 | 29 | # If used, must have same length as taxonomyCloud 30 | taxonomyCloudTitle = ["Tag Cloud", "Categories"] 31 | 32 | # set taxonomyPageHeader = [] to hide taxonomies on the page headers 33 | taxonomyPageHeader = ["tags", "categories"] 34 | 35 | 36 | # Highlighting config 37 | pygmentsCodeFences = true 38 | pygmentsUseClasses = false 39 | # Use the new Chroma Go highlighter in Hugo. 40 | pygmentsUseClassic = false 41 | #pygmentsOptions = "linenos=table" 42 | # See https://help.farbox.com/pygments.html 43 | pygmentsStyle = "tango" 44 | 45 | # Configure how URLs look like per section. 46 | [permalinks] 47 | blog = "/:section/:year/:month/:day/:slug/" 48 | 49 | # Image processing configuration. 50 | [imaging] 51 | resampleFilter = "CatmullRom" 52 | quality = 75 53 | anchor = "smart" 54 | 55 | # Language configuration 56 | 57 | [languages] 58 | [languages.en] 59 | languageName ="English" 60 | # Weight used for sorting. 61 | weight = 1 62 | [languages.en.params] 63 | title = "Dex" 64 | description = "Federate Identity Provider" 65 | 66 | [markup] 67 | [markup.goldmark] 68 | [markup.goldmark.parser.attribute] 69 | block = true 70 | [markup.goldmark.renderer] 71 | unsafe = true 72 | [markup.highlight] 73 | # See a complete list of available styles at https://xyproto.github.io/splash/docs/all.html 74 | style = "onedark" 75 | # Uncomment if you want your chosen highlight style used for code blocks without a specified language 76 | # guessSyntax = "true" 77 | 78 | # Everything below this are Site Params 79 | 80 | # Comment out if you don't want the "print entire section" link enabled. 81 | [outputs] 82 | section = ["HTML", "print", "RSS"] 83 | 84 | [caches] 85 | [caches.assets] 86 | dir = ":cacheDir/_gen" 87 | maxAge = -1 88 | [caches.getcsv] 89 | dir = ":cacheDir/:project" 90 | maxAge = "60s" 91 | [caches.getjson] 92 | dir = ":cacheDir/:project" 93 | maxAge = "60s" 94 | [caches.images] 95 | dir = ":cacheDir/_images" 96 | maxAge = -1 97 | [caches.modules] 98 | dir = ":cacheDir/modules" 99 | maxAge = -1 100 | 101 | [params] 102 | privacy_policy = "https://policies.google.com/privacy" 103 | 104 | # First one is picked as the Twitter card image if not set on page. 105 | # images = ["images/project-illustration.png"] 106 | 107 | # Menu title if your navbar has a versions selector to access old versions of your site. 108 | # This menu appears only if you have at least one [params.versions] set. 109 | version_menu = "Releases" 110 | 111 | # Flag used in the "version-banner" partial to decide whether to display a 112 | # banner on every page indicating that this is an archived version of the docs. 113 | # Set this flag to "true" if you want to display the banner. 114 | archived_version = false 115 | 116 | # The version number for the version of the docs represented in this doc set. 117 | # Used in the "version-banner" partial to display a version number for the 118 | # current doc set. 119 | version = "0.0" 120 | 121 | # A link to latest version of the docs. Used in the "version-banner" partial to 122 | # point people to the main doc site. 123 | url_latest_version = "https://dexidp.io" 124 | 125 | # Repository configuration (URLs for in-page links to opening issues and suggesting changes) 126 | github_repo = "https://github.com/dexidp/website" 127 | # An optional link to a related project repo. For example, the sibling repository where your product code lives. 128 | github_project_repo = "https://github.com/dexidp/dex" 129 | 130 | # Specify a value here if your content directory is not in your repo's root directory 131 | # github_subdir = "" 132 | 133 | # Enable Lunr.js offline search 134 | offlineSearch = true 135 | 136 | # Enable syntax highlighting and copy buttons on code blocks with Prism 137 | prism_syntax_highlighting = false 138 | 139 | # User interface configuration 140 | [params.ui] 141 | # Set to true to disable breadcrumb navigation. 142 | breadcrumb_disable = false 143 | # Set to false if you don't want to display a logo (/assets/icons/logo.svg) in the top navbar 144 | navbar_logo = true 145 | # Set to true if you don't want the top navbar to be translucent when over a `block/cover`, like on the homepage. 146 | navbar_translucent_over_cover_disable = false 147 | # Enable to show the side bar menu in its compact state. 148 | sidebar_menu_compact = true 149 | # Set to true to hide the sidebar search box (the top nav search box will still be displayed if search is enabled) 150 | sidebar_search_disable = true 151 | 152 | # Adds a H2 section titled "Feedback" to the bottom of each doc. The responses are sent to Google Analytics as events. 153 | # This feature depends on [services.googleAnalytics] and will be disabled if "services.googleAnalytics.id" is not set. 154 | # If you want this feature, but occasionally need to remove the "Feedback" section from a single page, 155 | # add "hide_feedback: true" to the page's front matter. 156 | [params.ui.feedback] 157 | enable = false 158 | # The responses that the user sees after clicking "yes" (the page was helpful) or "no" (the page was not helpful). 159 | yes = 'Glad to hear it! Please tell us how we can improve.' 160 | no = 'Sorry to hear that. Please tell us how we can improve.' 161 | 162 | # Adds a reading time to the top of each doc. 163 | # If you want this feature, but occasionally need to remove the Reading time from a single page, 164 | # add "hide_readingtime: true" to the page's front matter 165 | [params.ui.readingtime] 166 | enable = false 167 | 168 | [[params.social]] 169 | name = "GitHub" 170 | color = "#000000" 171 | url = "https://github.com/dexidp/dex" 172 | icon = "fab fa-github" 173 | 174 | [[params.social]] 175 | name = "Twitter" 176 | color = "#00aced" 177 | url = "https://twitter.com/dexidp" 178 | icon = "fab fa-twitter" 179 | 180 | [[params.social]] 181 | name = "Slack" 182 | color = "#00eded" 183 | url = "https://cloud-native.slack.com/archives/C01HF2G1R34" 184 | icon = "fab fa-slack" 185 | 186 | [[params.fonts]] 187 | name = "Fira Sans" 188 | sizes = [300, 400, 600, 700] 189 | type = "sans_serif" 190 | 191 | [[params.fonts]] 192 | name = "Fira Mono" 193 | sizes = [300, 400, 600, 700] 194 | type = "monospace" 195 | 196 | [[params.fonts]] 197 | name = "Fire Sans" 198 | sizes = [100, 200, 300, 400, 500, 600, 700] 199 | type = "heading_font" 200 | 201 | [params.links] 202 | # End user relevant links. These will show up on left side of footer and in the community page if you have one. 203 | [[params.links.user]] 204 | name = "User mailing list" 205 | url = "https://example.org/mail" 206 | icon = "fa fa-envelope" 207 | desc = "Discussion and help from your fellow users" 208 | [[params.links.user]] 209 | name ="Twitter" 210 | url = "https://example.org/twitter" 211 | icon = "fab fa-twitter" 212 | desc = "Follow us on Twitter to get the latest news!" 213 | [[params.links.user]] 214 | name = "Stack Overflow" 215 | url = "https://example.org/stack" 216 | icon = "fab fa-stack-overflow" 217 | desc = "Practical questions and curated answers" 218 | # Developer relevant links. These will show up on right side of footer and in the community page if you have one. 219 | [[params.links.developer]] 220 | name = "GitHub" 221 | url = "https://github.com/google/docsy" 222 | icon = "fab fa-github" 223 | desc = "Development takes place here!" 224 | [[params.links.developer]] 225 | name = "Slack" 226 | url = "https://example.org/slack" 227 | icon = "fab fa-slack" 228 | desc = "Chat with other project developers" 229 | [[params.links.developer]] 230 | name = "Developer mailing list" 231 | url = "https://example.org/mail" 232 | icon = "fa fa-envelope" 233 | desc = "Discuss development issues around the project" 234 | 235 | [module] 236 | replacements = "github.com/FortAwesome/Font-Awesome -> ., github.com/twbs/bootstrap -> ." 237 | [[module.imports]] 238 | path = "docsy" 239 | [[module.imports]] 240 | path = "github.com/twbs/bootstrap" 241 | disable = false 242 | -------------------------------------------------------------------------------- /content/docs/development/oidc-certification.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "OpenID Connect Provider Certification" 3 | description: "" 4 | date: 2020-09-30 5 | draft: false 6 | toc: true 7 | weight: 1100 8 | --- 9 | 10 | The OpenID Foundation provides a set of [conformance test profiles](https://openid.net/wordpress-content/uploads/2018/06/OpenID-Connect-Conformance-Profiles.pdf) that test both Relying Party (RP) 11 | and OpenID Provider (OP) OpenID Connect implementations. 12 | Upon submission of [results](https://openid.net/certification/submission/) and an affirmative response, 13 | the affirmed OP will be listed as a [certified OP](https://openid.net/developers/certified/) on the OpenID Connect website 14 | and allowed to use the [certification mark](https://openid.net/certification/mark/) according to the certification [terms and conditions](https://openid.net/wordpress-content/uploads/2015/03/OpenID-Certification-Terms-and-Conditions.pdf), section 3(d). 15 | 16 | Further details about the certification are available on the [OpenID Connect website](https://openid.net/certification/instructions/). 17 | 18 | ## Basic OpenID Provider profile 19 | 20 | Dex is an OP that strives to implement the [mandatory set](https://openid.net/specs/openid-connect-core-1_0.html#ServerMTI) of OpenID Connect features, 21 | and can be tested against the Basic OpenID Provider profile ([profile outline](https://openid.net/wordpress-content/uploads/2018/06/OpenID-Connect-Conformance-Profiles.pdf), section 2.1.1). 22 | These tests ensure that all features required by a [basic client](https://openid.net/specs/openid-connect-basic-1_0.html) work as expected. 23 | 24 | Unfortunately, Dex currently does not fully comply with the Basic profile at the moment. 25 | 26 | The progress for getting Dex certified can be tracked here: https://github.com/orgs/dexidp/projects/3/views/1 27 | 28 | ### Configuring Dex 29 | 30 | The Basic OP test suite doesn't require extensive configuration from Dex. 31 | The suite needs the following: 32 | 33 | - A public issuer URL 34 | - At least two separate clients (with redirect URIs pointing to `https://www.certification.openid.net/test/a/YOUR_ALIAS/callback`). 35 | 36 | `YOUR_ALIAS` is an arbitrary string that MUST be unique to avoid interference with other test runs. 37 | 38 | The easiest way to run a public Dex instance is running one locally and exposing it using a [tunnel](https://github.com/anderspitman/awesome-tunneling). 39 | 40 | The following instructions use [tunnelto.dev](https://tunnelto.dev/). 41 | 42 | Here is a minimal configuration example for running Dex: 43 | 44 | ```yaml 45 | issuer: https://dex.tunnelto.dev/dex 46 | 47 | storage: 48 | type: memory 49 | 50 | web: 51 | http: 0.0.0.0:5556 52 | 53 | oauth2: 54 | # Automate some clicking 55 | # Note: this might actually make some tests pass that otherwise wouldn't. 56 | skipApprovalScreen: true 57 | 58 | connectors: 59 | # Note: this might actually make some tests pass that otherwise wouldn't. 60 | - type: mockCallback 61 | id: mock 62 | name: Example 63 | 64 | # Basic OP test suite requires two clients. 65 | staticClients: 66 | - id: first_client 67 | secret: 89d6205220381728e85c4cf5 68 | redirectURIs: 69 | - https://www.certification.openid.net/test/a/dex/callback 70 | name: First client 71 | 72 | - id: second_client 73 | secret: 51c612288018fd384b05d6ad 74 | redirectURIs: 75 | - https://www.certification.openid.net/test/a/dex/callback 76 | name: Second client 77 | ``` 78 | 79 | Save it in a file (eg. `config.yaml`) then launch Dex: 80 | 81 | ```shell 82 | dex serve config.yaml 83 | ``` 84 | 85 | Then launch the tunnel: 86 | 87 | ```shell 88 | tunnelto --subdomain dex --port 5556 89 | ``` 90 | 91 | You can verify Dex running by checking the discovery endpoint: 92 | 93 | ```shell 94 | curl https://dex.tunnelto.dev/dex/.well-known/openid-configuration 95 | ``` 96 | 97 | ### Running tests 98 | 99 | 1. Open https://www.certification.openid.net/ in your browser 100 | 1. Login with your Google or GitLab account 101 | 1. Click _Create a new test plan_ 102 | 1. Select _OpenID Connect Core: Basic Certification Profile Authorization server test_ as the test plan 103 | 1. _Server metadata location_ should be **discovery** 104 | 1. _Client registration type_ should be **static_client** 105 | 1. Choose an alias (that you used in the redirect URIs above) 106 | 1. Enter the discovery URL 107 | 1. Enter the first client details in the _Client_ and _Second client_ sections 108 | 1. Enter the second client details in the _Client for client_secret_post_ section 109 | 1. Hit _Create test plan_ 110 | 1. Run through each test case, following all instructions given by individual cases. 111 | * In order to pass certain cases, screenshots of OP responses might be required. 112 | 113 | ### Last results 114 | 115 | Dex does not fully pass the Basic profile test suite yet. The following table contains the current state of test results. 116 | 117 | | Test Name | Status | Result | 118 | |------------------------------------------------------------------------------|-------------|---------| 119 | | oidcc-server | FINISHED | PASSED | 120 | | oidcc-response-type-missing | FINISHED | PASSED | 121 | | oidcc-userinfo-get | FINISHED | PASSED | 122 | | oidcc-userinfo-post-header | FINISHED | PASSED | 123 | | oidcc-userinfo-post-body | FINISHED | WARNING | 124 | | oidcc-ensure-request-without-nonce-succeeds-for-code-flow | FINISHED | PASSED | 125 | | oidcc-scope-profile | FINISHED | WARNING | 126 | | oidcc-scope-email | FINISHED | WARNING | 127 | | oidcc-scope-address | FINISHED | SKIPPED | 128 | | oidcc-scope-phone | FINISHED | SKIPPED | 129 | | oidcc-scope-all | FINISHED | SKIPPED | 130 | | oidcc-ensure-other-scope-order-succeeds | FINISHED | WARNING | 131 | | oidcc-display-page | FINISHED | PASSED | 132 | | oidcc-display-popup | FINISHED | PASSED | 133 | | oidcc-prompt-login | INTERRUPTED | UNKNOWN | 134 | | oidcc-prompt-none-not-logged-in | FINISHED | FAILED | 135 | | oidcc-prompt-none-logged-in | FINISHED | PASSED | 136 | | oidcc-max-age-1 | INTERRUPTED | FAILED | 137 | | oidcc-max-age-10000 | FINISHED | FAILED | 138 | | oidcc-ensure-request-with-unknown-parameter-succeeds | FINISHED | PASSED | 139 | | oidcc-id-token-hint | FINISHED | PASSED | 140 | | oidcc-login-hint | FINISHED | PASSED | 141 | | oidcc-ui-locales | FINISHED | PASSED | 142 | | oidcc-claims-locales | FINISHED | PASSED | 143 | | oidcc-ensure-request-with-acr-values-succeeds | FINISHED | WARNING | 144 | | oidcc-codereuse | FINISHED | PASSED | 145 | | oidcc-codereuse-30seconds | FINISHED | WARNING | 146 | | oidcc-ensure-registered-redirect-uri | INTERRUPTED | REVIEW | 147 | | oidcc-server-client-secret-post | FINISHED | PASSED | 148 | | oidcc-unsigned-request-object-supported-correctly-or-rejected-as-unsupported | INTERRUPTED | UNKNOWN | 149 | | oidcc-claims-essential | FINISHED | WARNING | 150 | | oidcc-ensure-request-object-with-redirect-uri | INTERRUPTED | UNKNOWN | 151 | | oidcc-refresh-token | INTERRUPTED | FAILED | 152 | | oidcc-ensure-request-with-valid-pkce-succeeds | FINISHED | PASSED | 153 | 154 | > TODO: find a better place for test results. 155 | -------------------------------------------------------------------------------- /content/docs/connectors/microsoft.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Authentication Through Microsoft" 3 | linkTitle: "Microsoft" 4 | description: "" 5 | date: 2020-09-30 6 | draft: false 7 | toc: true 8 | weight: 2080 9 | --- 10 | 11 | ## Overview 12 | 13 | One of the login options for dex uses the Microsoft OAuth2 flow to identify the 14 | end user through their Microsoft account. 15 | 16 | When a client redeems a refresh token through dex, dex will re-query Microsoft 17 | to update user information in the ID Token. To do this, __dex stores a readonly 18 | Microsoft access and refresh tokens in its backing datastore.__ Users that 19 | reject dex's access through Microsoft will also revoke all dex clients which 20 | authenticated them through Microsoft. 21 | 22 | ### Caveats 23 | 24 | `groups` claim in dex is only supported when `tenant` is specified in Microsoft 25 | connector config. Furthermore, `tenant` must also be configured to either 26 | `` or `` (see [Configuration](#configuration)). In 27 | order for dex to be able to list groups on behalf of logged in user, an 28 | explicit organization administrator consent is required. To obtain the 29 | consent do the following: 30 | 31 | - when registering dex application on https://apps.dev.microsoft.com add 32 | an explicit `Directory.Read.All` permission to the list of __Delegated 33 | Permissions__ 34 | - open the following link in your browser and log in under organization 35 | administrator account: 36 | 37 | `https://login.microsoftonline.com//adminconsent?client_id=` 38 | 39 | ## Configuration 40 | 41 | Register a new application on https://apps.dev.microsoft.com via `Add an app` 42 | ensuring the callback URL is `(dex issuer)/callback`. For example if dex 43 | is listening at the non-root path `https://auth.example.com/dex` the callback 44 | would be `https://auth.example.com/dex/callback`. 45 | 46 | The following is an example of a configuration for `examples/config-dev.yaml`: 47 | 48 | ```yaml 49 | connectors: 50 | - type: microsoft 51 | # Required field for connector id. 52 | id: microsoft 53 | # Required field for connector name. 54 | name: Microsoft 55 | config: 56 | # Credentials can be string literals or pulled from the environment. 57 | clientID: $MICROSOFT_APPLICATION_ID 58 | clientSecret: $MICROSOFT_CLIENT_SECRET 59 | redirectURI: http://127.0.0.1:5556/dex/callback 60 | ``` 61 | 62 | `tenant` configuration parameter controls what kinds of accounts may be 63 | authenticated in dex. By default, all types of Microsoft accounts (consumers 64 | and organizations) can authenticate in dex via Microsoft. To change this, set 65 | the `tenant` parameter to one of the following: 66 | 67 | - `common`- both personal and business/school accounts can authenticate in dex 68 | via Microsoft (default) 69 | - `consumers` - only personal accounts can authenticate in dex 70 | - `organizations` - only business/school accounts can authenticate in dex 71 | - `` or `` - only accounts belonging to specific 72 | tenant identified by either `` or `` can 73 | authenticate in dex 74 | 75 | For example, the following snippet configures dex to only allow business/school 76 | accounts: 77 | 78 | ```yaml 79 | connectors: 80 | - type: microsoft 81 | # Required field for connector id. 82 | id: microsoft 83 | # Required field for connector name. 84 | name: Microsoft 85 | config: 86 | # Credentials can be string literals or pulled from the environment. 87 | clientID: $MICROSOFT_APPLICATION_ID 88 | clientSecret: $MICROSOFT_CLIENT_SECRET 89 | redirectURI: http://127.0.0.1:5556/dex/callback 90 | tenant: organizations 91 | ``` 92 | 93 | `domainHint` configuration parameter allows for a more streamlined login 94 | experience when the email domain is common to all users of the connector. 95 | By default, users with multiple Microsoft sessions will be prompted to choose 96 | which account they want to use for login. When `domainHint` is configured, 97 | Microsoft will select the session with matching email without the interactive 98 | prompt. 99 | 100 | For example: user John Doe has 2 active Microsoft sessions: 101 | 102 | - John.Doe@live.com (consumer) 103 | - John.Doe@example.com (organization) 104 | 105 | If Example Organization configures the `domainHint` parameter with its 106 | organization's email suffix, John will not be prompted to select an account 107 | from the active sessions. Instead, the matching organization session is 108 | selected automatically. 109 | 110 | `scopes` configuration parameter controls what the initial scope(s) of the identity 111 | token that dex requests from Microsoft. To change this initial set, configure 112 | the `scopes` parameter to be a list of one or more valid scopes (as defined in 113 | [Microsoft Documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent)). 114 | 115 | The default scope (if one is not specified in the connector's configuration) is 116 | `user.read`. 117 | 118 | The scope list requested may also be appended by specifying [groups](#groups) or 119 | requesting a new token through the use of a refresh token. 120 | 121 | For example, the following snippet configures dex to request an OpenID token 122 | with only getting the email address associated with the account and nothing else: 123 | 124 | ```yaml 125 | connectors: 126 | - type: microsoft 127 | # Required field for connector id. 128 | id: microsoft 129 | # Required field for connector name. 130 | name: Microsoft 131 | config: 132 | # Credentials can be string literals or pulled from the environment. 133 | clientID: $MICROSOFT_APPLICATION_ID 134 | clientSecret: $MICROSOFT_CLIENT_SECRET 135 | redirectURI: http://127.0.0.1:5556/dex/callback 136 | tenant: example.onmicrosoft.com 137 | domainHint: example.com 138 | scopes: 139 | - openid 140 | - email 141 | ``` 142 | 143 | ### Groups 144 | 145 | When the `groups` claim is present in a request to dex __and__ `tenant` is 146 | configured, dex will query Microsoft API to obtain a list of groups the user is 147 | a member of. `onlySecurityGroups` configuration option restricts the list to 148 | include only security groups. By default all groups (security, Office 365, 149 | mailing lists) are included. 150 | 151 | Please note that `tenant` must be configured to either `` or 152 | `` for this to work. For more details on `tenant` configuration, 153 | see [Configuration](#configuration). 154 | 155 | By default, dex resolve groups ids to groups names, to keep groups ids, you can 156 | specify the configuration option `groupNameFormat: id`. 157 | 158 | It is possible to require a user to be a member of a particular group in order 159 | to be successfully authenticated in dex. For example, with the following 160 | configuration file only the users who are members of at least one of the listed 161 | groups will be able to successfully authenticate in dex: 162 | 163 | ```yaml 164 | connectors: 165 | - type: microsoft 166 | # Required field for connector id. 167 | id: microsoft 168 | # Required field for connector name. 169 | name: Microsoft 170 | config: 171 | # Credentials can be string literals or pulled from the environment. 172 | clientID: $MICROSOFT_APPLICATION_ID 173 | clientSecret: $MICROSOFT_CLIENT_SECRET 174 | redirectURI: http://127.0.0.1:5556/dex/callback 175 | tenant: myorg.onmicrosoft.com 176 | groups: 177 | - developers 178 | - devops 179 | ``` 180 | 181 | Also, `useGroupsAsWhitelist` configuration option, can restrict the groups 182 | claims to include only the user's groups that are in the configured `groups`. 183 | 184 | You can use the emailToLowercase (boolean) configuration option to streamline 185 | UPNs (user email) from Active Directory before putting them into an id token. 186 | Without this option, it can be tough to match the email claim because a client 187 | application doesn't know whether an email address has been added with 188 | capital- or lowercase letters. 189 | For example, it is hard to bind Roles in Kubernetes using email as a user name 190 | (--oidc-username-claim=email flag) because user names are case sensitive. 191 | 192 | ```yaml 193 | connectors: 194 | - type: microsoft 195 | # Required field for connector id. 196 | id: microsoft 197 | # Required field for connector name. 198 | name: Microsoft 199 | config: 200 | # Credentials can be string literals or pulled from the environment. 201 | clientID: $MICROSOFT_APPLICATION_ID 202 | clientSecret: $MICROSOFT_CLIENT_SECRET 203 | redirectURI: http://127.0.0.1:5556/dex/callback 204 | tenant: myorg.onmicrosoft.com 205 | groups: 206 | - developers 207 | - devops 208 | # All relevant E-Mail Addresses delivered by AD will transformed to 209 | # lowercase if config is TRUE 210 | emailToLowercase: true 211 | ``` --------------------------------------------------------------------------------