Skip to content

Commit

Permalink
Add local login flow (#18717)
Browse files Browse the repository at this point in the history
  • Loading branch information
bramkragten authored Nov 24, 2023
1 parent eaf7e29 commit 58e0179
Show file tree
Hide file tree
Showing 7 changed files with 424 additions and 60 deletions.
54 changes: 28 additions & 26 deletions src/auth/ha-auth-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,46 +29,48 @@ export class HaAuthFlow extends LitElement {

@property() public localize!: LocalizeFunc;

@property({ attribute: false }) public step?: DataEntryFlowStep;

@property({ type: Boolean }) private storeToken = false;

@state() private _state: State = "loading";

@state() private _stepData?: Record<string, any>;

@state() private _step?: DataEntryFlowStep;

@state() private _errorMessage?: string;

@state() private _submitting = false;

@state() private _storeToken = false;

createRenderRoot() {
return this;
}

willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);

if (!changedProps.has("_step")) {
if (!changedProps.has("step")) {
return;
}

if (!this._step) {
if (!this.step) {
this._stepData = undefined;
return;
}

const oldStep = changedProps.get("_step") as HaAuthFlow["_step"];
this._state = "step";

const oldStep = changedProps.get("step") as HaAuthFlow["step"];

if (
!oldStep ||
this._step.flow_id !== oldStep.flow_id ||
(this._step.type === "form" &&
this.step.flow_id !== oldStep.flow_id ||
(this.step.type === "form" &&
oldStep.type === "form" &&
this._step.step_id !== oldStep.step_id)
this.step.step_id !== oldStep.step_id)
) {
this._stepData =
this._step.type === "form"
? computeInitialHaFormData(this._step.data_schema)
this.step.type === "form"
? computeInitialHaFormData(this.step.data_schema)
: undefined;
}
}
Expand Down Expand Up @@ -117,7 +119,7 @@ export class HaAuthFlow extends LitElement {
this._providerChanged(this.authProvider);
}

if (!changedProps.has("_step") || this._step?.type !== "form") {
if (!changedProps.has("step") || this.step?.type !== "form") {
return;
}

Expand All @@ -133,18 +135,18 @@ export class HaAuthFlow extends LitElement {
private _renderForm() {
switch (this._state) {
case "step":
if (this._step == null) {
if (this.step == null) {
return nothing;
}
return html`
${this._renderStep(this._step)}
${this._renderStep(this.step)}
<div class="action">
<mwc-button
raised
@click=${this._handleSubmit}
.disabled=${this._submitting}
>
${this._step.type === "form"
${this.step.type === "form"
? this.localize("ui.panel.page-authorize.form.next")
: this.localize("ui.panel.page-authorize.form.start_over")}
</mwc-button>
Expand Down Expand Up @@ -205,7 +207,7 @@ export class HaAuthFlow extends LitElement {
.label=${this.localize("ui.panel.page-authorize.store_token")}
>
<ha-checkbox
.checked=${this._storeToken}
.checked=${this.storeToken}
@change=${this._storeTokenChanged}
></ha-checkbox>
</ha-formfield>
Expand All @@ -218,12 +220,12 @@ export class HaAuthFlow extends LitElement {
}

private _storeTokenChanged(e: CustomEvent<HTMLInputElement>) {
this._storeToken = (e.currentTarget as HTMLInputElement).checked;
this.storeToken = (e.currentTarget as HTMLInputElement).checked;
}

private async _providerChanged(newProvider?: AuthProvider) {
if (this._step && this._step.type === "form") {
fetch(`/auth/login_flow/${this._step.flow_id}`, {
if (this.step && this.step.type === "form") {
fetch(`/auth/login_flow/${this.step.flow_id}`, {
method: "DELETE",
credentials: "same-origin",
}).catch((err) => {
Expand Down Expand Up @@ -260,7 +262,7 @@ export class HaAuthFlow extends LitElement {
return;
}

this._step = data;
this.step = data;
this._state = "step";
} else {
this._state = "error";
Expand Down Expand Up @@ -288,7 +290,7 @@ export class HaAuthFlow extends LitElement {
if (this.oauth2State) {
url += `&state=${encodeURIComponent(this.oauth2State)}`;
}
if (this._storeToken) {
if (this.storeToken) {
url += `&storeToken=true`;
}

Expand Down Expand Up @@ -331,10 +333,10 @@ export class HaAuthFlow extends LitElement {

private async _handleSubmit(ev: Event) {
ev.preventDefault();
if (this._step == null) {
if (this.step == null) {
return;
}
if (this._step.type !== "form") {
if (this.step.type !== "form") {
this._providerChanged(this.authProvider);
return;
}
Expand All @@ -343,7 +345,7 @@ export class HaAuthFlow extends LitElement {
const postData = { ...this._stepData, client_id: this.clientId };

try {
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
const response = await fetch(`/auth/login_flow/${this.step.flow_id}`, {
method: "POST",
credentials: "same-origin",
body: JSON.stringify(postData),
Expand All @@ -361,7 +363,7 @@ export class HaAuthFlow extends LitElement {
this._redirect(newStep.result);
return;
}
this._step = newStep;
this.step = newStep;
this._state = "step";
} catch (err: any) {
// eslint-disable-next-line no-console
Expand Down
68 changes: 43 additions & 25 deletions src/auth/ha-authorize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
import { registerServiceWorker } from "../util/register-service-worker";
import "./ha-auth-flow";
import "./ha-local-auth-flow";

import("./ha-pick-auth-provider");

Expand All @@ -39,6 +40,8 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {

@state() private _error?: string;

@state() private _forceDefaultLogin = false;

constructor() {
super();
const query = extractSearchParamsObject() as AuthUrlSearchParams;
Expand Down Expand Up @@ -121,32 +124,43 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
})}
</ha-alert>`
: html`<p>${this.localize("ui.panel.page-authorize.authorizing")}</p>`}
${inactiveProviders.length > 0
? html`<p>
${this.localize("ui.panel.page-authorize.logging_in_with", {
authProviderName: html`<b>${this._authProvider!.name}</b>`,
})}
</p>`
: nothing}
<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.localize=${this.localize}
></ha-auth-flow>
${inactiveProviders.length > 0
? html`
<ha-pick-auth-provider
.localize=${this.localize}
${!this._forceDefaultLogin &&
this._authProvider!.users &&
this.clientId != null &&
this.redirectUri != null
? html`<ha-local-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.authProviders=${this._authProviders}
.localize=${this.localize}
@default-login-flow=${this._handleDefaultLoginFlow}
></ha-local-auth-flow>`
: html`${inactiveProviders.length > 0
? html`<p>
${this.localize("ui.panel.page-authorize.logging_in_with", {
authProviderName: html`<b>${this._authProvider!.name}</b>`,
})}
</p>`
: nothing}
<ha-auth-flow
.clientId=${this.clientId}
.authProviders=${inactiveProviders}
@pick-auth-provider=${this._handleAuthProviderPick}
></ha-pick-auth-provider>
`
: ""}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.localize=${this.localize}
></ha-auth-flow>
${inactiveProviders.length > 0
? html`
<ha-pick-auth-provider
.localize=${this.localize}
.clientId=${this.clientId}
.authProviders=${inactiveProviders}
@pick-auth-provider=${this._handleAuthProviderPick}
></ha-pick-auth-provider>
`
: ""}`}
`;
}

Expand Down Expand Up @@ -245,6 +259,10 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
}
}

private _handleDefaultLoginFlow() {
this._forceDefaultLogin = true;
}

private async _handleAuthProviderPick(ev) {
this._authProvider = ev.detail;
}
Expand Down
Loading

0 comments on commit 58e0179

Please sign in to comment.