Friday, January 31, 2020

How to identify root, intermediate and server certs.

Lot of us gets confuse about the certificate chain to identify which is root, intermediate and server certificate.  I tried to demonstrate it with pictorial representation to get some insight on this.

Primarily to see any domain certificate follow the process specified in the below image.



Root: The Root CA Certificate is always signed by the CA itself. The signatures of all certificates in the chain must be verified up to the Root CA Certificate.






If we notice that in the above picture Issued to and Issued by both are same because the Root CA Certificate is always signed by the CA itself.  If the issued by and Issued to both are same,then it is root cert. By decoding it we can easily identify it is root certificate.

Intermediate : Any certificate that sits between the SSL Certificate and the Root Certificate is called a chain or Intermediate Certificate. The Intermediate Certificate is the signer/issuer of the SSL  Certificate. The Root CA Certificate is the signer/issuer of the Intermediate Certificate. If the Intermediate Certificate is not installed on the server (where the SSL certificate is installed) it may prevent some browsers, mobile devices, applications, etc. from trusting the SSL certificate. 





In order to make the SSL certificate compatible with all clients, it is necessary that the Intermediate Certificate be installed.

Server/Domain certServer certificates (SSL certificates) are used to authenticate the identity of a server. When installed on a website, an SSL certificate turns the protocol on the website from HTTP to HTTPS and installs indicators that vouch for the authenticity of the website






If we notice in the above picture, the Issued by is pointing to the Intermediate cert(DigiCert SHA Secure Server CA) and Issued is pointing to Domain or Sever certificate.

This is how we establish the chaining for any certificates.

 Please find below step by to step  process to create a certificate chain.

1. Get CA signed certificate for domain.
2. Import or Download that certificate as base64.
3. Do the same for all the intermediate certificates (if more than one) and the root certificate.
4. Now create a new file. Example:  certificate_chain.crt.
5. Open that file in text editor and stack all 3 certificates on after the other and save.
1. Order of the certificates is starting from the domain and up towards the root
  • Domain cert
  • Intermediate cert 1 above domain
  • Intermediate cert 2 above that and so on
  • Root cert

2. You must include all certificates up to and including root

Example of merging certificates

-----BEGIN CERTIFICATE-----
MIIGvTCCBaWgAwIBAgIQBsyeRo2C7ECRbEpmpu+mazANBgkqhkiG9w0BAQUFADBI
[TRUNCATE]
MDEyMDAwMFowgYcxCzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDESMBAG
v+PMGxmcJcqnBrJT3yOyzxIZow==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEjzCCA3egAwIBAgIQBp4dt3/PHfupevXlyaJANzANBgkqhkiG9w0BAQUFADBh
[TRUNCATE]
slXkLGtB8L5cRspKKaBIXiDSRf8F3jSvcEuBOeLKB1d8tjHcISnivpcOd5AUUUDh
v+PMGxmcJcqnBrJT3yOyzxIZow==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
[TRUNCATE]
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

 If you want to decode certificates on your own computer, run this OpenSSL command:
openssl x509 -in certificate.crt -text -noout

Monday, January 13, 2020

Salesforce oAuth 2.0 flows with Node Js Integration.

Tried to wrap all the oAuth flows in one place and able to complete it. Sharing it to help to accelearte
the progress of your poc/project. Please tweak below code to use any flow with node
Js integration.



var sf = require('node-salesforce');
var http = require('http');
var url = require('url');
var fs = require('fs');
request = require('request');
path = require("path"),
https = require('https'), 
fs = require('fs'),  
base64url = require('base64-url'), 
nJwt = require('njwt')
const jsdom = require("jsdom");
const { JSDOM } = jsdom;

let client_Id ='3MVG9d8..z.hDcPKuO0qkcUX0IqWf.AIAsDF_dkcBYL80RvSIKADdH0svSMV_gKhpJAh1HwI4tRNfimBeuwrO';
let client_Secret='67D3847C8AC12050F369457935933CD1205A120C70E69E370B169BFC8CC3AE27';
let  sfdcURL = 'https://login.salesforce.com/services/oauth2/authorize' ;
let  tokenurl = 'https://login.salesforce.com/services/oauth2/token' ;
  
