Skip to content

Commit 38286f2

Browse files
authored
Missing documentation for Custom Auth (#963)
* Missing documentation for Custom Auth Closes: #934 Adds deprecation for _linkWith and _loginWith * Add 2.9.0 version * eslint specific rule * update readme and unit tests
1 parent 7ff9f92 commit 38286f2

File tree

9 files changed

+103
-56
lines changed

9 files changed

+103
-56
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ With Parse SDK 2.0.0, gone are the backbone style callbacks and Parse.Promises.
8080

8181
We have curated a [migration guide](2.0.0.md) that should help you migrate your code.
8282

83+
## 3rd Party Authentications
84+
85+
Parse Server supports many [3rd Party Authenications][3rd-parth-auth]. It is possible to [linkWith][link-with] any 3rd Party Authentication by creating a [custom authentication module][custom-auth-module].
86+
8387
## Want to ride the bleeding edge?
8488

8589
We recommend using the most recent tagged build published to npm for production. However, you can test not-yet-released versions of the Parse-SDK-JS by referencing specific branches in your `package.json`. For example, to use the master branch:
@@ -116,6 +120,8 @@ of patent rights can be found in the PATENTS file in the same directory.
116120
-----
117121
As of April 5, 2017, Parse, LLC has transferred this code to the parse-community organization, and will no longer be contributing to or distributing this code.
118122

119-
[types-parse]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/parse
120-
121-
[open-collective-link]: https://opencollective.com/parse-server
123+
[3rd-party-auth]: http://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication
124+
[custom-auth-module]:https://docs.parseplatform.org/js/guide/#custom-authentication-module).
125+
[link-with]: https://docs.parseplatform.org/js/guide/#linking-users
126+
[open-collective-link]: https://opencollective.com/parse-server
127+
[types-parse]: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/parse

integration/test/ParseUserTest.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ describe('Parse User', () => {
676676
user.setUsername('Alice');
677677
user.setPassword('sekrit');
678678
await user.signUp();
679-
await user._linkWith(provider.getAuthType(), provider.getAuthData());
679+
await user.linkWith(provider.getAuthType(), provider.getAuthData());
680680
expect(user._isLinked(provider)).toBe(true);
681681
await user._unlinkFrom(provider);
682682
expect(user._isLinked(provider)).toBe(false);
@@ -689,7 +689,7 @@ describe('Parse User', () => {
689689
user.setUsername('Alice');
690690
user.setPassword('sekrit');
691691
await user.save(null, { useMasterKey: true });
692-
await user._linkWith(provider.getAuthType(), provider.getAuthData(), { useMasterKey: true });
692+
await user.linkWith(provider.getAuthType(), provider.getAuthData(), { useMasterKey: true });
693693
expect(user._isLinked(provider)).toBe(true);
694694
await user._unlinkFrom(provider, { useMasterKey: true });
695695
expect(user._isLinked(provider)).toBe(false);
@@ -705,7 +705,7 @@ describe('Parse User', () => {
705705
expect(user.isCurrent()).toBe(false);
706706

707707
const sessionToken = user.getSessionToken();
708-
await user._linkWith(provider.getAuthType(), provider.getAuthData(), { sessionToken });
708+
await user.linkWith(provider.getAuthType(), provider.getAuthData(), { sessionToken });
709709
expect(user._isLinked(provider)).toBe(true);
710710
await user._unlinkFrom(provider, { sessionToken });
711711
expect(user._isLinked(provider)).toBe(false);
@@ -716,7 +716,7 @@ describe('Parse User', () => {
716716
user.setUsername('Alice');
717717
user.setPassword('sekrit');
718718
await user.save(null, { useMasterKey: true });
719-
await user._linkWith(provider.getAuthType(), provider.getAuthData(), { useMasterKey: true });
719+
await user.linkWith(provider.getAuthType(), provider.getAuthData(), { useMasterKey: true });
720720
expect(user._isLinked(provider)).toBe(true);
721721
expect(user.authenticated()).toBeFalsy();
722722
Parse.User.enableUnsafeCurrentUser();
@@ -729,7 +729,7 @@ describe('Parse User', () => {
729729
user.setUsername('Alice');
730730
user.setPassword('sekrit');
731731
await user.save(null, { useMasterKey: true });
732-
await user._linkWith(provider.getAuthType(), provider.getAuthData());
732+
await user.linkWith(provider.getAuthType(), provider.getAuthData());
733733
expect(user.getSessionToken()).toBeDefined();
734734
});
735735

@@ -758,7 +758,7 @@ describe('Parse User', () => {
758758
user.setUsername('Alice');
759759
user.setPassword('sekrit');
760760
await user.signUp();
761-
await user._linkWith(provider.getAuthType(), provider.getAuthData());
761+
await user.linkWith(provider.getAuthType(), provider.getAuthData());
762762
expect(user._isLinked(provider)).toBe(true);
763763
await user._unlinkFrom(provider);
764764
expect(user._isLinked(provider)).toBe(false);
@@ -812,7 +812,7 @@ describe('Parse User', () => {
812812
user.setPassword('sekrit');
813813
await user.signUp();
814814

815-
await user._linkWith('twitter', { authData });
815+
await user.linkWith('twitter', { authData });
816816

817817
expect(user.get('authData').twitter.id).toBe(authData.id);
818818
expect(user._isLinked('twitter')).toBe(true);
@@ -836,7 +836,7 @@ describe('Parse User', () => {
836836
user.setPassword('sekrit');
837837
await user.signUp();
838838

839-
await user._linkWith('twitter', { authData });
839+
await user.linkWith('twitter', { authData });
840840
await Parse.FacebookUtils.link(user);
841841

842842
expect(Parse.FacebookUtils.isLinked(user)).toBe(true);

src/AnonymousUtils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const AnonymousUtils = {
6969
*/
7070
logIn(options?: RequestOptions) {
7171
const provider = this._getAuthProvider();
72-
return ParseUser._logInWith(provider.getAuthType(), provider.getAuthData(), options);
72+
return ParseUser.logInWith(provider.getAuthType(), provider.getAuthData(), options);
7373
},
7474

7575
/**
@@ -84,7 +84,7 @@ const AnonymousUtils = {
8484
*/
8585
link(user: ParseUser, options?: RequestOptions) {
8686
const provider = this._getAuthProvider();
87-
return user._linkWith(provider.getAuthType(), provider.getAuthData(), options);
87+
return user.linkWith(provider.getAuthType(), provider.getAuthData(), options);
8888
},
8989

9090
_getAuthProvider() {

src/FacebookUtils.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ const FacebookUtils = {
170170
);
171171
}
172172
requestedPermissions = permissions;
173-
return ParseUser._logInWith('facebook', options);
173+
return ParseUser.logInWith('facebook', options);
174174
}
175175
const authData = { authData: permissions };
176-
return ParseUser._logInWith('facebook', authData, options);
176+
return ParseUser.logInWith('facebook', authData, options);
177177
},
178178

179179
/**
@@ -210,10 +210,10 @@ const FacebookUtils = {
210210
);
211211
}
212212
requestedPermissions = permissions;
213-
return user._linkWith('facebook', options);
213+
return user.linkWith('facebook', options);
214214
}
215215
const authData = { authData: permissions };
216-
return user._linkWith('facebook', authData, options);
216+
return user.linkWith('facebook', authData, options);
217217
},
218218

219219
/**

src/ParseUser.js

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,21 @@ class ParseUser extends ParseObject {
7474
}
7575

7676
/**
77-
* Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can
78-
* call linkWith on the user (even if it doesn't exist yet on the server).
77+
* Parse allows you to link your users with {@link https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication 3rd party authentication}, enabling
78+
* your users to sign up or log into your application using their existing identities.
79+
* Since 2.9.0
80+
*
81+
* @see {@link https://docs.parseplatform.org/js/guide/#linking-users Linking Users}
82+
* @param {String|AuthProvider} provider Name of auth provider or {@link https://parseplatform.org/Parse-SDK-JS/api/master/AuthProvider.html AuthProvider}
83+
* @param {Object} options
84+
* <ul>
85+
* <li>If provider is string, options is {@link http://docs.parseplatform.org/parse-server/guide/#supported-3rd-party-authentications authData}
86+
* <li>If provider is AuthProvider, options is saveOpts
87+
* </ul>
88+
* @param {Object} saveOpts useMasterKey / sessionToken
89+
* @return {Promise} A promise that is fulfilled with the user is linked
7990
*/
80-
_linkWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions = {}): Promise<ParseUser> {
91+
linkWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions = {}): Promise<ParseUser> {
8192
saveOpts.sessionToken = saveOpts.sessionToken || this.getSessionToken() || '';
8293
let authType;
8394
if (typeof provider === 'string') {
@@ -118,7 +129,7 @@ class ParseUser extends ParseObject {
118129
success: (provider, result) => {
119130
const opts = {};
120131
opts.authData = result;
121-
this._linkWith(provider, opts, saveOpts).then(() => {
132+
this.linkWith(provider, opts, saveOpts).then(() => {
122133
resolve(this);
123134
}, (error) => {
124135
reject(error);
@@ -132,6 +143,13 @@ class ParseUser extends ParseObject {
132143
}
133144
}
134145

146+
/**
147+
* @deprecated since 2.9.0 see {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith}
148+
*/
149+
_linkWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions = {}): Promise<ParseUser> {
150+
return this.linkWith(provider, options, saveOpts);
151+
}
152+
135153
/**
136154
* Synchronizes auth data for a provider (e.g. puts the access token in the
137155
* right place to be used by the Facebook SDK).
@@ -200,7 +218,7 @@ class ParseUser extends ParseObject {
200218
if (typeof provider === 'string') {
201219
provider = authProviders[provider];
202220
}
203-
return this._linkWith(provider, { authData: null }, options).then(() => {
221+
return this.linkWith(provider, { authData: null }, options).then(() => {
204222
this._synchronizeAuthData(provider);
205223
return Promise.resolve(this);
206224
});
@@ -687,8 +705,13 @@ class ParseUser extends ParseObject {
687705
return controller.hydrate(userJSON);
688706
}
689707

708+
/**
709+
* Static version of {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith}
710+
* @static
711+
*/
690712
static logInWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions) {
691-
return ParseUser._logInWith(provider, options, saveOpts);
713+
const user = new ParseUser();
714+
return user.linkWith(provider, options, saveOpts);
692715
}
693716

694717
/**
@@ -796,6 +819,17 @@ class ParseUser extends ParseObject {
796819
canUseCurrentUser = false;
797820
}
798821

822+
/**
823+
* When registering users with {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#linkWith linkWith} a basic auth provider
824+
* is automatically created for you.
825+
*
826+
* For advanced authentication, you can register an Auth provider to
827+
* implement custom authentication, deauthentication.
828+
*
829+
* @see {@link https://parseplatform.org/Parse-SDK-JS/api/master/AuthProvider.html AuthProvider}
830+
* @see {@link https://docs.parseplatform.org/js/guide/#custom-authentication-module Custom Authentication Module}
831+
* @static
832+
*/
799833
static _registerAuthenticationProvider(provider: any) {
800834
authProviders[provider.getAuthType()] = provider;
801835
// Synchronize the current user with the auth provider.
@@ -806,9 +840,13 @@ class ParseUser extends ParseObject {
806840
});
807841
}
808842

843+
/**
844+
* @deprecated since 2.9.0 see {@link https://parseplatform.org/Parse-SDK-JS/api/master/Parse.User.html#logInWith logInWith}
845+
* @static
846+
*/
809847
static _logInWith(provider: any, options: { authData?: AuthData }, saveOpts?: FullOptions) {
810848
const user = new ParseUser();
811-
return user._linkWith(provider, options, saveOpts);
849+
return user.linkWith(provider, options, saveOpts);
812850
}
813851

814852
static _clearCache() {

src/__tests__/AnonymousUtils-test.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class MockUser {
1515
this.attributes = {};
1616
}
1717
_isLinked() {}
18-
_linkWith() {}
18+
linkWith() {}
1919
static _registerAuthenticationProvider() {}
20-
static _logInWith() {}
20+
static logInWith() {}
2121
}
2222

2323
jest.setMock('../ParseUser', MockUser);
@@ -71,18 +71,18 @@ describe('AnonymousUtils', () => {
7171

7272
it('can link user', () => {
7373
const user = new MockUser();
74-
jest.spyOn(user, '_linkWith');
74+
jest.spyOn(user, 'linkWith');
7575
AnonymousUtils.link(user);
76-
expect(user._linkWith).toHaveBeenCalledTimes(1);
77-
expect(user._linkWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData(), undefined);
76+
expect(user.linkWith).toHaveBeenCalledTimes(1);
77+
expect(user.linkWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData(), undefined);
7878
expect(AnonymousUtils._getAuthProvider).toHaveBeenCalledTimes(1);
7979
});
8080

8181
it('can login user', () => {
82-
jest.spyOn(MockUser, '_logInWith');
82+
jest.spyOn(MockUser, 'logInWith');
8383
AnonymousUtils.logIn();
84-
expect(MockUser._logInWith).toHaveBeenCalledTimes(1);
85-
expect(MockUser._logInWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData(), undefined);
84+
expect(MockUser.logInWith).toHaveBeenCalledTimes(1);
85+
expect(MockUser.logInWith).toHaveBeenCalledWith('anonymous', mockProvider.getAuthData(), undefined);
8686
expect(AnonymousUtils._getAuthProvider).toHaveBeenCalledTimes(1);
8787
});
8888
});

src/__tests__/FacebookUtils-test.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ class MockUser {
1515
this.attributes = {};
1616
}
1717
_isLinked() {}
18-
_linkWith() {}
18+
linkWith() {}
1919
_unlinkFrom() {}
2020
static _registerAuthenticationProvider() {}
21-
static _logInWith() {}
21+
static logInWith() {}
2222
}
2323

2424
jest.setMock('../ParseUser', MockUser);
@@ -110,17 +110,17 @@ describe('FacebookUtils', () => {
110110
const authData = {
111111
id: '1234'
112112
};
113-
jest.spyOn(user, '_linkWith');
113+
jest.spyOn(user, 'linkWith');
114114
await FacebookUtils.link(user, authData);
115-
expect(user._linkWith).toHaveBeenCalledWith('facebook', { authData: { id: '1234' } }, undefined);
115+
expect(user.linkWith).toHaveBeenCalledWith('facebook', { authData: { id: '1234' } }, undefined);
116116
});
117117

118118
it('can link with options', async () => {
119119
FacebookUtils.init();
120120
const user = new MockUser();
121-
jest.spyOn(user, '_linkWith');
121+
jest.spyOn(user, 'linkWith');
122122
await FacebookUtils.link(user, {}, { useMasterKey: true });
123-
expect(user._linkWith).toHaveBeenCalledWith('facebook', { authData: {} }, { useMasterKey: true });
123+
expect(user.linkWith).toHaveBeenCalledWith('facebook', { authData: {} }, { useMasterKey: true });
124124
});
125125

126126
it('can check isLinked', async () => {
@@ -147,23 +147,23 @@ describe('FacebookUtils', () => {
147147

148148
it('can login with permission string', async () => {
149149
FacebookUtils.init();
150-
jest.spyOn(MockUser, '_logInWith');
150+
jest.spyOn(MockUser, 'logInWith');
151151
await FacebookUtils.logIn('public_profile');
152-
expect(MockUser._logInWith).toHaveBeenCalledTimes(1);
152+
expect(MockUser.logInWith).toHaveBeenCalledTimes(1);
153153
});
154154

155155
it('can login with authData', async () => {
156156
FacebookUtils.init();
157-
jest.spyOn(MockUser, '_logInWith');
157+
jest.spyOn(MockUser, 'logInWith');
158158
await FacebookUtils.logIn({ id: '1234' });
159-
expect(MockUser._logInWith).toHaveBeenCalledTimes(1);
159+
expect(MockUser.logInWith).toHaveBeenCalledTimes(1);
160160
});
161161

162162
it('can login with options', async () => {
163163
FacebookUtils.init();
164-
jest.spyOn(MockUser, '_logInWith');
164+
jest.spyOn(MockUser, 'logInWith');
165165
await FacebookUtils.logIn({}, { useMasterKey: true });
166-
expect(MockUser._logInWith).toHaveBeenCalledWith('facebook', { authData: {} }, {useMasterKey: true });
166+
expect(MockUser.logInWith).toHaveBeenCalledWith('facebook', { authData: {} }, {useMasterKey: true });
167167
});
168168

169169
it('provider getAuthType', async () => {

src/__tests__/ParseUser-test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -837,25 +837,25 @@ describe('ParseUser', () => {
837837
const provider = AnonymousUtils._getAuthProvider();
838838
ParseUser._registerAuthenticationProvider(provider);
839839
const user = new ParseUser();
840-
jest.spyOn(user, '_linkWith');
840+
jest.spyOn(user, 'linkWith');
841841
user._unlinkFrom(provider);
842-
expect(user._linkWith).toHaveBeenCalledTimes(1);
843-
expect(user._linkWith).toHaveBeenCalledWith(provider, { authData: null }, undefined);
842+
expect(user.linkWith).toHaveBeenCalledTimes(1);
843+
expect(user.linkWith).toHaveBeenCalledWith(provider, { authData: null }, undefined);
844844
});
845845

846846
it('can unlink with options', async () => {
847847
const provider = AnonymousUtils._getAuthProvider();
848848
ParseUser._registerAuthenticationProvider(provider);
849849
const user = new ParseUser();
850-
jest.spyOn(user, '_linkWith')
850+
jest.spyOn(user, 'linkWith')
851851
.mockImplementationOnce((authProvider, authData, saveOptions) => {
852852
expect(authProvider).toEqual(provider);
853853
expect(authData).toEqual({ authData: null});
854854
expect(saveOptions).toEqual({ useMasterKey: true });
855855
return Promise.resolve();
856856
});
857857
user._unlinkFrom(provider.getAuthType(), { useMasterKey: true });
858-
expect(user._linkWith).toHaveBeenCalledTimes(1);
858+
expect(user.linkWith).toHaveBeenCalledTimes(1);
859859
});
860860

861861
it('can destroy anonymous user when login new user', async () => {
@@ -1003,10 +1003,10 @@ describe('ParseUser', () => {
10031003
await user._linkWith('testProvider', { authData: { id: 'test' } });
10041004
expect(user.get('authData')).toEqual({ testProvider: { id: 'test' } });
10051005

1006-
jest.spyOn(user, '_linkWith');
1006+
jest.spyOn(user, 'linkWith');
10071007

10081008
await user._unlinkFrom('testProvider');
1009-
const authProvider = user._linkWith.mock.calls[0][0];
1009+
const authProvider = user.linkWith.mock.calls[0][0];
10101010
expect(authProvider.getAuthType()).toBe('testProvider');
10111011
});
10121012
});

0 commit comments

Comments
 (0)