| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -10,6 +10,7 @@ with. | |||
| 10 | 10 | ||
| 11 | 11 | ## My JavaScript Demos - I Love JavaScript! | |
| 12 | 12 | ||
| 13 | + * [Using Magic Email Links To Authenticate Users With Firebase 5.7.0 In Angular 7.1.2](https://bennadel.github.io/JavaScript-Demos/demos/firebase-email-auth-angular7/) | ||
| 13 | 14 | * [Using A "Drag Shield" To Block Mouse Events During A Drag-And-Drop Workflow In Angular 7.1.2](https://bennadel.github.io/JavaScript-Demos/demos/drag-shield-angular7/) | |
| 14 | 15 | * [ngOnChanges() Life Cycle Hook Only Gets Invoked If Calling Context Actually Provides Input Bindings In Angular 7.1.1](https://bennadel.github.io/JavaScript-Demos/demos/ng-on-changes-no-inputs-angular7/) | |
| 15 | 16 | * [Strict Mode Settings In JavaScript Are Scoped To The Script Tag](https://bennadel.github.io/JavaScript-Demos/demos/use-strict-scoping/) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + | ||
| 2 | + # Now that we're using Webpack, we can install modules locally and just ignore | ||
| 3 | + # them since the assets are baked into the compiled modules. | ||
| 4 | + node_modules/ | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,122 @@ | |||
| 1 | + <!-- | ||
| 2 | + For the sake of simplicity, we are going to keep this demo as SIMPLE AS POSSIBLE. | ||
| 3 | + Each phase of the passwordless / magic email link authentication workflow will be | ||
| 4 | + modeled by one of the following "views". | ||
| 5 | + --> | ||
| 6 | + <div [ngSwitch]="view"> | ||
| 7 | + | ||
| 8 | + <!-- | ||
| 9 | + PHASE ONE: Status Unknown - after we initialize the Firebase client instance, we | ||
| 10 | + don't know the user's authentication status right away. The status is reported | ||
| 11 | + asynchronously. As such, we want to represent the app as "loading" until will, | ||
| 12 | + at the very least, know whether or not the user is logged-in. | ||
| 13 | + --> | ||
| 14 | + <div *ngSwitchCase="( 'loading' )"> | ||
| 15 | + | ||
| 16 | + <p> | ||
| 17 | + <em>Loading....</em> | ||
| 18 | + </p> | ||
| 19 | + | ||
| 20 | + </div> | ||
| 21 | + | ||
| 22 | + <!-- | ||
| 23 | + PHASE TWO: Not Logged-In - once we know that the user does not have a Firebase | ||
| 24 | + user session, we can present them with a login form. Since we are using the magic | ||
| 25 | + email link / passwordless authentication, the user only needs to provide their | ||
| 26 | + email address, to which we will send a one-time-use magic email link. | ||
| 27 | + --> | ||
| 28 | + <div *ngSwitchCase="( 'login' )"> | ||
| 29 | + | ||
| 30 | + <h2> | ||
| 31 | + Login With Magic Email Link | ||
| 32 | + </h2> | ||
| 33 | + | ||
| 34 | + <div *ngIf="errorMessage" class="error"> | ||
| 35 | + {{ errorMessage }} | ||
| 36 | + </div> | ||
| 37 | + | ||
| 38 | + <form (submit)="sendMagicLink( emailInput.value.trim() ); $event.preventDefault()"> | ||
| 39 | + <strong>Email:</strong> | ||
| 40 | + <input #emailInput type="text" size="25" /> | ||
| 41 | + <button type="submit">Send Magic Email Link</button> | ||
| 42 | + </form> | ||
| 43 | + | ||
| 44 | + </div> | ||
| 45 | + | ||
| 46 | + <!-- | ||
| 47 | + PHASE TWO (continued): Email Link Sent - once the magic email link has been sent, | ||
| 48 | + the user will need to go do their email client (ex, Gmail) and either click on | ||
| 49 | + the link we sent her; or, copy-paste the link back into this browser. | ||
| 50 | + --> | ||
| 51 | + <div *ngSwitchCase="( 'sent' )"> | ||
| 52 | + | ||
| 53 | + <h2> | ||
| 54 | + Login With Magic Email Link | ||
| 55 | + </h2> | ||
| 56 | + | ||
| 57 | + <p> | ||
| 58 | + <strong>We've sent you an email</strong> - in order to complete your login, | ||
| 59 | + please click on the link in the email; or, copy-paste it back into this | ||
| 60 | + browser navigation bar. | ||
| 61 | + </p> | ||
| 62 | + | ||
| 63 | + <p> | ||
| 64 | + <a (click)="setView( 'login' )">Return to login</a> | ||
| 65 | + </p> | ||
| 66 | + | ||
| 67 | + </div> | ||
| 68 | + | ||
| 69 | + <!-- | ||
| 70 | + PHASE THREE: Pending Authentication - Firebase has sent out the one-time-use | ||
| 71 | + magic email link for passwordless authentication. The user now needs to confirm | ||
| 72 | + the email address associated with the link (as a security precaution to prevent | ||
| 73 | + session fixation attacks). | ||
| 74 | + // -- | ||
| 75 | + NOTE: If we store the user's email address in something like LocalStorage, then | ||
| 76 | + we can implicitly process this step without asking the user to do anything. | ||
| 77 | + --> | ||
| 78 | + <div *ngSwitchCase="( 'authenticate' )"> | ||
| 79 | + | ||
| 80 | + <h2> | ||
| 81 | + Complete Passwordless Authentication | ||
| 82 | + </h2> | ||
| 83 | + | ||
| 84 | + <div *ngIf="errorMessage" class="error"> | ||
| 85 | + {{ errorMessage }} | ||
| 86 | + </div> | ||
| 87 | + | ||
| 88 | + <form (submit)="authenticate( emailInput.value.trim() ); $event.preventDefault()"> | ||
| 89 | + <strong>Confirm Email:</strong> | ||
| 90 | + <input #emailInput type="text" size="25" /> | ||
| 91 | + <button type="submit">Sign-In</button> | ||
| 92 | + </form> | ||
| 93 | + | ||
| 94 | + <p> | ||
| 95 | + <a (click)="setView( 'login' )">Return to login</a> | ||
| 96 | + </p> | ||
| 97 | + | ||
| 98 | + </div> | ||
| 99 | + | ||
| 100 | + <!-- | ||
| 101 | + PHASE FOUR: Authenticated User - once the user confirms their email address, we | ||
| 102 | + are able to process the email-link URL. This will result in a Firebase use | ||
| 103 | + session. This session is long-lived by default (but can be adjusted); which makes | ||
| 104 | + it important to provide an explicit sign-out call-to-action. | ||
| 105 | + --> | ||
| 106 | + <div *ngSwitchCase="( 'home' )"> | ||
| 107 | + | ||
| 108 | + <h2> | ||
| 109 | + Welcome <code>{{ user.email }}</code>. | ||
| 110 | + </h2> | ||
| 111 | + | ||
| 112 | + <p> | ||
| 113 | + What a glorious day to be using Angular 7 and Firebase! | ||
| 114 | + </p> | ||
| 115 | + | ||
| 116 | + <p> | ||
| 117 | + <a (click)="signout()">Sign-Out</a> | ||
| 118 | + </p> | ||
| 119 | + | ||
| 120 | + </div> | ||
| 121 | + | ||
| 122 | + </div> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,34 @@ | |||
| 1 | + | ||
| 2 | + :host { | ||
| 3 | + display: block ; | ||
| 4 | + font-size: 18px ; | ||
| 5 | + } | ||
| 6 | + | ||
| 7 | + a { | ||
| 8 | + color: red ; | ||
| 9 | + cursor: pointer ; | ||
| 10 | + text-decoration: underline ; | ||
| 11 | + } | ||
| 12 | + | ||
| 13 | + input, | ||
| 14 | + button { | ||
| 15 | + font-size: inherit ; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + .error { | ||
| 19 | + background-color: #ffeeee ; | ||
| 20 | + border: 1px solid #ff0000 ; | ||
| 21 | + border-width: 1px 1px 1px 4px ; | ||
| 22 | + border-radius: 6px 6px 6px 6px ; | ||
| 23 | + color: #ff0000 ; | ||
| 24 | + margin: 16px 0px 16px 0px ; | ||
| 25 | + padding: 15px 25px 15px 25px ; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + form { | ||
| 29 | + display: flex ; | ||
| 30 | + | ||
| 31 | + > * { | ||
| 32 | + margin-right: 10px ; | ||
| 33 | + } | ||
| 34 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments