From 67227392c324ad1b1594044c06587def4cdb4176 Mon Sep 17 00:00:00 2001 From: gounux Date: Tue, 22 Apr 2025 17:12:58 +0200 Subject: [PATCH 1/4] Add third-party logins page Add missing participant creation --- .../reference/qfieldcloud/logins.en.md | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 documentation/reference/qfieldcloud/logins.en.md diff --git a/documentation/reference/qfieldcloud/logins.en.md b/documentation/reference/qfieldcloud/logins.en.md new file mode 100644 index 000000000..b96dd8515 --- /dev/null +++ b/documentation/reference/qfieldcloud/logins.en.md @@ -0,0 +1,84 @@ +--- +title: Third-party login +tx_slug: documentation_reference_qfieldcloud_sso_auth +--- + +# Third-party authentication + +QFieldCloud and QField / QFieldSync clients allow authentication using regular login and password, for a user that is already registered on QFieldCloud. + +It is also possible to authenticate using a third-party identity provider (e.g. Google, [OpenID Connect](https://openid.net/developers/how-connect-works/)). + +Here is a sequence diagram of how a third-party login happens in QFieldCloud (in the browser): + +```mermaid +sequenceDiagram + autonumber + + actor User + participant QFC as QFieldCloud + + User ->> QFC: Access login page + QFC -->> User: Display login form with configured third-party login buttons + + User ->> QFC: Click third-party login button + + create participant IDP as Identity Provider + QFC ->> IDP: Redirect to IDP for login + IDP -->> User: Display IDP's login form + + User ->> IDP: Log in using IDP's credentials + destroy IDP + + IDP ->> QFC: Redirect back with auth details + + alt User does not already have a QFieldCloud account + note over QFC: QFieldCloud account is created using IDP auth details + end + + QFC -->> User: User is logged in +``` + +Here is a sequence diagram of how third-party authentication happens in QField and QFieldSync: + +```mermaid +sequenceDiagram + autonumber + + participant IDP as Identity Provider + actor User + participant QF as QField / QFieldSync + participant QFC as QFieldCloud + + User ->>+ QF: Open the QFieldCloud login dialog + + QF ->> QFC: Ask for configured third-party ID providers + QFC -->> QF: Answer with the list of configured third-party ID providers + QF -->>- User: Display a button for each third-party ID provider + + User ->>+ QF: Click on 'Login with XYZ' provider button + + Note over QF: A QgsAuthMethodConfig of type OAuth2 is created
QGIS auth manager recognizes that the user is not authenticated yet
QGIS auth manager then redirects to the IDP for authenticating the user + + QF ->>+ IDP: Redirect to IDP for login + IDP -->> User: Display IDP's login form in a browser + User ->> IDP: Log in using IDP's credentials in the browser + IDP ->>- QF: Answer with auth details and an id_token token + + QF ->>+ QFC: Ask for current user's informations + Note over QF,QFC: The id_token provided by IDP is in in the X-QFC-ID-Token HTTP header
The IDP provider type (e.g. "google") is in the X-QFC-IDP-ID header + + QFC -->>- QF: Answer with user information (username, avatar, etc.) + QF -->>- User: User is logged in and authenticated + + loop send HTTP regular requests (e.g. file synchronization) + QF ->> QFC: Send a request (e.g. file Download/Upload) + Note over QF,QFC: The id_token provided by IDP is in in the X-QFC-ID-Token HTTP header
The IDP provider type (e.g. "google") is in the X-QFC-IDP-ID header + QFC -->> QF: Reply to the request + end + + loop refresh token regularly + QF ->> IDP: Ask for a new token + IDP -->> QF: Send a refreshed token + end +``` From bd291332201632104e8f643acb5719b0766484c4 Mon Sep 17 00:00:00 2001 From: Lukas Graf Date: Wed, 30 Apr 2025 16:53:51 +0200 Subject: [PATCH 2/4] Amend authentication docs. --- .../qfieldcloud/{logins.en.md => auth.en.md} | 41 ++++++++++++------- mkdocs.yml | 1 + 2 files changed, 28 insertions(+), 14 deletions(-) rename documentation/reference/qfieldcloud/{logins.en.md => auth.en.md} (58%) diff --git a/documentation/reference/qfieldcloud/logins.en.md b/documentation/reference/qfieldcloud/auth.en.md similarity index 58% rename from documentation/reference/qfieldcloud/logins.en.md rename to documentation/reference/qfieldcloud/auth.en.md index b96dd8515..14869ba84 100644 --- a/documentation/reference/qfieldcloud/logins.en.md +++ b/documentation/reference/qfieldcloud/auth.en.md @@ -1,13 +1,17 @@ --- -title: Third-party login -tx_slug: documentation_reference_qfieldcloud_sso_auth +title: Authentication +tx_slug: documentation_reference_qfieldcloud_auth --- -# Third-party authentication +# Authentication -QFieldCloud and QField / QFieldSync clients allow authentication using regular login and password, for a user that is already registered on QFieldCloud. +QFieldCloud and QField / QFieldSync clients allow authentication using regular username and password, or, if configured, **OpenID Connect** with a third-party identity provider. -It is also possible to authenticate using a third-party identity provider (e.g. Google, [OpenID Connect](https://openid.net/developers/how-connect-works/)). +## OpenID Connect authentication + +[OpenID Connect](https://openid.net/developers/how-connect-works/) (OIDC) is an industry standard authentication protocol on top of [OAuth2](https://oauth.net/2/) that allows to delegate authentication to an identity provider (IDP) such as Google, Microsoft, or any other OpenID Connect compliant provider. This allows users to log in to QFieldCloud using their existing accounts with these providers, without needing to create a separate account for QFieldCloud. + +OIDC can be used directly for signing up with QFieldCloud, or for signing in to an existing QFieldCloud account (matched via verified email address). Here is a sequence diagram of how a third-party login happens in QFieldCloud (in the browser): @@ -15,7 +19,7 @@ Here is a sequence diagram of how a third-party login happens in QFieldCloud (in sequenceDiagram autonumber - actor User + actor User as User (Browser) participant QFC as QFieldCloud User ->> QFC: Access login page @@ -23,20 +27,29 @@ sequenceDiagram User ->> QFC: Click third-party login button + QFC -->> User: Redirect to IDP for login create participant IDP as Identity Provider - QFC ->> IDP: Redirect to IDP for login - IDP -->> User: Display IDP's login form + User ->> IDP: Follow redirect to IDP login page + IDP -->> User: Display IDP's login page - User ->> IDP: Log in using IDP's credentials - destroy IDP + User ->> IDP: Authenticate using IDP credentials - IDP ->> QFC: Redirect back with auth details + IDP -->> User: Redirect to QFieldCloud callback URL with authorization code + User ->>+ QFC: Hand authorization code to QFieldCloud + QFC ->> IDP: Exchange authorization code for access token and ID token + IDP -->> QFC: Return access token + ID token + + Note over QFC: Validate ID token signature + + QFC ->> IDP: Request user profile information + destroy IDP + IDP -->> QFC: Return user profile information - alt User does not already have a QFieldCloud account - note over QFC: QFieldCloud account is created using IDP auth details + alt If user does not already have a QFieldCloud account + note over QFC: QFieldCloud account is created using IDP profile infos end - QFC -->> User: User is logged in + QFC -->>- User: Log user in (establish session) ``` Here is a sequence diagram of how third-party authentication happens in QField and QFieldSync: diff --git a/mkdocs.yml b/mkdocs.yml index 5a98cf513..6214402af 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -105,6 +105,7 @@ nav: - reference/qfieldcloud/workflow.md - reference/qfieldcloud/concepts.md - reference/qfieldcloud/projects.md + - reference/qfieldcloud/auth.md - reference/qfieldcloud/permissions.md - reference/qfieldcloud/jobs.md - reference/qfieldcloud/secrets.md From 7e8d30e9b541ce5a6e6b3cc50d13fe21ed1e3aad Mon Sep 17 00:00:00 2001 From: Lukas Graf Date: Tue, 6 May 2025 11:15:47 +0200 Subject: [PATCH 3/4] auth docs: Extend description of QField/QFieldSync OIDC flow. --- .../reference/qfieldcloud/auth.en.md | 97 +++++++++++++++++-- 1 file changed, 87 insertions(+), 10 deletions(-) diff --git a/documentation/reference/qfieldcloud/auth.en.md b/documentation/reference/qfieldcloud/auth.en.md index 14869ba84..381983f5c 100644 --- a/documentation/reference/qfieldcloud/auth.en.md +++ b/documentation/reference/qfieldcloud/auth.en.md @@ -13,6 +13,8 @@ QFieldCloud and QField / QFieldSync clients allow authentication using regular u OIDC can be used directly for signing up with QFieldCloud, or for signing in to an existing QFieldCloud account (matched via verified email address). +### QFieldCloud (Web) + Here is a sequence diagram of how a third-party login happens in QFieldCloud (in the browser): ```mermaid @@ -52,6 +54,8 @@ sequenceDiagram QFC -->>- User: Log user in (establish session) ``` +### QField / QFieldSync + Here is a sequence diagram of how third-party authentication happens in QField and QFieldSync: ```mermaid @@ -65,28 +69,31 @@ sequenceDiagram User ->>+ QF: Open the QFieldCloud login dialog - QF ->> QFC: Ask for configured third-party ID providers - QFC -->> QF: Answer with the list of configured third-party ID providers - QF -->>- User: Display a button for each third-party ID provider + QF ->> QFC: Ask for list of identity providers + QFC -->> QF: Answer with list of identity providers + QF -->>- User: Display a button for each identity provider User ->>+ QF: Click on 'Login with XYZ' provider button Note over QF: A QgsAuthMethodConfig of type OAuth2 is created
QGIS auth manager recognizes that the user is not authenticated yet
QGIS auth manager then redirects to the IDP for authenticating the user - QF ->>+ IDP: Redirect to IDP for login + QF ->> IDP: Redirect to IDP for login IDP -->> User: Display IDP's login form in a browser User ->> IDP: Log in using IDP's credentials in the browser - IDP ->>- QF: Answer with auth details and an id_token token + IDP -->> QF: Answer with authorization code + QF ->> IDP: Exchange authorization code for access token and ID token + IDP -->> QF: Answer with access token and ID token + QF ->> QFC: Use ID token to authenticate user + + Note over QFC: Validate ID token signature - QF ->>+ QFC: Ask for current user's informations - Note over QF,QFC: The id_token provided by IDP is in in the X-QFC-ID-Token HTTP header
The IDP provider type (e.g. "google") is in the X-QFC-IDP-ID header + QFC -->> QF: Establish user session and return user info - QFC -->>- QF: Answer with user information (username, avatar, etc.) QF -->>- User: User is logged in and authenticated - loop send HTTP regular requests (e.g. file synchronization) + loop HTTP requests to QFieldCloud QF ->> QFC: Send a request (e.g. file Download/Upload) - Note over QF,QFC: The id_token provided by IDP is in in the X-QFC-ID-Token HTTP header
The IDP provider type (e.g. "google") is in the X-QFC-IDP-ID header + Note over QF,QFC: Tokens are attached to requests in HTTP headers QFC -->> QF: Reply to the request end @@ -95,3 +102,73 @@ sequenceDiagram IDP -->> QF: Send a refreshed token end ``` + +#### Details + +1. **Open the QFieldCloud login dialog** + User clicks on the QFieldCloud login button in QField / QFieldSync

+ +2. **Ask for list of identity providers** + Query the QFieldCloud `api/v1/auth/providers` endpoint for a list of enabled identity providers, and their configuration details.

+ +3. **Answer with list of identity providers** + Return the list of enabled identity providers. + For each IDP this will include information to render the UI (title, logo, colors), and also the necessary OIDC configuration details for the given IDP. These include properties like the client ID, token URL, etc. for QField/QFieldSync to connect to the IDP.

+ +4. **Display a button for each identity provider** + For each enabled authentication method a login button is rendered.

+ +5. **Click on 'Login with XYZ' provider button** + User clicks the button to log in with a particular provider. + At this point, QField/QFieldSync will create a new `QgsAuthMethodConfig` of type OAuth2, and will use the OIDC configuration details received from QFieldCloud to configure it.

+ +6. **Redirect to IDP for login** + QField/QFieldSync will then open a browser window and send the user to the IDPs login page. + In the URL for that login page a redirect_url is included which points back to the callback at which QField/QFieldSync will receive the IDP's response that will include the authorization code. + For that purpose, QField/QFieldSync will spawn a temporary web server at `http://localhost:7070` which will receive that callback.

