Skip to content

Custom Auth

Custom Auth Provider

For cases where you have a custom SSO and need to introspect third-party token or cookie and receive access/refresh token custom auth provider can be used.

Custom auth provider is a part of frappe_utils and can be installed as a frappe app.

Example usecase

Lets consider a case were we have a third party SSO that returns user with a cookie once logged in.

Lets register this SSO provider as Custom Auth Provider and configure its introspection.

Field Options Description
Enable Flag Enable/Disable provider
Method GET/PUT/POST Method that SSO introspection accepts
Endpoint Introspection URL SSO Provider Endpoint that the request should be made against
Header Token Type Cookie/Token/Custom Type of Authorization header
Header Token Key Token Key What header key should be token/cookie/custom be picked up from.
Response Email Map Email key path "." path to the email key in introspection response. If response will be {data: {email: "example@castlecraft.in" }}} then your key should be data.email
OAuth Client Frappe OAuth Client Linked OAuth client that the token would be generated against
Referer URL Referer key value would be verified against the the HTTP Referer
Create User Flag Create a new user if user not found
New User Name Map User Name Path "." path to the user name key in introspection response. If response will be {data: {full_name: "CEPL User" }}} then your key should be data.full_name
Roles Table Default roles that should be assigned to newly created user

image.png

How to use?

Above configured custom provider can be used consumed as follows

CURL Request

curl http://$YOUR_SITE/api/method/frappe_utils.auth.validate \
    -H 'X-FRAPPE-CUSTOM-HEADER: $CUSTOM_PROVIDER_NAME' \
    -H 'Cookie: $COOKIE_KEY=67035c53b49543d1336e4369b4201917fa808b19a019d5a44225ae88' \
    -H '$TOKEN_KEY: 67035c53b49543d1336e4369b4201917fa808b19a019d5a44225ae88' \
    -H 'Referer: $EXPECTED_REFERER'

Following request should give you a frappe token for the user linked to provided cookie/token.

CURL Response

{
    "access_token": "cf2c7650b6d7159ffb0d225ac1a33e",
    "refresh_token": "d6a0b34fa256149af536952cde0e3a",
    "expires_in": 3600
}

Permission Rules

The Permission Rules table enables the assignment of permissions to users based on specified conditions. The provided condition if evaluated and true, the corresponding Permission Rule are assigned.

Select the appropriate Permission Rule value from the Permission Rules List. Enter the desired condition for evaluation using the following syntax:

Examples

User we want to create Permission Rule A only when user has domain_id:

Permission Rule Condiion
Permission Rule A payload['data']['domain_id']

Above permission rule will only be created when domain_id is present in provider response.

User we want to create Permission Rule B only when belongs to a country country:

Permission Rule Condiion
Permission Rule A payload['data']['domain_id']
Permission Rule B payload['data']['country'] === "India"

Above permission rule will only be created when country is india for provider response.

User Mapping

User mapping is for cases when addition mapping is needed around setting user fields dynamically from the response.

Examples

User we want set First Name and Last Name of use separately from incoming full_name:

Example incoming full-name: Prafful Suthar, Nishith Singh, etc hence following configuration could be added to achieve this

User Field Mapping
First Name payload['data']['full_name'].split(" ")[0]
Last Name payload['data']['full_name'].split(" ")[1]

User we want set Language from incoming country or have a default to English:

Example incoming country: India, Null/None, etc hence following configuration could be added to achieve this

User Field Mapping
Language "Hindi" if payload['data']['country'] == "India" else "English"

Note:

Utilize the variable payload to access API response data for Permission Rule Table and User Mapping Table.

Redirect URL

Implementation

Step 1: Enter Redirect URL

To enable redirection after validation, users should enter the desired URL in the "Redirect URL" field. This URL will determine where users are redirected after successful authentication.

Step 2: Validate Endpoint

When a user tries to authenticate, instead of directly returning the token, we'll check if the "Redirect URL" field is present for the user.

  • If the "Redirect URL" field is present:
    • Token generated will be base64 encoded JSON string
    • Redirect the user to the specified URL with the token as a parameter.

Example

Let's consider an example:

  • Custom Provider with Redirect URL: "https://something.com/callback"

After generating the token user will redirect to:

  • https://something.com/callback?token=eyJhY2Nlc3NfdG9rZW4iOiAieCIsICJyZWZyZXNoX3Rva2VuOiJZIiwuLn0=

  • Received token can be caught on callback and decoded for complete token response

  • How to decode token?

    token = `eyJhY2Nlc3NfdG9rZW4iOiAiY2FmZjc2NGI5MDJmYjQzYjYwNmY5YmNmZjE4M2Y4IiwgInRva2VuX3R5cGUiOiAiQmVhcmVyIiwgImV4cGlyZXNfaW4iOiAzNjAwLCAicmVmcmVzaF90b2tlbiI6ICJiMWE5YWE0NjBhMzQ4NWUwOWQ3MWQxM2Y4MGI1NmMiLCAiZW1haWwiOiAiYW5vbnltb3VzLnVzZXJAZXhhbXBsZS5jb20ifQ==`

    decoded_token = JSON.parse(atob(token))
  • Decoded Token
    {
        "access_token": "caff764b902fb43b606f9bcff183f8",
        "token_type": "Bearer",
        "expires_in": 3600,
        "refresh_token": "b1a9aa460a3485e09d71d13f80b56c",
        "email": "anonymous.user@example.com"
    }

"Custom" type token

This specific type is for scenarios requiring customized authorization token and cookie, where dynamic header and cookie configurations are essential.

In recent integration we faced a case where user wanted to send Authorization: Bearer <X> as header to custom auth provider, following did not work as frappe middleware work with same header configurations

Hence a custom way is needed when you need to send headers bypassing frappe layer.

Example.

Lets consider a use-case where i want to send following header and cookie to my provider

'Authorization': 'Bearer TOKEN',
'cookie': "MYSAPSSO2=ABC"
my_header = {
        // if you need header
        'header' : {
            'Authorization': 'Bearer TOKEN',
        },

        // if you need cookie
        'cookie': "MYSAPSSO2=ABC"
}
value = btoa(JSON.stringify(my_header))

// log it
console.log("This is your ENCODED_TOKEN: ",value)
// copy it
copy(value)

Above will give you encoded headers.

Append above encoded headers to your get token request

curl http://$YOUR_SITE/api/method/frappe_utils.auth.validate \
    -H 'X-FRAPPE-CUSTOM-HEADER: $CUSTOM_PROVIDER_NAME' \
    -H 'X-FRAPPE-CUSTOM-VALUE: $ENCODED_TOKEN' \
    -H 'Referer: $EXPECTED_REFERER'

Following request should return you frappe token for respective user.

{
    "access_token": "cf2c7650b6d7159ffb0d225ac1a33e",
    "refresh_token": "d6a0b34fa256149af536952cde0e3a",
    "expires_in": 3600
}