//
// OAuth2 client information can be shared with multiple connections.
//
var express = require('express');
var app = express();
var oauth2 = new sf.OAuth2({
    loginUrl : 'https://login.salesforce.com',
    clientId:client_Id,
    clientSecret:client_Secret,
    redirectUri : 'http://localhost:8000/oauth2/code'
});
//
// Get authz url and redirect to it.

//
app.get('/oauth2/auth', function(req, res) {
  res.redirect(oauth2.getAuthorizationUrl());
});

app.get('/', function (req, res) {
    res.send(`<html>
    <head>
    <style>
    ul {
      list-style-type: none;
      margin: 0;
      padding: 0;
      overflow: hidden;
      background-color: #333333;
    }
    li {
      float: left;
    }
    
    li a {
      display: block;
      color: white;
      text-align: center;
      padding: 16px;
      text-decoration: none;
    }
    
    li a:hover {
      background-color: #111111;
    }
    </style>
    </head>
    <body>
    
    <ul>
      <li><a href="http://localhost:8000/jwt">JWT Flow</a></li>
      <li><a href="http://localhost:8000/oauth2/auth">Web server</a></li>
      <li><a href="http://localhost:8000/username_password">User name and Password</a></li>
      <li><a href="http://localhost:8000/useragent">User agent</a></li>
      <li><a href="http://localhost:8000/refresh">Refresh token flow</a></li>
      <li><a href="http://localhost:8000/samlassertionaccesstoken">SAML Assertion</a></li>
      <li><a href="http://localhost:8000/device">Device flow</a></li>
      <li><a href="https://asset-tokens.herokuapp.com/">Asset token flow</a></li>
    </ul>
    
    </body>
    </html>`);
    
});
app.get('/oauth2/code', function(req, res) {
  var q = url.parse(req.url, true);
  request({   url : tokenurl+'?client_id='+
  client_Id
    +'&redirect_uri='+
          'http://localhost:8000/'+'&grant_type=authorization_code&code='+
          q.query.code+'&client_secret='+client_Secret,  
         method:'POST' 
       },
       function(err, remoteResponse, remoteBody) {
       
         res.send(remoteBody);
       } 
     );

  
});

app.get('/useragent', function (req,res){  
request({   url : sfdcURL+'?client_id='+client_Id+'&redirect_uri='+'http://localhost:8000/'+'&response_type=token',  
        method:'GET' 
      }).pipe(res); 
   
} );

/**
*  Username Password oAuth Flow
*/
app.get('/username_password', function (req,res){  

  var sfdcURL = 'https://login.salesforce.com/services/oauth2/token' ;

 let uname='David@abc.com';
 let pwd='passwordonly'

  var upurl = sfdcURL+
  '?client_id='+ client_Id+
   '&grant_type=password'+
   '&client_secret='+client_Secret+
   '&username='+uname+
   '&password='+pwd ;
 

   request({  url : upurl,  
        method:'POST' 
      },
      function(err, remoteResponse, remoteBody) {
        var sfdcResponse = JSON.parse(remoteBody); 
        res.send(sfdcResponse);
      } 
    );  
} );


function encryptUsingPrivateKey_nJWTLib (claims) {
  var absolutePath = path.resolve("pykey.pem");   
    var cert = fs.readFileSync(absolutePath );  
  var jwt_token = nJwt.create(claims,cert,'RS256'); 
  console.log(jwt_token); 
  var jwt_token_b64 = jwt_token.compact();
  console.log(jwt_token_b64);
 
  return jwt_token_b64;     
};

function getJWTSignedToken_nJWTLib(){ 

  var claims = {
    iss: '3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX',   
    sub: 'david@lightning601.com',     
    aud: 'https://login.salesforce.com',
    exp: (Math.floor(Date.now() / 1000) + (60*3))
   
  }

  return encryptUsingPrivateKey_nJWTLib(claims);
}
app.get('/jwt', function (req,res){  
  
  var sfdcURL = 'https://login.salesforce.com/services/oauth2/token' ;
  
  var sfdcUserName = 'david@lightning601.com';
  var token = getJWTSignedToken_nJWTLib(); 
    
  var paramBody = 'grant_type='+base64url.escape('urn:ietf:params:oauth:grant-type:jwt-bearer')+'&assertion='+token ; 
  var req_sfdcOpts = {  url : sfdcURL,  
              method:'POST', 
              headers: { 'Content-Type' : 'application/x-www-form-urlencoded'} ,
              body:paramBody 
            };
        
  request(req_sfdcOpts, 
    function(err, remoteResponse, remoteBody) {
      res.send(remoteBody);
    } 
  ); 
} );

/**
 * Device Authentication Flow
 */
app.get('/device', function (req,res){  


  let deviceurl = tokenurl+
  '?client_id='+ client_Id+
   '&response_type=device_code&redirect_uri=http://localhost:8000/' ;
 

   request({  url : deviceurl,  
        method:'POST' 
      },
      function(err, remoteResponse, remoteBody) {
        
        console.log(remoteBody) ;
        var sfdcResponse = JSON.parse(remoteBody); 
        var jsondata={
          "verification_uri" : sfdcResponse.verification_uri,
          "user_code" : sfdcResponse.user_code,
          "device_code" : sfdcResponse.device_code
        
        };
        console.log('@@@@@@@',jsondata) ;
        var hrefs=`http://localhost:8000/devicePol?device_code=${sfdcResponse.device_code}`;
        var step2redirect=`<html><head>${JSON.stringify(jsondata)} </head><body><a href=${hrefs}> Post authorizing in different browser/device click here: Device flow step 2 </a> </body></html>`;
        console.log(step2redirect) ;
        //res.send(JSON.parse(JSON.stringify(step2redirect)));
//${jsondata}
        res.send(step2redirect);
      } 
    );  
} ); 

/**
 *  Keep polling till device is verified using code
 */

app.get('/devicePol', function (req,res){ 
  var device_code = req.query.device_code;
  console.log('@@@@@@@@@device code@@@@@@@@@@@@',device_code);
  var devicePolurl = tokenurl+'?client_id='+ client_Id+'&code='+device_code+'&grant_type=device';
 //console.log('@@@@@@devicePolurl@@@@@@@',devicePolurl)
   request({  url : devicePolurl,  
      method:'POST' 
    },
    function(err, remoteResponse, remoteBody) {
      
      //console.log(remoteBody) ;
      var sfdcResponse = JSON.parse(remoteBody); 
      res.send(sfdcResponse);   
    } 
  );  
} ); 

 

  app.get('/samlassertionaccesstoken', function (req,res){ 
   
    let assertionvalue='PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJlc3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiB4bWxuczp4cz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEiIERlc3RpbmF0aW9uPSJodHRwczovL2xpZ2h0NjAxZGVwLWRldi1lZC5teS5zYWxlc2ZvcmNlLmNvbT9zbz0wMEQ3RjAwMDAwNEIxRXYiIElEPSJfNzAyNjBhYzItMjg0MTI0MmMiIElzc3VlSW5zdGFudD0iMjAxOS0xMi0yNlQxOToyMDozMy4xODdaIiBWZXJzaW9uPSIyLjAiPjxzYW1sMjpJc3N1ZXIgeG1sbnM6c2FtbDI9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPkF4aW9tPC9zYW1sMjpJc3N1ZXI';   tokenurl='https://light601dep-dev-ed.my.salesforce.com/services/oauth2/token';
    var samlurl = tokenurl+'?grant_type=assertion&assertion_type=urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser&assertion='+assertionvalue;
    console.log(samlurl);
      request({   url : samlurl,  
         method:'POST' 
       },
       function(err, remoteResponse, remoteBody) {
         
         //console.log(remoteBody) ;
         var sfdcResponse = JSON.parse(remoteBody); 
         console.log(sfdcResponse)
         res.send(sfdcResponse);    
       } );
      });
      app.get('/refresh', function(req, res) {
       
        let refresh_token = '5Aep8613hy0tHCYdhyHUIj3Fev55mM_VcyWVY6uxHslAKE.FvcRJitylwr4jQhZcx9Hwo7SA6lbd6f.AWbyKtfE';
        var q = url.parse(req.url, true);
        request({   url : tokenurl+'?client_id='+client_Id+'&redirect_uri='+
                'http://localhost:8000/'+'&grant_type=refresh_token&refresh_token='+
                refresh_token,  
               method:'POST' 
             },
             function(err, remoteResponse, remoteBody) {
             
               res.send(remoteBody);
             } 
           );
      
  
    
  });
   