+ +7. **Display IDP's login form in a browser** + The IDP presents the user with a login page and a consent form.

+ +8. **Log in using IDP's credentials in the browser** + The user authenticates to the IDP, using whichever authentication method the IDP supports (username/password, client certificate, session, ...).

+ +9. **Answer with authorization code** + The IDP will redirect the user's browser back to the redirect_url, where QField/QFieldSync's temporary webserver will receive the callback, which includes the long lived OIDC authorization code.

+ +10. **Exchange authorization code for access token and ID token** + QField/QFieldSync will send the authorization code to the IDP's token endpoint, and exchange it for ID token, access token and refresh token.

+ +11. **Answer with access token and ID token** + The IDP verifies the authoritation code (with the addition of PKCE), and responds with ID token, access token and refresh token, which are short lived.

+ +12. **Use ID token to authenticate user** + QField/QFieldSync will send the ID token and access token to QFieldCloud, and request the user's profile information.

+ +13. **Establish user session and return user info** + QFieldCloud will verify the ID token's signature and authenticate the user. If successful, it responds with the user's profile information and a user session.

+ +14. **User is logged in and authenticated** + QField/QFieldSync will receive and store the user's profile information and authentication session.

+ + + +#### Request loop + +15. **Send a request (e.g. file Download/Upload)** + Once a user has authenticated with the IDP, and QField/QFieldSync has received the OIDC tokens, it will attach the ID token and access token in subsequent requests to QFieldCloud as HTTP request headers. + (Technically speaking, it's actually the QGIS auth manager which will do this). + The access token is included as an `Authorization: Bearer ` HTTP header, and the ID token is included in the `X-QFC-ID-Token` HTTP header. + The IDP provider type (e.g. `google`) is included in the `X-QFC-IDP-ID` HTTP header, to let QFieldCloud know which IDP the token needs to be verified with.

