Authentication types are defined inside the SynapseInfo class, under supportedAuthTypes list. Here we can list all the supported authentication types that will be exposed to the end User in the UI, when they fill out the configuration wizard with their credentials. When a synapse doesn’t require authentication, this is commonly used in webhook only synapses, the NONE type should be used.
Depending on which credential the user selects from the UI picklist that enum will be provided in the metaConfig object. This way you can split logic for which option the synapse is using in that instance if you offer multiple authentication options.
# syntax to fetch selected authentication type self.connection.metaConfig.get('authType') """ Values that will be optut depending on the selected type: BASIC_TOKEN = 'UserPasswordToken' USER_PWD = 'UserPassword' API_KEY = 'ApiKey' OAUTH = 'Oauth' SIMPLE_OAUTH = 'SimpleOAuth' NONE = 'None' """
Below are example use cases of different authentication types.
Api Key
API Key (ApiKey) authentication is meant to be used where there is a single key or token used for the API authentication. This can be used for cases like API Keys or long lived bearer tokens.
Example synapse_info method:
def synapse_info(self): return SynapseInfo( name='synapse_name', category='category', metadata=UIMetadata(displayName='Synapse Name'), supportedAuthTypes=[AuthMetadata(authType=AuthType.API_KEY, label='API Key', fields=[AuthField(name='token', label='API Key', dataType=DataType.PASSWORD)])], configuredFields=[AuthField(name='endpoint', label='Endpoint URL', dataType=DataType.STRING))]) I
If you are integrating with a system that requires an API key in the URL, you can append the key / token at the end of each endpoint using the persisting connection object:
self.client.get(f"your-route?api_key={self.connection.authConfig.token}")
For cases where you need to provide the token inside the request headers you can create a helper method that generates the headers dictionary and pass it in each request:
def __headers(self): return {'Authentication': f"Bearer {self.connection.authConfig.token}"}
When using the SDK client you can use it to add the headers as:
self.client.get("your-route", headers=self.__headers())
oAuth 2.0
Oauth authentication type should be used for cases where the integrating system use the OAuth 2.0 authentication with Implicit Grant type. In addition to setting up the AuthMetadata object with clientSecret and clientId, we also need to set the oauthInfo object in the SynapseInfo method to define the Oauth variables in the oauthInfo object.
The Oauth object should contain:
- 'OAUTH_HOST' -> Host URL for authentication.
- 'OAUTH_URI' -> Path for iFrame.
- 'OAUTH_TOKEN_URL' -> URL to receive / refresh the bearer token.
For our partners that are using syncari embed that would need to have their clientId and secret stored on syncari side securely, please reach out to support.
def synapse_info(self) - SynapseInfo: return SynapseInfo( name='synapse_name', category='Category', metadata=UIMetadata(displayName=Synapse Name), supportedAuthTypes=[AuthMetadata(authType=AuthType.OAUTH, label='Oauth', fields=[ AuthField(name='clientId', label='Client Id', dataType=DataType.PASSWORD), AuthField(name='clientSecret', label='Client Secret', dataType=DataType.PASSWORD) ]) ], configuredFields=[ AuthField(name='endpoint', label='Endpoint URL', dataType=DataType.STRING)], oauthInfo={ 'OAUTH_HOST': 'https://xxxx.xxx.com', 'OAUTH_URI': '/oauth2/default/v1/authorize?client_id={{client_id}}&response_type=code&scope=&redirect_uri={{redirect_uri}}&state={{state}}', 'OAUTH_TOKEN_URL': 'https://xxx.xxx.com/oauth2/default/v1/token' } )
If the integrated system is using the standard Oauth, you can just set up the helper method with accessToken and our platform will take care of the rest:
def __headers(self): return {'Authentication': f"Bearer {self.connection.authConfig.accessToken}"}
When using the SDK client you can use it to add the headers as:
self.client.get("example", headers="self.__headers())"></self.client.get("example",>
If the system you are integrating with uses the Implicit Grant but doesn’t follow standards of oAUth 2.0 you can use get_access_token and refresh_token methods to set custom requests for both fetching the first token and refreshing it later on.
Bellow are example methods:
def get_access_token(self, oauth_request: OAuthRequest) - dict: resp = dict() get_token = self.client.post('api/oauth/token.json').json() resp['access_token'] = get_token['access_token'] resp['expires_in'] = get_token['expires_in'] resp['refresh_token'] = get_token['access_token'] return resp def refresh_token(self, connection: Connection) - dict: resp = dict() get_token = self.client.post('api/oauth/refresh_token').json() resp['access_token'] = get_token['access_token'] resp['expires_in'] = get_token['expires_in'] resp['refresh_token'] = get_token['access_token'] return resp
Simple oAuth 2.0
When you need to implement either different versions of OAUTH where they don’t require Implicit Grant type, like a system using Resource Owner Password Credentials Grant or Client Credentials Grant type, you can utilise the Simple OAUTH method.
With it you can either use the same patterns as the OAUTH one or you can also implement your own get token and refresh token methods - if the integrated system is not following standard patterns.
Commonly in these use cases the authentication would be implemented by having the test method fetching the initial access and refresh tokens and utilising only the refresh_token method.
def synapse_info(self) - SynapseInfo: return SynapseInfo( name='synapse_name', category='category', metadata=UIMetadata(displayName='Synapse Name'), supportedAuthTypes=[AuthMetadata(authType=AuthType.SIMPLE_OAUTH, label='Oauth', fields=[AuthField(name='clientId', label='Client Id', dataType=DataType.STRING), AuthField(name='clientSecret', label='Client Secret', dataType=DataType.PASSWORD)])], configuredFields=[ AuthField(name='endpoint', label='Endpoint URL', dataType=DataType.STRING, required=True)] ) def test(self, connection: Connection) - Connection: get_token = self.client.post('api/oauth/token').json() connection.authConfig.accessToken = get_token['access_token'] connection.authConfig.expiresIn = get_token['expires_in'] connection.authConfig.refreshToken = get_token['access_token'] return connection def refresh_token(self, connection: Connection) - dict: resp = dict() get_token = self.client.post('api/oauth/refresh_token').json() resp['access_token'] = get_token['access_token'] resp['expires_in'] = get_token['expires_in'] resp['refresh_token'] = get_token['access_token'] return resp
The test and refresh_token methods can be tailored to cater the integrated system’s requirements; it is only necessary to output the response back as it is in the example to the Syncari Platform.
Once this is set up you can use a similar helper method as with OAUTH to provide the bearer token in each API call:
def __headers(self): return {'Authentication': f"Bearer {self.connection.authConfig.accessToken}"}
When using the SDK client you can use it to add the headers as:
self.client.get("example", headers=self.__headers())
Username/Password
When using a SOAP API you can utilize the USER_PWD authentication type to pass the username and password variables to your SOAP client. You can use the following SynapseInfo template:
def synapse_info(self): return SynapseInfo( name='synapse_name', category='category', metadata=UIMetadata(displayName='Synapse Name'), supportedAuthTypes=[AuthMetadata(authType=AuthType.USER_PWD, label='User Name/Password', fields=[AuthField(name='userName', label='User Name', dataType=DataType.STRING), AuthField(name='password', label='Password', dataType=DataType.PASSWORD)]),], configuredFields=[AuthField(name='endpoint', label='Endpoint URL', dataType=DataType.STRING)] )
Inside your SOAP client you can use the self.connection.authConfig.userName and self.connection.authConfig.password persisting variables to access the credential values end user input in during the synapse setup.
Basic Token
With Basic_TOKEN authentication you can integrate a system that requires basic authentication. In the SynapseInfo method you can define the fields for username and password, then use the base64 encoding to create the token.
def synapse_info(self): return SynapseInfo( name='synapse_name', category='category', metadata=UIMetadata(displayName='Synapse Name'), supportedAuthTypes=[AuthMetadata(authType=AuthType.BASIC_TOKEN, label='User Name/Password', fields=[AuthField(name='userName', label='User Name', dataType=DataType.STRING), AuthField(name='password', label='Password', dataType=DataType.PASSWORD)]),], configuredFields=[AuthField(name='endpoint', label='Endpoint URL', dataType=DataType.STRING)] )
For this authentication we recommend creating the following helper method:
def __auth_headers(self): return {'Authorization': f'Basic {base64.b64encode(str.encode(self.get_access_token())).decode()}'}
And using it inside the syncari client as:
self.client.get("example", headers=self.__headers())