Implement OAuth in a Web Server Application

A Web Server Application runs on a server and delivers a user interface in a web browser that users interact with. It is a confidential client that uses the Authorization Code grant type to request an access token, as described below.

Step 1: Obtain Client Credentials

Your Web Server Application will be registered as a confidential client and you will receive client credentials in the form of a Client ID and Client Secret.

These credentials must be kept confidential and must not be shared with anyone outside of your organization.

Step 2: Redirect the User to the Authorization Endpoint

When a user of your Web Server Application wants to access their data, redirect them to the authorization endpoint of the Lobby as follows:

https://<LOBBY>/auth/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URL>

Here is an example:

https://constructionandengineering.oraclecloud.com/auth/authorize?response_type=code&client_id=MyClientId&redirect_uri=https://myapp.com/oauth/callback

Step 3: User Authentication and Consent

The Lobby responds to this request by prompting the user to sign in with their Oracle Primavera Cloud account credentials, if they are not already logged in.

The user authorizes your application to access their Primavera Cloud data by the act of authenticating their account.

Step 4: Receive the Authorization Code

The Lobby returns an Authorization Code to the specified redirect URL, as follows:

<REDIRECT_URUL>?code=<AUTHORIZATION_CODE>

Here is an example:

https://myapp.com/oauth/callback?code=TXlBdXRob3JpemF0aW9uQ29kZQ

Step 5: Exchange the Authorization Code for an Access Token

Your application exchanges the Authorization Code for an Access Token and Refresh Token by making a POST request to the token endpoint of the Lobby specifying the client credentials using Basic Authentication ( Base64 encoding of the Client ID and Secret joined by a colon ':'), as follows:

POST https://<LOBBY>/auth/token
 
Headers:
  Content-Type: application/x-www-form-urlencoded
  Authorization: Basic <BASE_64_ENCODED_CLIENT_CREDENTIALS>
 
Body:
  grant_type=authorization_code
  code=<AUTHORIZATION_CODE>
  redirect_uri=<REDIRECT_URL>

Here is an example curl request:

curl --request POST 'https://constructionandengineering.oraclecloud.com/auth/token' \
--header 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' \
--header 'Authorization: Basic TXlDbGllbnRJRDpNeUNsaWVudFNlY3JldA==' \
--data 'grant_type=authorization_code' \
--data 'code=TXlBdXRob3JpemF0aW9uQ29kZQ' \
--data 'redirect_uri=https://myapp.com/oauth/callback'

The response is in JSON format and contains the access token, expiration time of the access token and refresh token.

Here is an example response:

{
    "access-token": "eyJ4NXQjUzI1NiI...KtK5elB38rcAbgFtVP9A",
    "token-type": "Bearer",
    "expires-in": 7200,
    "refresh_token": "TXlSZWZyZXNoVG9rZW4="
}

Step 6: Use the Access Token

Use the Access Token to make authorized requests to Primavera Cloud APIs on behalf of the authenticated user by including it in the Authorization header of your HTTP requests, as follows:

Authorization: Bearer <ACCESS_TOKEN>

Here is an example curl request:

curl 'https://primavera-eu1.oraclecloud.com/api/restapi/project/{projectId}' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer eyJ4NXQjUzI1NiI...KtK5elB38rcAbgFtVP9A'

Step 7: Refresh the Access Token

When the Access Token expires, request a new access token without requiring the user to authenticate by making a POST request to the token endpoint of the Lobby, as follows:

POST https://<LOBBY>/auth/token
 
Headers:
  Content-Type: application/x-www-form-urlencoded
  Authorization: Basic <BASE_64_ENCODED_CLIENT_CREDENTIALS>
 
Body:
  grant_type=refresh_token
  refresh_token=<REFRESH_TOKEN>

Here is an example curl request:

curl --request POST 'https://constructionandengineering.oraclecloud.com/auth/token' \
--header 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' \
--header 'Authorization: Basic TXlDbGllbnRJRDpNeUNsaWVudFNlY3JldA==' \
--data 'grant_type=refresh_token' \
--data 'refresh_token=TXlSZWZyZXNoVG9rZW4='

The response is the same as the original token response, including a new access token, access token expiry and new refresh token.

(Optional) Proof Key for Code Exchange (PKCE)