var server = app.listen(8000, function () {
  
});

All Salesforce oAuth 2.0 flows in one place with python integration

Below code covers most of the oAuth 2.0 flows of Salesforce. Tweaking below code helps you
to implement any oAuth 2.0 flow within no time. All the Best !!

import flask
import requests
import tkinter as tk
import json
from json2html import *
from flask import request, jsonify
from base64 import urlsafe_b64encode
from datetime import datetime, timedelta
import Crypto
from flask import (
    Flask,
    render_template,
    jsonify,
)

import os
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

app = flask.Flask(__name__)
app = Flask(__name__)
app.config["DEBUG"] = TrueJWT_HEADER = '{"alg":"RS256"}'JWT_CLAIM_ISS = "3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX"JWT_CLAIM_SUB = "david@lightning601.com"JWT_CLAIM_AUD = "https://login.salesforce.com"JWT_AUTH_EP = "https://login.salesforce.com/services/oauth2/token"'''===========================Home page ============================================='''

@app.route('/', methods=["GET"])
def home():
    return "<h1> This blog is a great place to learn advanced concepts </h1>"

##############webserver first step ###########################
@app.route('/sfconnect', methods=["GET"])
def sfconnect():
    # return "<a href='https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fsalesforcedata'> Webserver flow </a>"    allflows = "<div style='background-color: #fad0c4;background-image: linear-gradient(315deg, #fad0c4 0%, #f1a7f1 74%);height:570px;width:1260px' ><div style='padding: 1em;position: absolute;'><ul style='list-style-type:disc;color: green;'>" + "<li style='color: green;font-size: 150%'>" + "<a href='https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fsalesforcedata'> Webserver flow </a>" + "</li>" + \
               "<li style='color: green;font-size: 150%'>" + "<a href='https://login.salesforce.com/services/oauth2/authorize?response_type=token&client_id=3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fsfconnect'> User agent flow </a>" + "</li>" + \
               "<li style='color: green;font-size: 150%'>" + "<a href='http://127.0.0.1:5000/unamepwd'>User name & Password flow </a>" + "</li>" + \
               "<li style='color: green;font-size: 150%'>" + "<a href='http://127.0.0.1:5000/refresh'>Refresh token flow</a>" + "</li>" + \
               "<li style='color: green;font-size: 150%'>" + "<a href='http://127.0.0.1:5000/jwtflow'>JWT Bearer flow</a>" + "</li>" + \
               "<li style='color: green;font-size: 150%'>" + "<a href='http://127.0.0.1:5000/Deviceflow'>Device flow step 1</a>" + "</li>" + \
               "<li style='color: green;font-size: 150%'>" + "<a href='http://127.0.0.1:5000/samlassertionflow'>Saml Assertion flow</a>" + "</li>"\
               "<li style='color: green;font-size: 150%'>" + "<a href='https://asset-tokens.herokuapp.com/' target = '_blank' >Asset Token flow</a>" + "</li>"+ "</ul></div></div>"
    return allflows


############################################################################################ Get token ###############################################################################################
@app.route('/salesforcedata', methods=["GET"])
def sfdata():
    print(request.args)
    if 'code' in request.args:
        code = request.args["code"]

    API_ENDPOINT = "https://login.salesforce.com/services/oauth2/token"    # r = requests.post(url=AUTHORIZE_ENDPOINT, data=dataauthorize)
    datafortoken = {'grant_type': 'authorization_code',
                    'client_id': '3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX',
                    'client_secret': 'B682A1156FF3A2CCF0E83764552CD1DD0FD2A4510577DDE69C408D80FB9F4A76',
                    'code': code,
                    'redirect_uri': 'http://localhost:5000/salesforcedata'                    }

    r = requests.post(url=API_ENDPOINT, data=datafortoken)
    sfdcres = r.text
    print("The pastebin URL is:%s" % sfdcres)

    dicdata = json.loads(sfdcres)

    # print('#############',jsondata,'$$$$$$$$$$',dicdata);
    acctkn = dicdata["access_token"]

    print('parsed access token', acctkn)

    # place your own domain name.    return getdata(dicdata["access_token"])


