Learn About Authentication Between Python Applications and Oracle Identity Cloud Service

You’re ready to learn about authentication between Python web applications and Oracle Identity Cloud Service. This includes understanding the following:

  • Use cases for using an SDK with a Python application to authenticate with Oracle Identity Cloud Service.

  • The three-legged authentication flow that Oracle Identity Cloud Service supports for the Python SDK

  • Methods and functions of the Python SDK

Learn About Three-Legged Authentication Flows

Oracle Identity Cloud Service supports the three-legged authentication flow for the Python SDK. In this flow, users interact directly with Oracle Identity Cloud Service. After a user signs in, Oracle Identity Cloud Service issues an authorization code that the SDK exchanges for a user access token. This access token can be used by the Python application to grant users access to the protected resources in the application. The three-legged flow uses the authorization code grant type.

For increased security, Oracle recommends that you use three-legged flows to integrate your Python web applications with Oracle Identity Cloud Service for authentication. By using the authorization code grant type, you can also access other applications that are protected by Oracle Identity Cloud Service without having to reauthenticate.

Learn About the Primary Use Cases for Using an SDK with a Python Application

The Python web application implements two use cases: one for authenticating users and the other for accessing detailed information about the user who is logged in.

The following data flow diagrams illustrate the flow of events, calls, and responses between the web browser, the web application, and Oracle Identity Cloud Service for each use case.

Figure - Use Case 1: User Authentication

Description of Figure - follows
Description of "Figure - Use Case 1: User Authentication"

The data flow happens this way:

  1. The user requests a protected resource.

  2. The authentication module uses the SDK to generate a request-authorization-code URL for Oracle Identity Cloud Service and send this URL as a redirect response to the web browser.

  3. The web browser calls the URL.

  4. The Oracle Identity Cloud Service Sign In page appears.

  5. The user submits their Oracle Identity Cloud Service sign-in credentials.

  6. After the user logs in successfully, Oracle Identity Cloud Service creates a session for the user and issues an authorization code.

  7. The web application makes a back-end (or server-to-server) call to exchange the authorization code for a user access token.

  8. Oracle Identity Cloud Service issues the access token.

  9. A session is established, and the user is redirected to the Home page.

  10. The Home page of the web application appears.

Figure - Use Case 2: Get User Details

Description of Figure - follows
Description of "Figure - Use Case 2: Get User Details"

The data flow happens this way:

  1. The user requests the /myProfile resource.

  2. The web application calls Oracle Identity Cloud Service using the SDK, which uses the access token that’s stored in the user session as a parameter.

  3. The user's details are sent to the web application as a JSON object.

  4. The My Profile page renders the JSON object as HTML content.

Learn About Methods and Functions of the Python SDK

The Python SDK is available as two python files, IdcsClient.py and Constants.py, which you must include in your web application. These python files are dependent on third-party libraries that also must be included in your application. To include them, run the following pip install commands:

pip install simplejson==3.13.2
pip install cryptography==2.1.4
pip install PyJWT==1.5.2
pip install requests==2.18.4
pip install six==1.10.0
pip install py3_lru_cache==0.1.6

This sample web application was developed by using the Python DJango framework, which implements URL routes in the form of functions.

The Python SDK requires a JSON variable that’s loaded with Oracle Identity Cloud Service connection information. The Python web application uses a config.json file that provides the following information.

//Oracle Identity Cloud Service connection parameters as a json var
{
   "ClientId" : "clientid",
   "ClientSecret" : "clientsecret",
   "BaseUrl" : "https://idcs-1234.identity.oraclecloud.com",
   "AudienceServiceUrl" : "https://idcs-1234.identity.oraclecloud.com",
   "TokenIssuer" : "https://identity.oraclecloud.com",
   "scope" : "urn:opc:idm:t.user.me openid",
   "redirectURL": "http://localhost:8000/callback",
   "logoutSufix":"/oauth2/v1/userlogout"
}

Below is a brief explanation of each required attribute for this SDK:

Table - Required Attributes for the Python SDK

Attribute Name Attribute Description
ClientId The value of the client ID that’s generated after you register the web application by using the Oracle Identity Cloud Service console.
ClientSecret The value of the client secret that’s generated after you register the web application using the Oracle Identity Cloud Service console.
BaseUrl The domain URL of your Oracle Identity Cloud Service instance.
AdminServiceUrl The domain name URL of your Oracle Identity Cloud Service instance. This is usually the same as BaseUrl.
TokenIssuer Keep the value as presented here.
scope The scope controls the data that the application can access or process on behalf of the user. Because the application uses the SDK for authentication, the scope is openid. The application also implements the get user details use case, for which you must also use the scope urn:opc:idm:t.user.me.

