Skip to content

Commit 7de0336

Browse files
committed
PD-4790 update docs and naming
1 parent 4e9ef50 commit 7de0336

17 files changed

Lines changed: 240 additions & 190 deletions

projects/orcid-ui-docs/src/app/app.routes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ export const routes: Routes = [
6464
),
6565
},
6666
{
67-
path: 'two-factor-auth-form',
67+
path: 'auth-challenge',
6868
loadComponent: () =>
69-
import('./pages/two-factor-auth-form-page.component').then(
70-
(m) => m.TwoFactorAuthFormPageComponent
69+
import('./pages/auth-challenge-page.component').then(
70+
(m) => m.AuthChallengePageComponent
7171
),
7272
},
7373
]

projects/orcid-ui-docs/src/app/docs-shell.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ <h1 class="docs-logo">Orcid UI</h1>
3232
<a routerLink="/skeleton-placeholder" routerLinkActive="active">
3333
Skeleton Placeholder
3434
</a>
35-
<a routerLink="/two-factor-auth-form" routerLinkActive="active">
36-
Two Factor Authentication Form
35+
<a routerLink="/auth-challenge" routerLinkActive="active">
36+
Authentication Challenge
3737
</a>
3838

3939
<div class="nav-section">Directives</div>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
<app-documentation-page
2+
title="Auth Challenge Component"
3+
description="The &lt;app-auth-challenge&gt; component is a subform that validates user credentials (password) and manages 2FA/recovery code inputs."
4+
>
5+
<div controls>
6+
<p>Customize the subform to preview different configurations:</p>
7+
8+
<div style="display: grid; gap: 16px; margin-bottom: 24px">
9+
<mat-checkbox [(ngModel)]="showHelpText">
10+
Display 2FA help text / controls
11+
</mat-checkbox>
12+
13+
<mat-checkbox [(ngModel)]="showAlert"> Display alert </mat-checkbox>
14+
15+
<mat-checkbox [(ngModel)]="showPasswordField">
16+
Display password field
17+
</mat-checkbox>
18+
19+
<mat-checkbox [(ngModel)]="showTwoFactorField">
20+
Display two-factor field
21+
</mat-checkbox>
22+
23+
<button
24+
style="width: 100px; height: 40px; margin-left: 10px"
25+
mat-button
26+
(click)="form.reset()"
27+
>
28+
Reset form
29+
</button>
30+
</div>
31+
</div>
32+
33+
<div examples>
34+
<form [formGroup]="form" class="w-[537px]">
35+
<app-auth-challenge
36+
[showAlert]="showAlert"
37+
[showHelpText]="showHelpText"
38+
[showPasswordField]="showPasswordField"
39+
[showTwoFactorField]="showTwoFactorField"
40+
codeControlName="twoFactorCode"
41+
recoveryControlName="twoFactorRecoveryCode"
42+
passwordControlName="password"
43+
>
44+
</app-auth-challenge>
45+
</form>
46+
</div>
47+
48+
<div usage style="font-size: 14px">
49+
<p>
50+
This component is a sub-form that must be placed inside a parent
51+
<code>[formGroup]</code>. It manages the UI switching and validation logic
52+
between the password field, 2FA code, and recovery code inputs.
53+
</p>
54+
55+
<p>To implement this component, use the code highlighted in yellow.</p>
56+
57+
<h4>1. Template</h4>
58+
<p>
59+
Place the component inside your existing form. You can toggle the
60+
visibility of the password or 2FA fields using the boolean inputs.
61+
</p>
62+
<pre><code class="language-html">&lt;form [formGroup]="form" (ngSubmit)="save()"&gt;
63+
&lt;!-- Other inputs... --&gt;
64+
65+
<span style="background-color: #fff59d; color: #000;">&lt;app-auth-challenge</span>
66+
<span style="background-color: #fff59d; color: #000;">[showPasswordField]="true"</span>
67+
<span style="background-color: #fff59d; color: #000;">[showTwoFactorField]="true"</span>
68+
<span style="background-color: #fff59d; color: #000;">passwordControlName="password"</span>
69+
<span style="background-color: #fff59d; color: #000;">codeControlName="twoFactorCode"</span>
70+
<span style="background-color: #fff59d; color: #000;">recoveryControlName="twoFactorRecoveryCode"</span>
71+
<span style="background-color: #fff59d; color: #000;">[showAlert]="true"&gt;</span>
72+
<span style="background-color: #fff59d; color: #000;">&lt;/app-auth-challenge&gt;</span>
73+
74+
&lt;/form&gt;</code></pre>
75+
76+
<h4>2. Form Configuration</h4>
77+
<p>
78+
Initialize the controls in your parent component. Note that
79+
<code>Validators.required</code> for the 2FA fields is managed
80+
automatically by the child component.
81+
</p>
82+
<pre><code class="language-typescript">this.form = this.fb.group(&#123;
83+
// ... other controls
84+
<span style="background-color: #fff59d; color: #000;">password: ['', Validators.required],</span>
85+
<span style="background-color: #fff59d; color: #000;">twoFactorCode: [null, [Validators.minLength(6), Validators.maxLength(6)]],</span>
86+
<span style="background-color: #fff59d; color: #000;">twoFactorRecoveryCode: [null, [Validators.minLength(10), Validators.maxLength(10)]],</span>
87+
&#125;);</code></pre>
88+
89+
<h4>3. Handling Submit & Responses</h4>
90+
<p>
91+
Use <code>@ViewChild</code> to access the component. This allows you to
92+
delegate backend error mapping (invalid password, invalid codes) and focus
93+
management.
94+
</p>
95+
<pre><code class="language-typescript"><span style="background-color: #fff59d; color: #000;">@ViewChild(AuthChallengeComponent) authChallengeComponent: AuthChallengeComponent;</span>
96+
97+
save() &#123;
98+
if (this.form.valid) &#123;
99+
this.service.update(this.form.value).subscribe(response => &#123;
100+
// Pass backend response to child to handle errors (password/2fa) or focus
101+
<span style="background-color: #fff59d; color: #000;">this.authChallengeComponent?.processBackendResponse(response);</span>
102+
103+
<span style="color: #666">// Used when we don't know if the user</span>
104+
<span style="color: #666">// has 2fa enabled (e.g. signin)</span>
105+
<span style="background-color: #fff59d; color: #000;">if (response.twoFactorEnabled && !response.invalidPassword) &#123;</span>
106+
<span style="background-color: #fff59d; color: #000;">this.twoFactorEnabled = true;</span>
107+
<span style="background-color: #fff59d; color: #000;">&#125;</span>
108+
&#125;);
109+
&#125;
110+
&#125;</code></pre>
111+
<h4>4. Interface Definition</h4>
112+
<p>
113+
The endpoint payload/response object needs to extend the
114+
<strong><code>AuthChallenge</code></strong> interface/pojo.
115+
</p>
116+
<pre><code class="language-typescript">export interface AuthChallenge &#123;
117+
invalidPassword?: boolean;
118+
invalidTwoFactorCode?: boolean;
119+
invalidTwoFactorRecoveryCode?: boolean;
120+
twoFactorCode?: string;
121+
twoFactorRecoveryCode?: string;
122+
twoFactorEnabled?: boolean;
123+
&#125;</code></pre>
124+
125+
<h4>5. Backend Implementation</h4>
126+
<p>
127+
The backend validation consists of two steps: verifying the password and
128+
validating the 2FA status.
129+
</p>
130+
<p>
131+
<strong>1. Password Check:</strong> First, retrieve the user profile and
132+
validate the submitted password against the stored encrypted password. If
133+
it does not match, set the <code>invalidPassword</code> flag and return
134+
the form.
135+
</p>
136+
<p>
137+
<strong>2. 2FA Check:</strong> If the password is valid, use the
138+
<code>TwoFactorAuthenticationManager</code>. If no codes are provided, it
139+
will assume a two-step flow (enabling the <code>twoFactorEnabled</code>
140+
flag). Otherwise, it validates the provided codes.
141+
</p>
142+
143+
<pre><code class="language-java"><span style="background-color: #fff59d; color: #000;">ProfileEntity profile = profileEntityCacheManager.retrieve(getCurrentUserOrcid());</span>
144+
145+
<span style="color: #666">// 1. Validate Password</span>
146+
<span style="background-color: #fff59d; color: #000;">if (form.getPassword() == null || !encryptionManager.hashMatches(form.getPassword(), profile.getEncryptedPassword())) &#123;</span>
147+
<span style="background-color: #fff59d; color: #000;">form.setInvalidPassword(true);</span>
148+
<span style="background-color: #fff59d; color: #000;">return form;</span>
149+
<span style="background-color: #fff59d; color: #000;">&#125;</span>
150+
151+
<span style="color: #666">// 2. Validate 2FA</span>
152+
<span style="background-color: #fff59d; color: #000;">if (!twoFactorAuthenticationManager.validateTwoFactorAuthForm(orcid, form)) &#123;</span>
153+
<span style="background-color: #fff59d; color: #000;">return form;</span>
154+
<span style="background-color: #fff59d; color: #000;">&#125;</span></code></pre>
155+
</div>
156+
157+
<div inputs>
158+
<ul style="font-size: 14px">
159+
<li>
160+
<code style="font-weight: bold">passwordControlName</code>:
161+
<code>string</code>. The name of the form control for the password
162+
input. (default <code>'passwordControl'</code>)
163+
</li>
164+
<li>
165+
<code style="font-weight: bold">codeControlName</code>:
166+
<code>string</code>. The name of the form control for the 6-digit
167+
authentication code. (default <code>'twoFactorCodeControl'</code>)
168+
</li>
169+
<li>
170+
<code style="font-weight: bold">recoveryControlName</code>:
171+
<code>string</code>. The name of the form control for the 10-character
172+
recovery code. (default <code>'twoFactorRecoveryCodeControl'</code>)
173+
</li>
174+
<li>
175+
<code style="font-weight: bold">showPasswordField</code>:
176+
<code>boolean</code>. Whether to display the password input field.
177+
(default <code>true</code>)
178+
</li>
179+
<li>
180+
<code style="font-weight: bold">showTwoFactorField</code>:
181+
<code>boolean</code>. Whether to display the 2FA/Recovery input fields.
182+
(default <code>false</code>)
183+
</li>
184+
<li>
185+
<code style="font-weight: bold">showAlert</code>: <code>boolean</code>.
186+
Whether to display the notice alert indicating 2FA is active or password
187+
verification is needed. (default <code>false</code>)
188+
</li>
189+
<li>
190+
<code style="font-weight: bold">showHelpText</code>:
191+
<code>boolean</code>. Whether to display the helper links (e.g. "Use a
192+
recovery code instead") below the inputs. (default <code>true</code>)
193+
</li>
194+
</ul>
195+
</div>
196+
</app-documentation-page>

projects/orcid-ui-docs/src/app/pages/two-factor-auth-form-page.component.scss renamed to projects/orcid-ui-docs/src/app/pages/auth-challenge-page.component.scss

File renamed without changes.

projects/orcid-ui-docs/src/app/pages/two-factor-auth-form-page.component.ts renamed to projects/orcid-ui-docs/src/app/pages/auth-challenge-page.component.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import { MatSelectModule } from '@angular/material/select'
1111
import { MatFormFieldModule } from '@angular/material/form-field'
1212
import { MatInputModule } from '@angular/material/input'
1313
import { MatIconModule } from '@angular/material/icon'
14-
import { TwoFactorAuthFormComponent } from '@orcid/ui'
14+
import { AuthChallengeComponent } from '@orcid/ui'
1515
import { DocumentationPageComponent } from '../components/documentation-page/documentation-page.component'
1616
import '@angular/localize/init'
1717
import { MatCheckboxModule } from '@angular/material/checkbox'
1818

1919
@Component({
20-
selector: 'two-factor-auth-form-page',
20+
selector: 'auth-challenge-page',
2121
standalone: true,
2222
imports: [
2323
CommonModule,
@@ -27,16 +27,18 @@ import { MatCheckboxModule } from '@angular/material/checkbox'
2727
MatInputModule,
2828
MatCheckboxModule,
2929
MatIconModule,
30-
TwoFactorAuthFormComponent,
30+
AuthChallengeComponent,
3131
DocumentationPageComponent,
3232
ReactiveFormsModule,
3333
],
34-
styleUrls: ['./two-factor-auth-form-page.component.scss'],
35-
templateUrl: './two-factor-auth-form-page.component.html',
34+
styleUrls: ['./auth-challenge-page.component.scss'],
35+
templateUrl: './auth-challenge-page.component.html',
3636
})
37-
export class TwoFactorAuthFormPageComponent implements OnInit {
37+
export class AuthChallengePageComponent implements OnInit {
3838
showAlert = false
3939
showHelpText = true
40+
showPasswordField = true
41+
showTwoFactorField = false
4042
form: UntypedFormGroup
4143

4244
constructor(private _fb: UntypedFormBuilder) {}
@@ -48,6 +50,7 @@ export class TwoFactorAuthFormPageComponent implements OnInit {
4850
null,
4951
[Validators.minLength(10), Validators.maxLength(10)],
5052
],
53+
password: ['', Validators.required],
5154
})
5255
}
5356
}

0 commit comments

Comments
 (0)