diff --git a/docs/docs/guides/integrate/identity-providers/azure-ad.mdx b/docs/docs/guides/integrate/identity-providers/azure-ad.mdx
index 0df515284..a681d58cf 100644
--- a/docs/docs/guides/integrate/identity-providers/azure-ad.mdx
+++ b/docs/docs/guides/integrate/identity-providers/azure-ad.mdx
@@ -77,7 +77,7 @@ You only have to add the client ID and secret, you have created in the step befo
You can configure the following settings if you like, a useful default will be filled if you don't change anything:
**Scopes**: The scopes define which scopes will be sent to the provider, `openid`, `profile`, and `email` are prefilled.
-This information will be taken to create/update the user within ZITADEL. Make sure to also add `User.Read`
+This information will be taken to create/update the user within ZITADEL. Make sure to also add `User.Read`. ZITADEL ensures that at least `openid` and `User.Read` scopes are always sent.
**Email Verified**: Azure AD doesn't send the email verified claim in the users token, if you don't enable this setting.
The user is then created with an unverified email, which results in an email verification message.
diff --git a/docs/docs/guides/integrate/identity-providers/github.mdx b/docs/docs/guides/integrate/identity-providers/github.mdx
index 749bb915b..5ab11dd55 100644
--- a/docs/docs/guides/integrate/identity-providers/github.mdx
+++ b/docs/docs/guides/integrate/identity-providers/github.mdx
@@ -61,7 +61,7 @@ The GitHub provider templates have everything you need preconfigured. You only h
You can configure the following settings if you like, a useful default will be filled if you don't change anything:
**Scopes**: The scopes define which scopes will be sent to the provider, `openid`, `profile`, and `email` are prefilled.
-This information is used to create and/or update the user within ZITADEL.
+This information is used to create and/or update the user within ZITADEL. ZITADEL ensures that at least the `openid`-scope is always sent.
diff --git a/docs/docs/guides/integrate/identity-providers/gitlab.mdx b/docs/docs/guides/integrate/identity-providers/gitlab.mdx
index 64600dbd4..fe3a89e97 100644
--- a/docs/docs/guides/integrate/identity-providers/gitlab.mdx
+++ b/docs/docs/guides/integrate/identity-providers/gitlab.mdx
@@ -62,7 +62,7 @@ Add the client ID and secret you have created in the Gitlab Application.
You can configure the following settings if you like, a useful default will be filled if you don't change anything:
-**Scopes**: The scopes define which scopes will be sent to the provider, `openid`, `profile`, and `email` are prefilled. This informations will be taken to create/update the user within ZITADEL.
+**Scopes**: The scopes define which scopes will be sent to the provider, `openid`, `profile`, and `email` are prefilled. This informations will be taken to create/update the user within ZITADEL. ZITADEL ensures that at least the `openid`-scope is always sent.
diff --git a/docs/docs/guides/integrate/identity-providers/google.mdx b/docs/docs/guides/integrate/identity-providers/google.mdx
index 9fd0ff7ab..e2ca36001 100644
--- a/docs/docs/guides/integrate/identity-providers/google.mdx
+++ b/docs/docs/guides/integrate/identity-providers/google.mdx
@@ -45,7 +45,7 @@ Add the client ID and secret created before on your Google App.
You can configure the following settings if you like, a useful default will be filled if you don't change anything:
-**Scopes**: The scopes define which scopes will be sent to the provider, `openid`, `profile`, and `email` are prefilled. This information will be taken to create/update the user within ZITADEL.
+**Scopes**: The scopes define which scopes will be sent to the provider, `openid`, `profile`, and `email` are prefilled. This information will be taken to create/update the user within ZITADEL. ZITADEL ensures that at least the `openid`-scope is always sent.
diff --git a/internal/idp/providers/azuread/azuread.go b/internal/idp/providers/azuread/azuread.go
index 2d19b44aa..da1ce0ead 100644
--- a/internal/idp/providers/azuread/azuread.go
+++ b/internal/idp/providers/azuread/azuread.go
@@ -16,6 +16,8 @@ const (
authURLTemplate string = "https://login.microsoftonline.com/%s/oauth2/v2.0/authorize"
tokenURLTemplate string = "https://login.microsoftonline.com/%s/oauth2/v2.0/token"
userinfoURL string = "https://graph.microsoft.com/v1.0/me"
+
+ ScopeUserRead string = "User.Read"
)
// TenantType are the well known tenant types to scope the users that can authenticate. TenantType is not an
@@ -99,7 +101,7 @@ func New(name, clientID, clientSecret, redirectURI string, scopes []string, opts
}
func newConfig(tenant TenantType, clientID, secret, callbackURL string, scopes []string) *oauth2.Config {
- c := &oauth2.Config{
+ return &oauth2.Config{
ClientID: clientID,
ClientSecret: secret,
RedirectURL: callbackURL,
@@ -107,13 +109,34 @@ func newConfig(tenant TenantType, clientID, secret, callbackURL string, scopes [
AuthURL: fmt.Sprintf(authURLTemplate, tenant),
TokenURL: fmt.Sprintf(tokenURLTemplate, tenant),
},
- Scopes: []string{oidc.ScopeOpenID},
- }
- if len(scopes) > 0 {
- c.Scopes = scopes
+ Scopes: ensureMinimalScope(scopes),
}
+}
- return c
+// ensureMinimalScope ensures that at least openid and `User.Read` ist set
+// if none is provided it will request `openid profile email phone User.Read`
+func ensureMinimalScope(scopes []string) []string {
+ if len(scopes) == 0 {
+ return []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopePhone, ScopeUserRead}
+ }
+ var openIDSet, userReadSet bool
+ for _, scope := range scopes {
+ if scope == oidc.ScopeOpenID {
+ openIDSet = true
+ continue
+ }
+ if scope == ScopeUserRead {
+ userReadSet = true
+ continue
+ }
+ }
+ if !openIDSet {
+ scopes = append(scopes, oidc.ScopeOpenID)
+ }
+ if !userReadSet {
+ scopes = append(scopes, ScopeUserRead)
+ }
+ return scopes
}
// User represents the structure return on the userinfo endpoint and implements the [idp.User] interface
diff --git a/internal/idp/providers/azuread/azuread_test.go b/internal/idp/providers/azuread/azuread_test.go
index 16d72d0b4..87b048ae9 100644
--- a/internal/idp/providers/azuread/azuread_test.go
+++ b/internal/idp/providers/azuread/azuread_test.go
@@ -36,7 +36,7 @@ func TestProvider_BeginAuth(t *testing.T) {
redirectURI: "redirectURI",
},
want: &oidc.Session{
- AuthURL: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=clientID&prompt=select_account&redirect_uri=redirectURI&response_type=code&scope=openid&state=testState",
+ AuthURL: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=clientID&prompt=select_account&redirect_uri=redirectURI&response_type=code&scope=openid+profile+email+phone+User.Read&state=testState",
},
},
{
@@ -50,7 +50,7 @@ func TestProvider_BeginAuth(t *testing.T) {
},
},
want: &oidc.Session{
- AuthURL: "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=clientID&prompt=select_account&redirect_uri=redirectURI&response_type=code&scope=openid&state=testState",
+ AuthURL: "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=clientID&prompt=select_account&redirect_uri=redirectURI&response_type=code&scope=openid+profile+email+phone+User.Read&state=testState",
},
},
{
@@ -59,13 +59,13 @@ func TestProvider_BeginAuth(t *testing.T) {
clientID: "clientID",
clientSecret: "clientSecret",
redirectURI: "redirectURI",
- scopes: []string{openid.ScopeOpenID, openid.ScopeProfile, "user"},
+ scopes: []string{openid.ScopeOpenID, openid.ScopeProfile, "custom"},
options: []ProviderOptions{
WithTenant(ConsumersTenant),
},
},
want: &oidc.Session{
- AuthURL: "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=clientID&prompt=select_account&redirect_uri=redirectURI&response_type=code&scope=openid+profile+user&state=testState",
+ AuthURL: "https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?client_id=clientID&prompt=select_account&redirect_uri=redirectURI&response_type=code&scope=openid+profile+custom+User.Read&state=testState",
},
},
}