############################################################################# User name and password flow####################################################################################
@app.route('/unamepwd', methods=["GET"])
def username_pwd():
    API_ENDPOINT = "https://login.salesforce.com/services/oauth2/token"
    clientid = '3MVG9G9pzCUSkzZvyptQFNKyeFZLuFEuMqSNrj_gLpwyqgHTmUSLK0qb0EvWiNm6VYzLixRXeULtJZlm3LevO'    clientsec = '32B4AFDB1FD3E9B8FD62FD2333ACC9B33A65778C35634F8D618745746A2A6C86'    # data to be sent to api    data = {'grant_type': 'password',
            'client_id': clientid,
            'client_secret': clientsec,
            'username': 'David@abc.com',
            'password': 'pwdsecuritytoken'            }

    # String reqbody = 'grant_type=password&client_id='+clientid+'&client_secret='+clientsec+'&username='+'David@lightning601.com'+'&password='+'Welcome@18G841Lq4OPaBc3nvtMcGmhC5GH';
    # sending post request and saving response as response object    r = requests.post(url=API_ENDPOINT, data=data)

    # extracting response text    # sfdcres = json.dumps(r.text)    resp = json.loads(r.text)
    # return json2html.convert(json=json.loads(r.text))
    return getdata(resp["access_token"])


############################################################################# Refresh token flow#############################################################################################
@app.route('/refresh', methods=["GET"])
def refrehflow():
    API_ENDPOINT = "https://login.salesforce.com/services/oauth2/token"
    clientid = '3MVG9G9pzCUSkzZvyptQFNKyeFZLuFEuMqSNrj_gLpwyqgHTmUSLK0qb0EvWiNm6VYzLixRXeULtJZlm3LevO'    refresh_token = '5Aep8613hy0tHCYdhyHUIj3Fev55mM_VcyWVY6uxHslAKE.Fvf2x7ni.qVWP4HfxXN7ieW.wzJFXROLFe4F8cR9'  # data to be sent to api    data = {'grant_type': 'refresh_token',
            'client_id': clientid,
            'refresh_token': refresh_token
            }

    # String reqbody = 'grant_type=password&client_id='+clientid+'&client_secret='+clientsec+'&username='+'David@lightning601.com'+'&password='+'Welcome@18G841Lq4OPaBc3nvtMcGmhC5GH';
    # sending post request and saving response as response object    r = requests.post(url=API_ENDPOINT, data=data)

    # extracting response text    sfdcres = r.text
    # return json2html.convert(json=json.loads(r.text))    resp = json.loads(r.text)
    # return json2html.convert(json=json.loads(r.text))
    return getdata(resp["access_token"])


############re usable method #########################
def getdata(acctkn):
    END_POINT = "https://light601dep-dev-ed.my.salesforce.com/services/apexrest/contactsfordatabase/";

    data = {"Authorization": "Bearer " + acctkn,
            "Content-Type": "application/json"            }

    r = requests.get(END_POINT, headers=data)

    print("contacts data from salesforce:%s" % r.content)

    # dict = json.loads(r.content)
    # return r.content    return json2html.convert(json=json.loads(r.content))


def jwt_claim():
    '''    Function to package JWT Claim data in a base64 encoded string    :return:    base64 encoded jwt claims data    '''
    claim_template = '{{"iss": "{0}", "sub": "{1}", "aud": "{2}", "exp": {3}}}'    claim = urlsafe_b64encode(JWT_HEADER.encode()).decode()
    claim += "."
    # expiration_ts = (datetime.now(tz=timezone.utc) + timedelta(minutes=5)).timestamp()    expiration_ts = int((datetime.now() + timedelta(seconds=300)).timestamp())
    payload = claim_template.format(JWT_CLAIM_ISS, JWT_CLAIM_SUB, JWT_CLAIM_AUD, expiration_ts)
    print(payload)

    claim += urlsafe_b64encode(payload.encode()).decode()
    return claim


def sign_data(data):
    f = open('pykey.pem', 'r')
    print('$$$$$$$file$$$$$$$$', f)
    rsa1key = RSA.importKey(f.read())
    signer = PKCS1_v1_5.new(rsa1key)
    digest = SHA256.new()
    digest.update(data.encode())
    sign = signer.sign(digest)
    return urlsafe_b64encode(sign).decode()


