Open galadril opened 1 year ago
Flow and pseudo code (WIP):
User creates an 'Application' in Domoticz (for example 'Domoticz4Android') and de-select 'Is Public'. Specify a 'client_secret' (a password for the Application)
User creates a Domoticz User that will be used from the App (or uses an already existing User). It is not recommended to use the standard 'domoticz' admin user for this.
Users starts (Android) App and configures it with
Users initiates the connection process
First the app queries /.well-known/openid-configuration
to request the current end-points, methods, etc. supported by Domoticz. This information will be used in the next steps.
The app sends the User via a Browser with a GET request to /oauth2/v1/authorize
endpoint (= _authorizationendpoint) with multiple (url encoded) parameters:
code
openid
S256
is acceptedcode_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
The User will be presented with a Login dialog (currently just a standard Browser auth dialog)
If authenticated correctly, the User (browser) will be redirected (HTTP 302) back to the provided location of the 'redirect_uri'
This redirect response should be captured by the App and the different URL parameters have to be processed
To exchange the received 'code' for tokens, a POST request needs to be done by the App itself (and not the Browser) to /oauth2/v1/token
(= _tokenendpoint) and several parameters have to be provided:
authorization_code
If everything matches (the code_verifier and the client_id/client_secret), domoticz generates the tokens. The resulting JSON should contain a (JWT) token
and an refresh_token
.
Now this Bearer token should be provided with each request between the App and Domoticz using the 'Authorization' header.
Once the token has expired (receiving 401 from Domoticz), the refresh token can be used to request a new token without the need to go through the above process and asking the User for credentials again.
refresh_token
I could be wrong, but isnt the whole purpose of having a oauth pkce flow to not ask the user for credentials yourself from within the app. I would expect to open a browser with some parameters (challenge etc) to let Domoticz handle the authentication.
And then use the access/refresh tokens afterwards
Thats how i understand it from for example Okta https://developer.okta.com/docs/guides/implement-grant-type/authcodepkce/main/
That is indeed how it works on the web. And if you 'sent' the user to Domoticz, it will ask for a User/Pass (currently through standard Basic Auth dialog of the browser and not via a nice login dialog at the moment) and redirect the User back.
I am not an App developer, I do not know if/how an App could send the User to their Domoticz instance, perform the login there and then get redirect back to the App. But I know it can be done as I see it work in multiple apps.
But you are right, ideally the App does not require to ask for User/Pass and just receives the 'code' and can continue from there. Let's make that work! And I am happy to help where I can.
So i can ask the user to fill in the port/ip for remote and local domoticz connections for example.
First the app will then generate a code verifier followed by a code challenge (for the pkce challenge) Then open a browser to allow for user authentication with the next url;
https://{host}:{port}/authorize?
response_type=code&
code_challenge={codeChallenge}&
code_challenge_method=S256&
client_id=YOUR_CLIENT_ID&
redirect_uri={yourCallbackUrl}&
scope=SCOPE&
state={state}
if the user is authenticated, domoticz login form is going to redirect to the {yourCallbackUrl} adding some authenticationToken parameter and the same state value as the original input:
{yourCallbackUrl}?code={authorizationCode}&state={state}
After authenticating, show a permissions acknowledgement form, Domoticz asking the user if you allow that application to connect
Then i could use this authorizationCode to get an access and refresh token via some POST call like:
curl --request POST \
--url 'https://{host}:{port}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data 'client_id=YOUR_CLIENT_ID' \
--data 'code_verifier={yourGeneratedCodeVerifier}' \
--data 'code={yourAuthorizationCode}' \
--data 'redirect_uri={yourCallbackUrl}'
That token endpoint checks the PKCE code challenge and verifier.. also the redirect url should be the same as the original requested one and validates the client id.
If all goes well, you'll receive an HTTP 200 response with a payload containing access_token, refresh_token, id_token, and token_type values:
{
"access_token":"eyJz93a...k4laUWw",
"refresh_token":"GEbRxBN...edjnXbL",
"id_token":"eyJ0XAi...4faeEoQ",
"token_type":"Bearer",
"expires_in":86400
}
If i need to refresh my access token, it would be something like:
curl --request POST \
--url 'https://{host}:{port}/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data grant_type=refresh_token \
--data 'client_id=YOUR_CLIENT_ID' \
--data 'refresh_token={yourRefreshToken}'
a sample of a yourCallbackUrl would be for the mobile app: domoticz://app
that redirect link has a deeplink back the app in.
This is how im used to implementing PKCE / OAUTH flows
Yes, that is correct :)
Domoticz internal OAuth2/OIDC service does not have such nice (2-step) login/consent screens yet, but I am working on a (single-step) login/consent screen.. That will be available soon in an upcoming Domoticz Beta.
But everything else is already there and can be implemented. Just currently the browser does not show a nice login but the standard Basic Auth dialog. But that is not relevant to complete the App side of the flow.
If I can help somehow with testing or ... let me know.
@galadril , I updated my initial comment with the Flow/Pseudo code...
The 'client_id' AND the 'client_secret' are both needed. Although using PKCE ensures the code exchange is not compromised, it does not authenticate the client application (more on this can be found here). And the 'client_secret' has to be provided when doing the POST to the token endpoint. This way the specific app instance gets a trust relation with the specific Domoticz instance.
Don't forget to query the /.well-known/openid-configuration
first to get the correct URI's for the Authentication and Token endpoints. Somewhere in the future, Domoticz users can configure different URI's if they are using another IAM service instead of the now build-in one.
@kiddigital Did the new Domoticz update bring your oAuth to the stable release??
Yes! 😁 Give it a go..
I will.. but yeah moving houses, Android Auto support and Wear OS stopped working came in between..
@kiddigital while going throught this, i just got the idea.. why shouldn't we have a build-in client id/secret for the mobile app? As its part of Domoticz, just like the frontend.. its kinda weird for me to ask from the official Domoticz apps, to first setup the app right?
Makes sense indeed.. saves the User a step.
Can you provide me a build-in id/secret?
Can you provide me a build-in id/secret?
There is no really build-in id/secret, just entries in the Applications
table.
Just create an Application called 'DomoticzMobileApp' with a random secret (7fc692bdd8adaadb2d77b91638770999
for example).
A few default entries will be there by default (disabled except the standard UI) including 'DomoticzMobileApp'.
But the User has to explicitly activate it AND set a secret (either private or public key-pair). Otherwise any app could fake it is a default app and only need User/Pass.
The default apps just make it easier (no typos in ClientID for example).
Domoticz internal OAuth2/OIDC service does not have such nice (2-step) login/consent screens yet, but I am working on a (single-step) login/consent screen.. That will be available soon in an upcoming Domoticz Beta.
was this done already btw?
Yes, there is an optional field for the 2FA code for Users that have 2FA enabled.
And by default there is an 'domoticzMobileApp' application available in the 'Applications' config which is disabled by default and has to be enabled.
More info about OAuth: https://github.com/domoticz/domoticz/blob/development/SECURITY_SETUP.md