14 | This is an example app of authentication using Firebase in an Ionic 3 app. 15 |
16 |{{user.description}}
17 |23 | {{user.phoneNumber}} 24 |
25 |29 | {{user.email}} 30 |
31 |35 | {{user.provider}} 36 |
37 |
6 |
7 |
8 |
57 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rulesDirectory": [
4 | "codelyzer"
5 | ],
6 | "rules": {
7 | "align": {
8 | "options": [
9 | "parameters",
10 | "statements"
11 | ]
12 | },
13 | "array-type": false,
14 | "arrow-parens": false,
15 | "arrow-return-shorthand": true,
16 | "curly": true,
17 | "deprecation": {
18 | "severity": "warn"
19 | },
20 | "eofline": true,
21 | "import-blacklist": [
22 | true,
23 | "rxjs/Rx"
24 | ],
25 | "import-spacing": true,
26 | "indent": {
27 | "options": [
28 | "spaces"
29 | ]
30 | },
31 | "interface-name": false,
32 | "max-classes-per-file": false,
33 | "max-line-length": [
34 | true,
35 | 140
36 | ],
37 | "member-access": false,
38 | "member-ordering": [
39 | true,
40 | {
41 | "order": [
42 | "static-field",
43 | "instance-field",
44 | "static-method",
45 | "instance-method"
46 | ]
47 | }
48 | ],
49 | "no-consecutive-blank-lines": false,
50 | "no-console": [
51 | true,
52 | "debug",
53 | "info",
54 | "time",
55 | "timeEnd",
56 | "trace"
57 | ],
58 | "no-empty": false,
59 | "no-inferrable-types": [
60 | true,
61 | "ignore-params"
62 | ],
63 | "no-non-null-assertion": true,
64 | "no-redundant-jsdoc": true,
65 | "no-switch-case-fall-through": true,
66 | "no-var-requires": false,
67 | "object-literal-key-quotes": [
68 | true,
69 | "as-needed"
70 | ],
71 | "object-literal-sort-keys": false,
72 | "ordered-imports": false,
73 | "quotemark": [
74 | true,
75 | "single"
76 | ],
77 | "semicolon": {
78 | "options": [
79 | "always"
80 | ]
81 | },
82 | "space-before-function-paren": {
83 | "options": {
84 | "anonymous": "never",
85 | "asyncArrow": "always",
86 | "constructor": "never",
87 | "method": "never",
88 | "named": "never"
89 | }
90 | },
91 | "trailing-comma": false,
92 | "no-output-on-prefix": true,
93 | "no-inputs-metadata-property": true,
94 | "no-host-metadata-property": true,
95 | "no-input-rename": true,
96 | "no-output-rename": true,
97 | "typedef-whitespace": {
98 | "options": [
99 | {
100 | "call-signature": "nospace",
101 | "index-signature": "nospace",
102 | "parameter": "nospace",
103 | "property-declaration": "nospace",
104 | "variable-declaration": "nospace"
105 | },
106 | {
107 | "call-signature": "onespace",
108 | "index-signature": "onespace",
109 | "parameter": "onespace",
110 | "property-declaration": "onespace",
111 | "variable-declaration": "onespace"
112 | }
113 | ]
114 | },
115 | "use-lifecycle-interface": true,
116 | "use-pipe-transform-interface": true,
117 | "one-variable-per-declaration": false,
118 | "component-class-suffix": [true, "Page", "Component"],
119 | "directive-class-suffix": true,
120 | "directive-selector": [
121 | true,
122 | "attribute",
123 | "app",
124 | "camelCase"
125 | ],
126 | "component-selector": [
127 | true,
128 | "element",
129 | "app",
130 | "page",
131 | "kebab-case"
132 | ]
133 | , "variable-name": {
134 | "options": [
135 | "ban-keywords",
136 | "check-format",
137 | "allow-pascal-case"
138 | ]
139 | },
140 | "whitespace": {
141 | "options": [
142 | "check-branch",
143 | "check-decl",
144 | "check-operator",
145 | "check-separator",
146 | "check-type",
147 | "check-typecast"
148 | ]
149 | }
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/src/app/sign-up/sign-up.page.ts:
--------------------------------------------------------------------------------
1 | import { Component, NgZone } from '@angular/core';
2 | import { AngularFireAuth } from '@angular/fire/auth';
3 | import { Router } from '@angular/router';
4 | import { FormGroup, FormControl, Validators } from '@angular/forms';
5 | import { FirebaseAuthService } from '../firebase-auth.service';
6 | import { Subscription } from 'rxjs';
7 |
8 | @Component({
9 | selector: 'app-sign-up',
10 | templateUrl: './sign-up.page.html',
11 | styleUrls: ['./sign-up.page.scss'],
12 | })
13 | export class SignUpPage {
14 | signUpForm: FormGroup;
15 | submitError: string;
16 | authRedirectResult: Subscription;
17 |
18 | validation_messages = {
19 | 'email': [
20 | { type: 'required', message: 'Email is required.' },
21 | { type: 'pattern', message: 'Enter a valid email.' }
22 | ],
23 | 'password': [
24 | { type: 'required', message: 'Password is required.' },
25 | { type: 'minlength', message: 'Password must be at least 6 characters long.' }
26 | ]
27 | };
28 |
29 | constructor(
30 | public angularFire: AngularFireAuth,
31 | public router: Router,
32 | private ngZone: NgZone,
33 | private authService: FirebaseAuthService
34 | ) {
35 | this.signUpForm = new FormGroup({
36 | 'email': new FormControl('', Validators.compose([
37 | Validators.required,
38 | Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
39 | ])),
40 | 'password': new FormControl('', Validators.compose([
41 | Validators.minLength(6),
42 | Validators.required
43 | ]))
44 | });
45 | // Get firebase authentication redirect result invoken when using signInWithRedirect()
46 | // signInWithRedirect() is only used when client is in web but not desktop
47 | this.authRedirectResult = this.authService.getRedirectResult()
48 | .subscribe(result => {
49 | if (result.user) {
50 | this.redirectLoggedUserToProfilePage();
51 | } else if (result.error) {
52 | this.submitError = result.error;
53 | }
54 | });
55 | }
56 |
57 | // Once the auth provider finished the authentication flow, and the auth redirect completes,
58 | // redirect the user to the profile page
59 | redirectLoggedUserToProfilePage() {
60 | // As we are calling the Angular router navigation inside a subscribe method, the navigation will be triggered outside Angular zone.
61 | // That's why we need to wrap the router navigation call inside an ngZone wrapper
62 | this.ngZone.run(() => {
63 | this.router.navigate(['profile']);
64 | });
65 | }
66 |
67 | signUpWithEmail() {
68 | this.authService.signUpWithEmail(this.signUpForm.value['email'], this.signUpForm.value['password'])
69 | .then(user => {
70 | // navigate to user profile
71 | this.redirectLoggedUserToProfilePage();
72 | })
73 | .catch(error => {
74 | this.submitError = error.message;
75 | });
76 | }
77 |
78 | facebookSignUp() {
79 | this.authService.signInWithFacebook()
80 | .then((result: any) => {
81 | if (result.additionalUserInfo) {
82 | this.authService.setProviderAdditionalInfo(result.additionalUserInfo.profile);
83 | }
84 | // This gives you a Facebook Access Token. You can use it to access the Facebook API.
85 | // const token = result.credential.accessToken;
86 | // The signed-in user info is in result.user;
87 | this.redirectLoggedUserToProfilePage();
88 | }).catch((error) => {
89 | // Handle Errors here.
90 | console.log(error);
91 | });
92 | }
93 |
94 | googleSignUp() {
95 | this.authService.signInWithGoogle()
96 | .then((result: any) => {
97 | if (result.additionalUserInfo) {
98 | this.authService.setProviderAdditionalInfo(result.additionalUserInfo.profile);
99 | }
100 | // This gives you a Google Access Token. You can use it to access the Google API.
101 | // const token = result.credential.accessToken;
102 | // The signed-in user info is in result.user;
103 | this.redirectLoggedUserToProfilePage();
104 | }).catch((error) => {
105 | // Handle Errors here.
106 | console.log(error);
107 | });
108 | }
109 |
110 | twitterSignUp() {
111 | this.authService.signInWithTwitter()
112 | .then((result: any) => {
113 | if (result.additionalUserInfo) {
114 | this.authService.setProviderAdditionalInfo(result.additionalUserInfo.profile);
115 | }
116 | // This gives you a Twitter Access Token. You can use it to access the Twitter API.
117 | // const token = result.credential.accessToken;
118 | // The signed-in user info is in result.user;
119 | this.redirectLoggedUserToProfilePage();
120 | }).catch((error) => {
121 | // Handle Errors here.
122 | console.log(error);
123 | });
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/app/sign-in/sign-in.page.ts:
--------------------------------------------------------------------------------
1 | import { Component, NgZone } from '@angular/core';
2 | import { AngularFireAuth } from '@angular/fire/auth';
3 | import { FormGroup, FormControl, Validators } from '@angular/forms';
4 | import { Router } from '@angular/router';
5 | import { FirebaseAuthService } from '../firebase-auth.service';
6 | import { Subscription } from 'rxjs';
7 |
8 | @Component({
9 | selector: 'app-sign-in',
10 | templateUrl: 'sign-in.page.html',
11 | styleUrls: ['sign-in.page.scss'],
12 | })
13 | export class SignInPage {
14 | signInForm: FormGroup;
15 | submitError: string;
16 | authRedirectResult: Subscription;
17 |
18 | validation_messages = {
19 | 'email': [
20 | { type: 'required', message: 'Email is required.' },
21 | { type: 'pattern', message: 'Enter a valid email.' }
22 | ],
23 | 'password': [
24 | { type: 'required', message: 'Password is required.' },
25 | { type: 'minlength', message: 'Password must be at least 6 characters long.' }
26 | ]
27 | };
28 |
29 | constructor(
30 | public angularFire: AngularFireAuth,
31 | public router: Router,
32 | private ngZone: NgZone,
33 | private authService: FirebaseAuthService
34 | ) {
35 | this.signInForm = new FormGroup({
36 | 'email': new FormControl('', Validators.compose([
37 | Validators.required,
38 | Validators.pattern('^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$')
39 | ])),
40 | 'password': new FormControl('', Validators.compose([
41 | Validators.minLength(6),
42 | Validators.required
43 | ]))
44 | });
45 |
46 | // Get firebase authentication redirect result invoken when using signInWithRedirect()
47 | // signInWithRedirect() is only used when client is in web but not desktop
48 | this.authRedirectResult = this.authService.getRedirectResult()
49 | .subscribe(result => {
50 | if (result.user) {
51 | this.redirectLoggedUserToProfilePage();
52 | } else if (result.error) {
53 | this.submitError = result.error;
54 | }
55 | });
56 | }
57 |
58 | // Once the auth provider finished the authentication flow, and the auth redirect completes,
59 | // redirect the user to the profile page
60 | redirectLoggedUserToProfilePage() {
61 | // As we are calling the Angular router navigation inside a subscribe method, the navigation will be triggered outside Angular zone.
62 | // That's why we need to wrap the router navigation call inside an ngZone wrapper
63 | this.ngZone.run(() => {
64 | this.router.navigate(['profile']);
65 | });
66 | }
67 |
68 | signInWithEmail() {
69 | this.authService.signInWithEmail(this.signInForm.value['email'], this.signInForm.value['password'])
70 | .then(user => {
71 | // navigate to user profile
72 | this.redirectLoggedUserToProfilePage();
73 | })
74 | .catch(error => {
75 | this.submitError = error.message;
76 | });
77 | }
78 |
79 | facebookSignIn() {
80 | this.authService.signInWithFacebook()
81 | .then((result: any) => {
82 | if (result.additionalUserInfo) {
83 | this.authService.setProviderAdditionalInfo(result.additionalUserInfo.profile);
84 | }
85 | // This gives you a Facebook Access Token. You can use it to access the Facebook API.
86 | // const token = result.credential.accessToken;
87 | // The signed-in user info is in result.user;
88 | this.redirectLoggedUserToProfilePage();
89 | }).catch((error) => {
90 | // Handle Errors here.
91 | console.log(error);
92 | });
93 | }
94 |
95 | googleSignIn() {
96 | this.authService.signInWithGoogle()
97 | .then((result: any) => {
98 | if (result.additionalUserInfo) {
99 | this.authService.setProviderAdditionalInfo(result.additionalUserInfo.profile);
100 | }
101 | // This gives you a Google Access Token. You can use it to access the Google API.
102 | // const token = result.credential.accessToken;
103 | // The signed-in user info is in result.user;
104 | this.redirectLoggedUserToProfilePage();
105 | }).catch((error) => {
106 | // Handle Errors here.
107 | console.log(error);
108 | });
109 | }
110 |
111 | twitterSignIn() {
112 | this.authService.signInWithTwitter()
113 | .then((result: any) => {
114 | if (result.additionalUserInfo) {
115 | this.authService.setProviderAdditionalInfo(result.additionalUserInfo.profile);
116 | }
117 | // This gives you a Twitter Access Token. You can use it to access the Twitter API.
118 | // const token = result.credential.accessToken;
119 | // The signed-in user info is in result.user;
120 | this.redirectLoggedUserToProfilePage();
121 | }).catch((error) => {
122 | // Handle Errors here.
123 | console.log(error);
124 | });
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/app/firebase-auth.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AngularFireAuth } from '@angular/fire/auth';
3 | import { Observable, Subject, from } from 'rxjs';
4 | import { Platform } from '@ionic/angular';
5 | import { User, auth } from 'firebase/app';
6 | import { ProfileModel } from './profile/profile.model';
7 | import { filter, map, take } from 'rxjs/operators';
8 |
9 | @Injectable()
10 | export class FirebaseAuthService {
11 |
12 | currentUser: User;
13 | userProviderAdditionalInfo: any;
14 | redirectResult: Subject