def do_auth(endpoint, data):
    '''    Function to POST JWT claim to SFDC /oauth/token endpoint and receive an access_token    :return:    access token    '''
    r = requests.post(endpoint, data=data)
    return r


@app.route('/jwtflow', methods=["GET"])
def jwtflow():
    # Keeping with JWS spec, we need to remove the padding "=" characters from base64 encoded string    claim = jwt_claim().replace("=", "")

    # Keeping with JWS spec, we need to remove the padding "=" characters from base64 encoded string    signed_claim = sign_data(claim).replace("=", "")

    target_payload = claim + "." + signed_claim

    auth_payload = {"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": target_payload}
    response = do_auth(JWT_AUTH_EP, data=auth_payload)

    #  convert the text dictionary to data structure so it can be rendered as a json properly    response_text = eval(response.text)

    response_headers = eval(str(response.headers))

    return_dict = {"claim": claim, "signed_claim": signed_claim, "target_payload": target_payload,
                   "response_text": response_text, "response_headers": response_headers}
    # return jsonify(return_dict)    sfdcres = response.text
    print("The SFDC response:%s" % sfdcres)

    dicdata = json.loads(sfdcres)

    # print('#############',jsondata,'$$$$$$$$$$',dicdata);
    acctkn = dicdata["access_token"]

    print('parsed access token', acctkn)

    # place your own domain name.    return getdata(dicdata["access_token"])


#####################Device flow#######################################
@app.route('/Deviceflow', methods=["GET"])
def deviceflow():
    print(request.args)
    Deviceflowclientid = '3MVG9d8..z.hDcPKuO0qkcUX0IvjSlDS5xKC7RazmseJKnAbeQxg3zIE55yk7zvsy3NpjLIayWxNoUU3RfYz0';

    API_ENDPOINT = "https://login.salesforce.com/services/oauth2/token"
    getdevicecode = {'response_type': 'device_code',
                     'client_id': Deviceflowclientid,
                     'client_secret': 'B682A1156FF3A2CCF0E83764552CD1DD0FD2A4510577DDE69C408D80FB9F4A76',
                     'redirect_uri': 'http://localhost:5000/Deviceflowstep2'                     }

    r = requests.post(url=API_ENDPOINT, data=getdevicecode)
    sfdcres = r.text

    dicdata = json.loads(sfdcres)
    devicecode = dicdata["device_code"]
    parseddata = ''    for i in dicdata:
        parseddata = parseddata+"<tr><th>" + str(i) + "</th><td>" + str(dicdata[i]) + "</td></tr>"    parseddata = "<table border='1' style='color:blue;background-color:gold;'><tbody>" + parseddata + "</tbody></table>"    stepsbeforegettingtoken="Before clicking below link, take the verification uri <b style='color:red'>{}</b> and enter it into another device(Mobile/Deskstop)/n and then enter User code <b style='color:red'>{}</b>".format(str(dicdata['verification_uri']),str(dicdata['user_code']))
    step2link = "<br/><br/><b style='color:Green'>"+stepsbeforegettingtoken+"</b><br/><h2><a href = " + "http://127.0.0.1:5000/Deviceflowstep2?devicecode=" + devicecode + "> Device flow step 2 (Get access token) " + "</h2>"    parseddata = parseddata + step2link
    return parseddata

###################################
#####################Device flow#######################################
@app.route('/Deviceflowstep2', methods=["GET"])
def deviceflowstep2():
    print('####################', request.args)
    # return request.args.devicecode
    dicdata = json.dumps(request.args)
    # devicecode = dicdata["devicecode"]    print(dicdata)

    dicdata = json.loads(dicdata)
    Deviceflowclientid = '3MVG9d8..z.hDcPKuO0qkcUX0IvjSlDS5xKC7RazmseJKnAbeQxg3zIE55yk7zvsy3NpjLIayWxNoUU3RfYz0';

    API_ENDPOINT = "https://login.salesforce.com/services/oauth2/token"    # r = requests.post(url=AUTHORIZE_ENDPOINT, data=dataauthorize)
    getdevicecode = {'grant_type': 'device',
                     'client_id': Deviceflowclientid,
                     'code': dicdata['devicecode']
                     }

    r = requests.post(url=API_ENDPOINT, data=getdevicecode)
    sfdcres = r.text

    dicdata = json.loads(sfdcres)
    acctkn = dicdata["access_token"]

    print('parsed access token', acctkn)


    return json2html.convert(json=json.loads(r.content))


