|
4 | 4 | AuthError, |
5 | 5 | Auth0User, |
6 | 6 | Credentials as CredentialsModel, |
| 7 | + SSOCredentials, |
7 | 8 | } from '../../models'; |
8 | 9 |
|
9 | 10 | // Mock HttpClient but preserve getAuthHeader |
@@ -116,6 +117,7 @@ describe('AuthenticationOrchestrator', () => { |
116 | 117 | orchestrator = new AuthenticationOrchestrator({ |
117 | 118 | clientId, |
118 | 119 | httpClient: mockHttpClientInstance as unknown as HttpClient, |
| 120 | + baseUrl: baseUrl, |
119 | 121 | }); |
120 | 122 | }); |
121 | 123 |
|
@@ -860,4 +862,90 @@ describe('AuthenticationOrchestrator', () => { |
860 | 862 | ); |
861 | 863 | }); |
862 | 864 | }); |
| 865 | + |
| 866 | + describe('sso exchange', () => { |
| 867 | + const ssoResponse = { |
| 868 | + access_token: 'session_transfer_token_value', |
| 869 | + issued_token_type: |
| 870 | + 'urn:auth0:params:oauth:token-type:session_transfer_token', |
| 871 | + token_type: 'N_A', |
| 872 | + expires_in: 120, |
| 873 | + id_token: validIdToken, |
| 874 | + refresh_token: 'new_refresh_token', |
| 875 | + }; |
| 876 | + |
| 877 | + const parameters = { |
| 878 | + refreshToken: 'a refresh token of a user', |
| 879 | + }; |
| 880 | + |
| 881 | + it('should send correct payload with session_transfer audience', async () => { |
| 882 | + mockHttpClientInstance.post.mockResolvedValueOnce({ |
| 883 | + json: ssoResponse, |
| 884 | + response: new Response(null, { status: 200 }), |
| 885 | + }); |
| 886 | + await orchestrator.ssoExchange(parameters); |
| 887 | + |
| 888 | + expect(mockHttpClientInstance.post).toHaveBeenCalledWith( |
| 889 | + '/oauth/token', |
| 890 | + expect.objectContaining({ |
| 891 | + grant_type: 'refresh_token', |
| 892 | + client_id: clientId, |
| 893 | + refresh_token: parameters.refreshToken, |
| 894 | + audience: 'urn:samples.auth0.com:session_transfer', |
| 895 | + }), |
| 896 | + undefined |
| 897 | + ); |
| 898 | + }); |
| 899 | + |
| 900 | + it('should return SSOCredentials instance', async () => { |
| 901 | + mockHttpClientInstance.post.mockResolvedValueOnce({ |
| 902 | + json: ssoResponse, |
| 903 | + response: new Response(null, { status: 200 }), |
| 904 | + }); |
| 905 | + |
| 906 | + const result = await orchestrator.ssoExchange(parameters); |
| 907 | + |
| 908 | + expect(result).toBeInstanceOf(SSOCredentials); |
| 909 | + expect(result.sessionTransferToken).toBe(ssoResponse.access_token); |
| 910 | + expect(result.tokenType).toBe(ssoResponse.issued_token_type); |
| 911 | + expect(result.expiresIn).toBe(ssoResponse.expires_in); |
| 912 | + expect(result.idToken).toBe(ssoResponse.id_token); |
| 913 | + expect(result.refreshToken).toBe(ssoResponse.refresh_token); |
| 914 | + }); |
| 915 | + |
| 916 | + it('should handle oauth error', async () => { |
| 917 | + mockHttpClientInstance.post.mockResolvedValueOnce({ |
| 918 | + json: oauthErrorResponse, |
| 919 | + response: new Response(null, { status: 400 }), |
| 920 | + }); |
| 921 | + |
| 922 | + await expect(orchestrator.ssoExchange(parameters)).rejects.toThrow( |
| 923 | + AuthError |
| 924 | + ); |
| 925 | + }); |
| 926 | + |
| 927 | + it('should pass custom headers', async () => { |
| 928 | + mockHttpClientInstance.post.mockResolvedValueOnce({ |
| 929 | + json: ssoResponse, |
| 930 | + response: new Response(null, { status: 200 }), |
| 931 | + }); |
| 932 | + await orchestrator.ssoExchange({ |
| 933 | + refreshToken: 'a refresh token', |
| 934 | + headers: { 'X-Custom-Header': 'custom-value' }, |
| 935 | + }); |
| 936 | + |
| 937 | + expect(mockHttpClientInstance.post).toHaveBeenCalledWith( |
| 938 | + '/oauth/token', |
| 939 | + expect.objectContaining({ |
| 940 | + grant_type: 'refresh_token', |
| 941 | + refresh_token: 'a refresh token', |
| 942 | + }), |
| 943 | + { 'X-Custom-Header': 'custom-value' } |
| 944 | + ); |
| 945 | + }); |
| 946 | + |
| 947 | + it('should throw when refreshToken is missing', async () => { |
| 948 | + await expect(orchestrator.ssoExchange({} as any)).rejects.toThrow(); |
| 949 | + }); |
| 950 | + }); |
863 | 951 | }); |
0 commit comments