Proof Key for Code Exchange (PKCE) is an optional additional security protocol for use with Authorization Code flows. It helps prevent interception of the authorization code by malicious actors. PKCE involves the client generating a random secret (called a code verifier) and creating a derived value (called a code challenge) from it using a transform function. The code challenge is sent to the Lobby during the initial authorization request, while the code verifier is kept secret. When the Authorization Code is returned, the client provides the code verifier to prove its identity and exchanges the Authorization Code for an access token. For more details, see RFC 7636.

PKCE is not required for Web Server Applications, but it has been recommended by various authors for use in all Authorization Code flows.

If you choose to implement PKCE, follow the steps described below.

  1. Generate a random code verifier, which is a high-entropy cryptographic random string of between 43-128 characters.
  2. Create a code challenge by applying a cryptographic hash function like SHA-256 to the code verifier. Encode the result as URL-safe Base64.

For testing purposes, you can use the helper utility at https://example-app.com/pkce to generate the required values.

Here is an example using JavaScript:

const crypto = require('crypto');
// Generate a random code verifier
const codeVerifier = base64URLEncode(crypto.randomBytes(48));
// Create a code challenge using SHA-256
const codeChallenge = base64URLEncode(crypto.createHash('sha256').update(codeVerifier).digest());
function base64URLEncode(buffer) {
    return buffer.toString('base64')
        .replace(/=/g, '')
        .replace(/\+/g, '-')
        .replace(/\//g, '_');
}

3.When your application redirects the User to the Authorization Endpoint, include the code challenge and code challenge method as follows:

https://<LOBBY>/auth/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URL>&code_challenge=<CODE_CHALLENGE>&code_challenge_method=<CODE_CHALLENGE_METHOD>

Here is an example:

https://constructionandengineering.oraclecloud.com/auth/authorize?response_type=code&client_id=MyClientId&redirect_uri=https://myapp.com/oauth/callback&code_challenge=mS8J4mBfBb-6Qh8VdcP4XyDG0g0-URpKVTzIltVt5-2k&code_challenge_method=S256

4.When your application exchanges the Authorization Code for an Access Token, include the code verifier as follows:

POST https://<LOBBY>/auth/token
 
Headers:
 Content-Type: application/x-www-form-urlencoded
 
Body:
client_id=<CLIENT_ID>
grant_type=authorization_code
code=<AUTHORIZATION_CODE>
code_verifier=<CODE_VERIFIER>
redirect_uri=<REDIRECT_URI>

Here is an example curl request:

curl --request POST 'https://constructionandengineering.oraclecloud.com/auth/token' \
--header 'Content-Type: application/x-www-form-urlencoded;charset=UTF-8' \
--data 'client_id=MyClientId' \
--data 'grant_type=authorization_code' \
--data 'code=TXlBdXRob3JpemF0aW9uQ29kZQ' \
--data 'code_verifier=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM' \
--data 'redirect_uri=https://myapp.com/oauth/callback'

(Optional) State Parameter

The state parameter is an optional security measure to prevent Cross-Site Request Forgery (CSRF) attacks. It's a random value generated by the client and used to verify the integrity of the authorization process. The Lobby includes this value when redirecting back to the client with the Authorization Code.

If you choose to make use of the state parameter, follow the steps described below.

Generate a random, unique value in your client application.

Include this value in the authorization request sent to the Lobby as follows:

https://<LOBBY>/auth/authorize?response_type=code&client_id=<CLIENT_ID>&redirect_uri=<REDIRECT_URI>&state=<STATE>

Here is an example:

https://constructionandengineering.oraclecloud.com/auth/authorize?response_type=code&client_id=MyClientId&redirect_uri=https://myapp.com/oauth/callback&state=TXlTdGF0ZQ

When your application receives the OAuth response, check that the state parameter in the response matches the previously sent. It will be returned as follows:

<REDIRECT_URI>?code=<AUTHORIZATION_CODE>&state=<STATE>

Here is an example:

https://myapp.com/oauth/callback?code=TXlBdXRob3JpemF0aW9uQ29kZQ&state=TXlTdGF0ZQ

If they match, proceed with the authorization process. If they don't, consider it a potential security breach, reject the response, invalidate the state parameter, and generate a new one for the next authorization request.