#########################################################################################



def samlflow(entries):

    assertion=str(entries['assertion'].get())
    API_ENDPOINT = "https://light601dep-dev-ed.my.salesforce.com/services/oauth2/token"    # r = requests.post(url=AUTHORIZE_ENDPOINT, data=dataauthorize)    import base64

    data=str(entries['assertion'].get())
    getdevicecode = {'grant_type': 'assertion',
                     'assertion_type': 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:browser',
                     'assertion': data}
    r = requests.post(url=API_ENDPOINT, data=getdevicecode)
    sfdcres = r.text
    print('##################',sfdcres)
    dicdata = json.loads(sfdcres)
    acctkn = dicdata["access_token"]

    print('parsed access token', acctkn)

    return json2html.convert(json=json.loads(r.content))


def makeform(root, fields):
    entries = {}
    for field in fields:
        print(field)
        row = tk.Frame(root)
        lab = tk.Label(row, width=22, text=field+": ", anchor='w')
        ent = tk.Entry(row)
        ent.insert(0, "0")
        row.pack(side=tk.TOP,
                 fill=tk.X,
                 padx=5,
                 pady=5)
        lab.pack(side=tk.LEFT)
        ent.pack(side=tk.RIGHT,
                 expand=tk.YES,
                 fill=tk.X)
        entries[field] = ent
    return entries

@app.route('/samlassertionflow', methods=["GET"])
def samlassertionflow():
    app = flask.Flask(__name__)
    app = Flask(__name__)
    root = tk.Tk()
    fields = ('assertion', 'End point')
    ents = makeform(root, fields)
    b1 = tk.Button(root, text='Saml assertion flow',
           command=(lambda e=ents: samlflow(e)))
    b1.pack(side=tk.LEFT, padx=5, pady=5)

    root.mainloop()

    return 'Proceed with the generated input interface'


#########################################################################################
if __name__ == "__main__":
    port = int(os.getenv("PORT", 5000))
    # Run the app, listening on all IPs with our chosen port number    app.run(host="0.0.0.0", port=port, debug=True, use_reloader=True)

app.run()

Salesforce JWT Flow with Python to retrieve and insert data into SQL.

We can use below code to fetch the data from SF via JWT flow from python and insert it into 
Database.In case if you want to schedule your python program to retrieve the data from SF to
take the backup of your data you can refer this link 
"https://datatofish.com/python-script-windows-scheduler/" to learn how to schedule 
any python program from Windows. 

Note: You need to tweak your code according to your Salesforce connected app settings like 
consumerkey and certificates and username of your SF.



import flask
import requests
import tkinter as tk
import json
from json2html import *
import mysql.connector
from flask import request, jsonify
from base64 import urlsafe_b64encode
from datetime import datetime, timedelta
from mysql.connector import Error
from mysql.connector import errorcode
import Crypto
from flask import (
    Flask,
    render_template,
    jsonify,
)

import os
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

app = flask.Flask(__name__)
app = Flask(__name__)
app.config["DEBUG"] = TrueJWT_HEADER = '{"alg":"RS256"}'JWT_CLAIM_ISS = "3MVG9d8..z.hDcPKuO0qkcUX0IncIWJdRX90Yc5BHsYUmbsHh8eeRweKXys8392v5gcuiK1_WHF3_zSS9rfoX"JWT_CLAIM_SUB = "david@abc.com"JWT_CLAIM_AUD = "https://login.salesforce.com"JWT_AUTH_EP = "https://login.salesforce.com/services/oauth2/token"
@app.route('/', methods=["GET"])
def home():
    return "<h1> This blog is a great place to learn advanced concepts </h1>"

