Skip to content

Commit

Permalink
[SDK-3238] silent signin option (#2170)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-yangy authored Sep 13, 2024
1 parent a7ab442 commit deeddd0
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 9 deletions.
14 changes: 13 additions & 1 deletion packages/passport/sdk/src/Passport.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('Passport', () => {
let getProviderSilentMock: jest.Mock;
let getLinkedAddressesMock: jest.Mock;
let linkExternalWalletMock: jest.Mock;
let forceUserRefreshMock: jest.Mock;

beforeEach(() => {
authLoginMock = jest.fn().mockReturnValue(mockUser);
Expand All @@ -67,6 +68,7 @@ describe('Passport', () => {
getProviderSilentMock = jest.fn();
getLinkedAddressesMock = jest.fn();
linkExternalWalletMock = jest.fn();
forceUserRefreshMock = jest.fn();
(AuthManager as unknown as jest.Mock).mockReturnValue({
login: authLoginMock,
loginCallback: loginCallbackMock,
Expand All @@ -75,6 +77,7 @@ describe('Passport', () => {
getDeviceFlowEndSessionEndpoint: getDeviceFlowEndSessionEndpointMock,
getUser: getUserMock,
requestRefreshTokenAfterRegistration: requestRefreshTokenMock,
forceUserRefresh: forceUserRefreshMock,
});
(MagicAdapter as jest.Mock).mockReturnValue({
login: magicLoginMock,
Expand Down Expand Up @@ -493,7 +496,7 @@ describe('Passport', () => {
expect(user).toEqual(mockUser.profile);
});

it('should login if login sliently returns error', async () => {
it('should login if login silently returns error', async () => {
getUserMock.mockRejectedValue(new Error('Unknown or invalid refresh token.'));
authLoginMock.mockReturnValue(mockUserImx);
const user = await passport.login();
Expand Down Expand Up @@ -547,6 +550,15 @@ describe('Passport', () => {
);
}
});

it('should try to login silently if silent is true', async () => {
getUserMock.mockReturnValue(null);

await passport.login({ useSilentLogin: true });

expect(forceUserRefreshMock).toBeCalledTimes(1);
expect(authLoginMock).toBeCalledTimes(0);
});
});

describe('linkExternalWallet', () => {
Expand Down
11 changes: 8 additions & 3 deletions packages/passport/sdk/src/Passport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,16 @@ export class Passport {
* @param options.useCachedSession = false - If true, and no active session exists, then the user will not be
* prompted to log in and the Promise will resolve with a null value.
* @param options.anonymousId - If provided, Passport internal metrics will be enriched with this value.
* @param options.useSilentLogin - If true, and no active session exists, then the user will not be prompted to log in. Instead, we will attempt to authenticate the user silently. This approach will fail if the user does not have an active session with the authentication server, or if user input is required (for example, consent is required).
* @returns {Promise<UserProfile | null>} the user profile if the user is logged in, otherwise null
*/
public async login(options?: {
useCachedSession: boolean;
useCachedSession?: boolean;
anonymousId?: string;
useSilentLogin?: boolean;
}): Promise<UserProfile | null> {
return withMetricsAsync(async () => {
const { useCachedSession = false } = options || {};
const { useCachedSession = false, useSilentLogin } = options || {};
let user: User | null = null;

try {
Expand All @@ -197,7 +199,10 @@ export class Passport {
}
logger.warn('Failed to retrieve a cached user session', error);
}
if (!user && !useCachedSession) {

if (!user && useSilentLogin) {
user = await this.authManager.forceUserRefresh();
} else if (!user && !useCachedSession) {
user = await this.authManager.login(options?.anonymousId);
}

Expand Down
8 changes: 4 additions & 4 deletions packages/passport/sdk/src/authManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('AuthManager', () => {

let authManager: AuthManager;
let mockSigninPopup: jest.Mock;
let mockSigninPopupCallback: jest.Mock;
let mockSigninCallback: jest.Mock;
let mockSignoutRedirect: jest.Mock;
let mockGetUser: jest.Mock;
let mockSigninSilent: jest.Mock;
Expand All @@ -94,7 +94,7 @@ describe('AuthManager', () => {

beforeEach(() => {
mockSigninPopup = jest.fn();
mockSigninPopupCallback = jest.fn();
mockSigninCallback = jest.fn();
mockSignoutRedirect = jest.fn();
mockGetUser = jest.fn();
mockSigninSilent = jest.fn();
Expand All @@ -104,7 +104,7 @@ describe('AuthManager', () => {
mockOverlayRemove = jest.fn();
(UserManager as jest.Mock).mockReturnValue({
signinPopup: mockSigninPopup,
signinPopupCallback: mockSigninPopupCallback,
signinCallback: mockSigninCallback,
signoutRedirect: mockSignoutRedirect,
signoutSilent: mockSignoutSilent,
getUser: mockGetUser,
Expand Down Expand Up @@ -365,7 +365,7 @@ describe('AuthManager', () => {
it('should call login callback', async () => {
await authManager.loginCallback();

expect(mockSigninPopupCallback).toBeCalled();
expect(mockSigninCallback).toBeCalled();
});
});

Expand Down
2 changes: 1 addition & 1 deletion packages/passport/sdk/src/authManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ export default class AuthManager {

public async loginCallback(): Promise<void> {
return withPassportError<void>(
async () => this.userManager.signinPopupCallback(),
async () => { await this.userManager.signinCallback(); },
PassportErrorType.AUTHENTICATION_ERROR,
);
}
Expand Down

0 comments on commit deeddd0

Please sign in to comment.