From f7cb1b16f81d046099ad794683ba73d26d974464 Mon Sep 17 00:00:00 2001 From: dimw Date: Mon, 30 Mar 2026 13:49:03 +0200 Subject: [PATCH 1/4] feat: add support for authenticated-emails option #3391 Signed-off-by: dimw Signed-off-by: dimw --- main.go | 2 +- pkg/apis/options/options.go | 2 + pkg/validation/options.go | 4 +- validator.go | 19 +++++- validator_test.go | 128 ++++++++++++++++++++++++++++++++++-- 5 files changed, 145 insertions(+), 10 deletions(-) diff --git a/main.go b/main.go index ba970679..c70ee957 100644 --- a/main.go +++ b/main.go @@ -67,7 +67,7 @@ func main() { logger.Fatalf("%s", err) } - validator := NewValidator(opts.EmailDomains, opts.AuthenticatedEmailsFile) + validator := NewValidator(opts.EmailDomains, opts.AuthenticatedEmailsFile, opts.AuthenticatedEmails) oauthproxy, err := NewOAuthProxy(opts, validator) if err != nil { logger.Fatalf("ERROR: Failed to initialise OAuth2 Proxy: %v", err) diff --git a/pkg/apis/options/options.go b/pkg/apis/options/options.go index b57d5aed..a6fa3818 100644 --- a/pkg/apis/options/options.go +++ b/pkg/apis/options/options.go @@ -30,6 +30,7 @@ type Options struct { RelativeRedirectURL bool `flag:"relative-redirect-url" cfg:"relative_redirect_url"` AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file"` + AuthenticatedEmails []string `flag:"authenticated-email" cfg:"authenticated_emails"` EmailDomains []string `flag:"email-domain" cfg:"email_domains"` WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains"` HtpasswdFile string `flag:"htpasswd-file" cfg:"htpasswd_file"` @@ -139,6 +140,7 @@ func NewFlagSet() *pflag.FlagSet { flagSet.StringSlice("email-domain", []string{}, "authenticate emails with the specified domain (may be given multiple times). Use * to authenticate any email") flagSet.StringSlice("whitelist-domain", []string{}, "allowed domains for redirection after authentication. Prefix domain with a . or a *. to allow subdomains (eg .example.com, *.example.com)") flagSet.String("authenticated-emails-file", "", "authenticate against emails via file (one per line)") + flagSet.StringSlice("authenticated-email", []string{}, "authenticate users with these email addresses (may be given multiple times)") flagSet.String("htpasswd-file", "", "additionally authenticate against a htpasswd file. Entries must be created with \"htpasswd -B\" for bcrypt encryption") flagSet.StringSlice("htpasswd-user-group", []string{}, "the groups to be set on sessions for htpasswd users (may be given multiple times)") flagSet.String("proxy-prefix", "/oauth2", "the url root path that this proxy should be nested under (e.g. //sign_in)") diff --git a/pkg/validation/options.go b/pkg/validation/options.go index 13ce2e0b..426ee282 100644 --- a/pkg/validation/options.go +++ b/pkg/validation/options.go @@ -47,8 +47,8 @@ func Validate(o *options.Options) error { } } - if o.AuthenticatedEmailsFile == "" && len(o.EmailDomains) == 0 && o.HtpasswdFile == "" { - msgs = append(msgs, "missing setting for email validation: email-domain or authenticated-emails-file required."+ + if o.AuthenticatedEmailsFile == "" && len(o.EmailDomains) == 0 && len(o.AuthenticatedEmails) == 0 && o.HtpasswdFile == "" { + msgs = append(msgs, "missing setting for email validation: email-domain, authenticated-emails-file, or authenticated-emails required."+ "\n use email-domain=* to authorize all email addresses") } diff --git a/validator.go b/validator.go index 587ef857..7ce1d34e 100644 --- a/validator.go +++ b/validator.go @@ -73,7 +73,7 @@ func (um *UserMap) LoadAuthenticatedEmailsFile() { atomic.StorePointer(&um.m, unsafe.Pointer(&updated)) // #nosec G103 } -func newValidatorImpl(domains []string, usersFile string, +func newValidatorImpl(domains []string, usersFile string, inlineEmails []string, done <-chan bool, onUpdate func()) func(string) bool { validUsers := NewUserMap(usersFile, done, onUpdate) @@ -86,6 +86,16 @@ func newValidatorImpl(domains []string, usersFile string, domains[i] = strings.ToLower(domain) } + // Create a map for inline emails for fast lookup + inlineEmailsMap := make(map[string]bool) + for _, email := range inlineEmails { + if email != "" { + // Actually, the local part of the email (before @) is case-sensitive, + // but we stick to the pattern already used for files. + inlineEmailsMap[strings.ToLower(strings.TrimSpace(email))] = true + } + } + validator := func(email string) (valid bool) { if email == "" { return @@ -95,6 +105,9 @@ func newValidatorImpl(domains []string, usersFile string, if !valid { valid = validUsers.IsValid(email) } + if !valid { + valid = inlineEmailsMap[email] + } if allowAll { valid = true } @@ -104,8 +117,8 @@ func newValidatorImpl(domains []string, usersFile string, } // NewValidator constructs a function to validate email addresses -func NewValidator(domains []string, usersFile string) func(string) bool { - return newValidatorImpl(domains, usersFile, nil, func() {}) +func NewValidator(domains []string, usersFile string, inlineEmails []string) func(string) bool { + return newValidatorImpl(domains, usersFile, inlineEmails, nil, func() {}) } // isEmailValidWithDomains checks if the authenticated email is validated against the provided domain diff --git a/validator_test.go b/validator_test.go index 976c0d7d..bdfb55a5 100644 --- a/validator_test.go +++ b/validator_test.go @@ -34,9 +34,9 @@ func (vt *ValidatorTest) TearDown() { os.Remove(vt.authEmailFileName) } -func (vt *ValidatorTest) NewValidator(domains []string, +func (vt *ValidatorTest) NewValidator(domains []string, inlineEmails []string, updated chan<- bool) func(string) bool { - return newValidatorImpl(domains, vt.authEmailFileName, + return newValidatorImpl(domains, vt.authEmailFileName, inlineEmails, vt.done, func() { if vt.updateSeen == false { updated <- true @@ -112,7 +112,7 @@ func TestValidatorOverwriteEmailListDirectly(t *testing.T) { "plugh@example.com", }) updated := make(chan bool) - validator := vt.NewValidator([]string(nil), updated) + validator := vt.NewValidator([]string(nil), []string(nil), updated) for _, tc := range testCasesPreUpdate { t.Run(tc.name, func(t *testing.T) { @@ -141,6 +141,7 @@ func TestValidatorCases(t *testing.T) { testCases := []struct { name string allowedEmails []string + inlineEmails []string allowedDomains []string email string expectedAuthZ bool @@ -148,6 +149,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailNotInCorrect1stSubDomainsNotInEmails", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "foo.bar@example0.com", expectedAuthZ: false, @@ -155,6 +157,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailNotInCorrect1stSubDomainsNotInEmailsWildcard", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"*.example0.com", "*.example1.com"}, email: "foo.bar@example0.com", expectedAuthZ: false, @@ -162,6 +165,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInFirstDomain", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "foo@bar.example0.com", expectedAuthZ: true, @@ -169,6 +173,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInFirstDomainWildcard", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"*.example0.com", "*.example1.com"}, email: "foo@bar.example0.com", expectedAuthZ: true, @@ -176,6 +181,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailNotInCorrect2ndSubDomainsNotInEmails", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "baz.quux@example1.com", expectedAuthZ: false, @@ -183,6 +189,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInSecondDomain", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "baz@quux.example1.com", expectedAuthZ: true, @@ -190,6 +197,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInSecondDomainWildcard", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"*.example0.com", "*.example1.com"}, email: "baz@quux.example1.com", expectedAuthZ: true, @@ -197,6 +205,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInFirstEmailList", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "xyzzy@example.com", expectedAuthZ: true, @@ -204,6 +213,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInFirstEmailListWildcard", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"*.example0.com", "*.example1.com"}, email: "xyzzy@example.com", expectedAuthZ: true, @@ -211,6 +221,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailNotInDomainsNotInEmails", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "xyzzy.plugh@example.com", expectedAuthZ: false, @@ -218,6 +229,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInLastEmailList", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{".example0.com", ".example1.com"}, email: "plugh@example.com", expectedAuthZ: true, @@ -225,6 +237,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailIn1stSubdomain", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{"us.example.com", "de.example.com", "example.com"}, email: "xyzzy@us.example.com", expectedAuthZ: true, @@ -232,6 +245,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailIn2ndSubdomain", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{"us.example.com", "de.example.com", "example.com"}, email: "xyzzy@de.example.com", expectedAuthZ: true, @@ -239,6 +253,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailNotInAnySubdomain", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{"us.example.com", "de.example.com", "example.com"}, email: "global@au.example.com", expectedAuthZ: false, @@ -246,6 +261,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailInLastSubdomain", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{"us.example.com", "de.example.com", "example.com"}, email: "xyzzy@example.com", expectedAuthZ: true, @@ -253,6 +269,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmailDomainNotCompletelyMatch", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{".example.com", ".example1.com"}, email: "something@fooexample.com", expectedAuthZ: false, @@ -260,6 +277,7 @@ func TestValidatorCases(t *testing.T) { { name: "HackerExtraDomainPrefix1", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{".mycompany.com"}, email: "something@evilhackmycompany.com", expectedAuthZ: false, @@ -267,6 +285,7 @@ func TestValidatorCases(t *testing.T) { { name: "HackerExtraDomainPrefix2", allowedEmails: nil, + inlineEmails: []string{}, allowedDomains: []string{".mycompany.com"}, email: "something@ext.evilhackmycompany.com", expectedAuthZ: false, @@ -274,6 +293,7 @@ func TestValidatorCases(t *testing.T) { { name: "EmptyDomainAndEmailList", allowedEmails: []string(nil), + inlineEmails: []string{}, allowedDomains: []string(nil), email: "foo.bar@example.com", expectedAuthZ: false, @@ -282,6 +302,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailMatchWithAllowedEmails", email: "foo.bar@example.com", allowedEmails: []string{"foo.bar@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"example.com"}, expectedAuthZ: true, }, @@ -289,6 +310,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailFromSameDomainButNotInList", email: "baz.quux@example.com", allowedEmails: []string{"foo.bar@example.com"}, + inlineEmails: []string{}, allowedDomains: []string(nil), expectedAuthZ: false, }, @@ -296,6 +318,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailMatchOnDomain", email: "foo.bar@example.com", allowedEmails: []string(nil), + inlineEmails: []string{}, allowedDomains: []string{"example.com"}, expectedAuthZ: true, }, @@ -303,6 +326,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailMatchOnDomain2", email: "baz.quux@example.com", allowedEmails: []string(nil), + inlineEmails: []string{}, allowedDomains: []string{"example.com"}, expectedAuthZ: true, }, @@ -310,6 +334,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailFromFirstDomainShouldValidate", email: "foo.bar@example0.com", allowedEmails: []string{"Foo.Bar@Example.Com"}, + inlineEmails: []string{}, allowedDomains: []string{"example0.com", "example1.com"}, expectedAuthZ: true, }, @@ -317,6 +342,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailFromSecondDomainShouldValidate", email: "baz.quux@example1.com", allowedEmails: []string{"Foo.Bar@Example.Com"}, + inlineEmails: []string{}, allowedDomains: []string{"example0.com", "example1.com"}, expectedAuthZ: true, }, @@ -324,6 +350,7 @@ func TestValidatorCases(t *testing.T) { name: "FirstEmailInListShouldValidate", email: "xyzzy@example.com", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"example0.com", "example1.com"}, expectedAuthZ: true, }, @@ -331,6 +358,7 @@ func TestValidatorCases(t *testing.T) { name: "SecondEmailInListShouldValidate", email: "plugh@example.com", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"example0.com", "example1.com"}, expectedAuthZ: true, }, @@ -338,6 +366,7 @@ func TestValidatorCases(t *testing.T) { name: "EmailNotInListThatMatchesNoDomains ", email: "xyzzy.plugh@example.com", allowedEmails: []string{"xyzzy@example.com", "plugh@example.com"}, + inlineEmails: []string{}, allowedDomains: []string{"example0.com", "example1.com"}, expectedAuthZ: false, }, @@ -345,6 +374,7 @@ func TestValidatorCases(t *testing.T) { name: "LoadedEmailAddressesAreNotLowerCased", email: "foo.bar@example.com", allowedEmails: []string{"Foo.Bar@Example.Com"}, + inlineEmails: []string{}, allowedDomains: []string{"Frobozz.Com"}, expectedAuthZ: true, }, @@ -352,6 +382,7 @@ func TestValidatorCases(t *testing.T) { name: "ValidatedEmailAddressesAreNotLowerCased", email: "Foo.Bar@Example.Com", allowedEmails: []string{"Foo.Bar@Example.Com"}, + inlineEmails: []string{}, allowedDomains: []string{"Frobozz.Com"}, expectedAuthZ: true, }, @@ -359,6 +390,7 @@ func TestValidatorCases(t *testing.T) { name: "LoadedDomainsAreNotLowerCased", email: "foo.bar@frobozz.com", allowedEmails: []string{"Foo.Bar@Example.Com"}, + inlineEmails: []string{}, allowedDomains: []string{"Frobozz.Com"}, expectedAuthZ: true, }, @@ -366,6 +398,7 @@ func TestValidatorCases(t *testing.T) { name: "ValidatedDomainsAreNotLowerCased", email: "foo.bar@Frobozz.Com", allowedEmails: []string{"Foo.Bar@Example.Com"}, + inlineEmails: []string{}, allowedDomains: []string{"Frobozz.Com"}, expectedAuthZ: true, }, @@ -373,6 +406,7 @@ func TestValidatorCases(t *testing.T) { name: "IgnoreSpacesInAuthEmails", email: "foo.bar@example.com", allowedEmails: []string{" foo.bar@example.com "}, + inlineEmails: []string{}, allowedDomains: []string(nil), expectedAuthZ: true, }, @@ -380,6 +414,7 @@ func TestValidatorCases(t *testing.T) { name: "IgnorePrefixSpacesInAuthEmails", email: "foo.bar@example.com", allowedEmails: []string{" foo.bar@example.com"}, + inlineEmails: []string{}, allowedDomains: []string(nil), expectedAuthZ: true, }, @@ -387,6 +422,7 @@ func TestValidatorCases(t *testing.T) { name: "CheckForEqualityNotSuffix", email: "foo@evilcompany.com", allowedEmails: []string(nil), + inlineEmails: []string{}, allowedDomains: []string{".company.com"}, expectedAuthZ: false, }, @@ -394,6 +430,7 @@ func TestValidatorCases(t *testing.T) { name: "CheckForEqualityNotSuffix2", email: "foo@evilcompany.com", allowedEmails: []string(nil), + inlineEmails: []string{}, allowedDomains: []string{"company.com"}, expectedAuthZ: false, }, @@ -401,9 +438,92 @@ func TestValidatorCases(t *testing.T) { name: "CheckForEqualityNotSuffixWildcard", email: "foo@evilcompany.com", allowedEmails: []string(nil), + inlineEmails: []string{}, allowedDomains: []string{"*.company.com"}, expectedAuthZ: false, }, + + // Inline email test cases + { + name: "InlineEmailOnly", + allowedEmails: []string{}, + inlineEmails: []string{"user1@example.com", "user2@example.com"}, + allowedDomains: []string{}, + email: "user1@example.com", + expectedAuthZ: true, + }, + { + name: "InlineEmailNotFound", + allowedEmails: []string{}, + inlineEmails: []string{"user1@example.com", "user2@example.com"}, + allowedDomains: []string{}, + email: "user3@example.com", + expectedAuthZ: false, + }, + { + name: "CombinedFileAndInlineEmails", + allowedEmails: []string{"fileuser@example.com"}, + inlineEmails: []string{"inlineuser@example.com"}, + allowedDomains: []string{}, + email: "inlineuser@example.com", + expectedAuthZ: true, + }, + { + name: "CombinedFileAndInlineEmailsFileMatch", + allowedEmails: []string{"fileuser@example.com"}, + inlineEmails: []string{"inlineuser@example.com"}, + allowedDomains: []string{}, + email: "fileuser@example.com", + expectedAuthZ: true, + }, + { + name: "CombinedFileAndInlineEmailsNoMatch", + allowedEmails: []string{"fileuser@example.com"}, + inlineEmails: []string{"inlineuser@example.com"}, + allowedDomains: []string{}, + email: "other@example.com", + expectedAuthZ: false, + }, + { + name: "InlineEmailsWithDomains", + allowedEmails: []string{}, + inlineEmails: []string{"specific@example.com"}, + allowedDomains: []string{"domain.com"}, + email: "any@domain.com", + expectedAuthZ: true, + }, + { + name: "InlineEmailsWithDomainsSpecificMatch", + allowedEmails: []string{}, + inlineEmails: []string{"specific@example.com"}, + allowedDomains: []string{"domain.com"}, + email: "specific@example.com", + expectedAuthZ: true, + }, + { + name: "InlineEmailsCaseInsensitive", + allowedEmails: []string{}, + inlineEmails: []string{"User1@Example.Com"}, + allowedDomains: []string{}, + email: "user1@example.com", + expectedAuthZ: true, + }, + { + name: "InlineEmailsWithWhitespace", + allowedEmails: []string{}, + inlineEmails: []string{" user1@example.com ", "user2@example.com"}, + allowedDomains: []string{}, + email: "user1@example.com", + expectedAuthZ: true, + }, + { + name: "EmptyInlineEmail", + allowedEmails: []string{}, + inlineEmails: []string{"user1@example.com", "", "user2@example.com"}, + allowedDomains: []string{}, + email: "user2@example.com", + expectedAuthZ: true, + }, } for _, tc := range testCases { @@ -413,7 +533,7 @@ func TestValidatorCases(t *testing.T) { g := NewWithT(t) vt.WriteEmails(t, tc.allowedEmails) - validator := vt.NewValidator(tc.allowedDomains, nil) + validator := vt.NewValidator(tc.allowedDomains, tc.inlineEmails, nil) authorized := validator(tc.email) g.Expect(authorized).To(Equal(tc.expectedAuthZ)) }) From d3c5e7ef4099f7a8f0b71ce8bf42867f0b37fd2a Mon Sep 17 00:00:00 2001 From: dimw Date: Mon, 30 Mar 2026 18:24:24 +0200 Subject: [PATCH 2/4] doc: update changelog for authenticated-email option feature Signed-off-by: dimw Signed-off-by: dimw --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc4c2379..8d88e583 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ## Changes since v7.15.1 +- [#3394](https://github.com/oauth2-proxy/oauth2-proxy/pull/3394) feat: add support for --authenticated-email option (@dimw) + # V7.15.1 ## Release Highlights From df08c8d1f3a46a59a81cdc37d000ae0537561d25 Mon Sep 17 00:00:00 2001 From: dimw Date: Mon, 30 Mar 2026 19:05:33 +0200 Subject: [PATCH 3/4] fix: correct error message for missing email validation settings Signed-off-by: dimw --- pkg/validation/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/validation/options.go b/pkg/validation/options.go index 426ee282..79033d01 100644 --- a/pkg/validation/options.go +++ b/pkg/validation/options.go @@ -48,7 +48,7 @@ func Validate(o *options.Options) error { } if o.AuthenticatedEmailsFile == "" && len(o.EmailDomains) == 0 && len(o.AuthenticatedEmails) == 0 && o.HtpasswdFile == "" { - msgs = append(msgs, "missing setting for email validation: email-domain, authenticated-emails-file, or authenticated-emails required."+ + msgs = append(msgs, "missing setting for email validation: email-domain, authenticated-emails-file, or authenticated-email required."+ "\n use email-domain=* to authorize all email addresses") } From 17ac37bfbd5f755d3f65010dcabdbb7718245e87 Mon Sep 17 00:00:00 2001 From: dimw Date: Mon, 30 Mar 2026 19:17:13 +0200 Subject: [PATCH 4/4] doc: update email authentication instructions for individual addresses Signed-off-by: dimw --- docs/docs/configuration/providers/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/docs/configuration/providers/index.md b/docs/docs/configuration/providers/index.md index 6f333e5a..f8ba7ef8 100644 --- a/docs/docs/configuration/providers/index.md +++ b/docs/docs/configuration/providers/index.md @@ -35,8 +35,9 @@ OpenID Connect provider. ## Email Authentication -To authorize a specific email-domain use `--email-domain=yourcompany.com`. To authorize individual email addresses use -`--authenticated-emails-file=/path/to/file` with one email per line. To authorize all email addresses use `--email-domain=*`. +To authorize a specific email-domain use `--email-domain=yourcompany.com`. To authorize individual email addresses use +`--authenticated-email=user@example.com`, or `--authenticated-emails-file=/path/to/file` with one email per line. +To authorize all email addresses use `--email-domain=*`. ## Adding a new Provider