@app.route('/sfconnect', methods=["GET"])
def sfconnect():
    # return "     allflows = "<div style='background-color: #fad0c4;background-image: linear-gradient(315deg, #fad0c4 0%, #f1a7f1 74%);height:570px;width:1260px' ><div style='padding: 1em;position: absolute;'><ul style='list-style-type:disc;color: green;'>" + \
   "<li style='color: green;font-size: 150%'>" + "<a href='http://127.0.0.1:5000/jwtflow'>JWT Bearer flow</a>" + "</li>" + "</ul></div></div>"     return allflows

############re usable method #########################
def getdata(acctkn):
    END_POINT = "https://light601dep-dev-ed.my.salesforce.com/services/apexrest/contactsfordatabase/";

    data = {"Authorization": "Bearer " + acctkn,
            "Content-Type": "application/json"            }

    r = requests.get(END_POINT, headers=data)
    r2= json.loads(r.content)
    print("###test#### get typeof from salesforce:%s", type(r2))
    sf_data = r.content
    data=r2
    print("###test123####contacts data from salesforce:%s",data)
    mydb = mysql.connector.connect(
        host="127.0.0.1",
        user="root",
        passwd="password",
        database="salesforcedata",auth_plugin='mysql_native_password')
    mycursor = mydb.cursor()
    for x in data:
        sql = "INSERT INTO Contactsf (FirstName, LastName) VALUES (%s, %s)"        val = (x['FirstName'], x['LastName'])
        mycursor.execute(sql, tuple(val))
        mydb.commit()
        continue
    mycursor.close()  ## here all loops done    mydb.close()  ## close db connection
    return json2html.convert(json=json.loads(r.content))


def jwt_claim():
    '''    Function to package JWT Claim data in a base64 encoded string    :return:    base64 encoded jwt claims data    '''
    claim_template = '{{"iss": "{0}", "sub": "{1}", "aud": "{2}", "exp": {3}}}'    claim = urlsafe_b64encode(JWT_HEADER.encode()).decode()
    claim += "."
    # expiration_ts = (datetime.now(tz=timezone.utc) + timedelta(minutes=5)).timestamp()    expiration_ts = int((datetime.now() + timedelta(seconds=300)).timestamp())
    payload = claim_template.format(JWT_CLAIM_ISS, JWT_CLAIM_SUB, JWT_CLAIM_AUD, expiration_ts)
    print(payload)

    claim += urlsafe_b64encode(payload.encode()).decode()
    return claim


def sign_data(data):
    f = open('pykey.pem', 'r')
    print('$$$$$$$file$$$$$$$$', f)
    rsa1key = RSA.importKey(f.read())
    signer = PKCS1_v1_5.new(rsa1key)
    digest = SHA256.new()
    digest.update(data.encode())
    sign = signer.sign(digest)
    return urlsafe_b64encode(sign).decode()


def do_auth(endpoint, data):
    '''    Function to POST JWT claim to SFDC /oauth/token endpoint and receive an access_token    :return:    access token    '''
    r = requests.post(endpoint, data=data)
    return r


@app.route('/jwtflow', methods=["GET"])
def jwtflow():
    # Keeping with JWS spec, we need to remove the padding "=" characters from base64 encoded string    claim = jwt_claim().replace("=", "")

    # Keeping with JWS spec, we need to remove the padding "=" characters from base64 encoded string    signed_claim = sign_data(claim).replace("=", "")

    target_payload = claim + "." + signed_claim

    auth_payload = {"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer", "assertion": target_payload}
    response = do_auth(JWT_AUTH_EP, data=auth_payload)

    #  convert the text dictionary to data structure so it can be rendered as a json properly    response_text = eval(response.text)

    response_headers = eval(str(response.headers))

    return_dict = {"claim": claim, "signed_claim": signed_claim, "target_payload": target_payload,
                   "response_text": response_text, "response_headers": response_headers}
    # return jsonify(return_dict)    sfdcres = response.text
    print("The SFDC response:%s" % sfdcres)

    dicdata = json.loads(sfdcres)

    # print('#############',jsondata,'$$$$$$$$$$',dicdata);
    acctkn = dicdata["access_token"]

    print('parsed access token', acctkn)


    return getdata(acctkn)

if __name__ == "__main__":
    port = int(os.getenv("PORT", 8001))
    # Run the app, listening on all IPs with our chosen port number    app.run(host="0.0.0.0", port=port, debug=True, use_reloader=True)

app.run()