+ +16. **Reply to the request** + QFieldCloud will authenticate the user, either through an existing session, or through the OIDC tokens, and respond to the request.

+ + +#### Token refresh loop + +17. **Ask for a new token** + QField/QFieldSync will regularly refresh the ID and access tokens by calling the IDP's token refresh endpoint and submitting the refresh token it received.

+ +18. **Send a refreshed token** + The IDP will respond with new ID and access tokens.

From 8b668eaaadaeadb0402bdf36e73ae679c8d5e323 Mon Sep 17 00:00:00 2001 From: Lukas Graf Date: Tue, 6 May 2025 17:25:27 +0200 Subject: [PATCH 4/4] auth docs: Remove redundant note from diagram. --- documentation/reference/qfieldcloud/auth.en.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/documentation/reference/qfieldcloud/auth.en.md b/documentation/reference/qfieldcloud/auth.en.md index 381983f5c..1feba8035 100644 --- a/documentation/reference/qfieldcloud/auth.en.md +++ b/documentation/reference/qfieldcloud/auth.en.md @@ -75,8 +75,6 @@ sequenceDiagram User ->>+ QF: Click on 'Login with XYZ' provider button - Note over QF: A QgsAuthMethodConfig of type OAuth2 is created
QGIS auth manager recognizes that the user is not authenticated yet
QGIS auth manager then redirects to the IDP for authenticating the user - QF ->> IDP: Redirect to IDP for login IDP -->> User: Display IDP's login form in a browser User ->> IDP: Log in using IDP's credentials in the browser