The logoutSufix and redirectURL attributes are both used by the application. Therefore, they aren’t required by the SDK.

The application implements the auth function definition, which maps the /auth URL. When a user authenticates with Oracle Identity Cloud Service, the browser makes a request to this URL.

The auth function initializes the Authentication Manager, uses the JSON configuration attributes as parameters, uses the SDK to generate the Oracle Identity Cloud Service authorization code URL, and then redirects the browser to this URL.

#Loading the SDK Python file.
from . import IdcsClient
 
#Function used to load the configurations from the config.json file
def getOptions():
    fo = open("config.json", "r")
    config = fo.read()
    options = json.loads(config)
    return options
 
# Definition of the /auth route
def auth(request):
    #Loading the configurations
    options = getOptions()
    #Authentication Manager loaded with the configurations.
    am = IdcsClient.AuthenticationManager(options)
    #Using Authentication Manager to generate the Authorization Code URL, passing the 
    #application's callback URL as parameter, along with code value and code parameter.
    url = am.getAuthorizationCodeUrl(options["redirectURL"], options["scope"], "1234", "code")
    #Redirecting the browser to the Oracle Identity Cloud Service Authorization URL.
    return HttpResponseRedirect(url)

The following parameters are used to generate the authorization code URL:

Table - Parameters used to generate the authorization code URL

Parameter Name Parameter Description
options["redirectURL"] After successful sign in, Oracle Identity Cloud Service redirects the user’s web browser to this URL. This URL must match the one that you’ll configure for the trusted application in the Oracle Identity Cloud Service console.
options["scope"] The OAuth or OpenID Connect scope of authentication. This application requires only openid authentication.
state The web application uses this code to check whether communication can be established to Oracle Identity Cloud Service. The parameter is defined by the OAuth protocol.
response_type The value that is required by the authorization code grant type (for example, code).

The callback function uses the authorization code URL parameter to request an access token. The access token is stored as a cookie, which is then sent to the browser for future use.

# Definition of the /callback route
def callback(request):
   code = request.GET.get('code')
   #Authentication Manager loaded with the configurations.
   am = IdcsClient.AuthenticationManager(getOptions())
   #Using the Authentication Manager to exchange the Authorization Code to an Access Token.
   ar = am.authorizationCode(code)
   #Get the access token as a variable
   access_token = ar.getAccessToken()
   #User Manager loaded with the configurations.
   um = IdcsClient.UserManager(getOptions())
   #Using the access_token value to get an object instance representing the User Profile.
   u = um.getAuthenticatedUser(access_token)
   #Getting the user details in json object format.
   displayname = u.getDisplayName()
   #The application then adds these information to the User Session.
   request.session['access_token'] = access_token
   request.session['displayname'] = displayname
   #Rendering the home page and adding displayname to be printed in the page.
   return render(request, 'sampleapp/home.html', {'displayname': displayname})

The myProfile function accesses the user's access token, calls the getAuthenticatedUser function to retrieve the user's information as JSON text, and then sends the information to the myProfile.html for rendering.

# Definition of the /myProfile route
def myProfile(request):
   #Getting the Access Token value from the session
   access_token = request.session.get('access_token', 'none')
   if access_token == 'none':
       #If the access token isn't present redirects to login page.
       return render(request, 'sampleapp/login.html')
   else:
       #If the access token is present, then loads the User Manager with the configurations.
       am = IdcsClient.UserManager(getOptions())
       #Using the access_token value to get an object instance representing the User Profile.
       u = am.getAuthenticatedUser(access_token)
       #Getting the user details in json format.
       jsonProfile = json.dumps(u.getUser())
       #Getting User information to send to the My Profile page.
       displayname = request.session.get('displayname', 'displayname')
       #Rendering the content of the My Profile Page.
       return render(request, 'sampleapp/myProfile.html', {'displayname': displayname, 'jsonProfile':jsonProfile})

To sign the user out from single-sign-on between the application and Oracle Identity Cloud Service, the Python web application implements the logout function. This function invalidates the user session and then redirects the user to Oracle Identity Cloud Service's OAuth logout URL. This URL is set up in the config.json file as the logoutSufix parameter.

# Definition of the /logout route
def logout(request):
    options = getOptions()
    url = options["BaseUrl"]
    url += options["logoutSufix"]
    del request.session['access_token']
    del request.session['displayname']
    return HttpResponseRedirect(url)