Apps built with Code On Time offer inherent user and role management capabilities. For public-facing apps, the initial challenge to broader user adoption lies in convincing users to create accounts. Internet users are generally reluctant to provide their credentials on multiple websites. Enterprise apps, regardless of their complexity, must integrate seamlessly with existing security systems. IT departments are unlikely to approve apps that do not provide single sign-on for their users. Your app can address both challenges effectively due to the embedded support for OAuth 2.0 Authorization.
What Is OAuth 2.0 Authorization?
OAuth 2.0 authorization is an industry-standard protocol for authorizing third-party applications to access user data. It allows users to grant access to their data without sharing their passwords with the third-party application.
OAuth 2.0 authorization works by having the user log in to their account with the identity provider (such as Google or Facebook) and then granting permission to the third-party application to access their data. Once the user has granted permission, the third-party application can access the user's data without the user having to log in again.
OAuth 2.0 authorization is a secure and convenient way for users to authorize third-party applications to access their data. It is also a flexible protocol that can be used with a variety of identity providers and third-party applications.
Preparing App for OAuth 2.0
Your custom app requires a way to track its users. Various database tables may reference the user records to indicate who created or modified data. To tailor the user experience for different audiences, you can assign app-specific roles to the users. To achieve this, you need to install the membership support in the app database. Additionally, your app needs a location to store its runtime configuration data, which can be achieved by integrating the Content Management System.
Make sure to add both the membership system and the CMS to your application database when configuring the connection string.
You need to publish your application to a public address and enable SSL support.
The configuration of a Code On Time app for OAuth 2.0 authorization is the same uniform process for any provider. For example, let's see how to configure Google as an identity provider.
Google as Identity Provider
Let’s allow users with a valid Google account to sign in to your app.
Sign in to the production version of your app with the admin account and navigate to the Site Content. Click the floating “plus” button and proceed to register the Identity Provider by selecting the corresponding option in the list.
Press the OK button to continue. When the OAuth Identity Provider configuration form opens, choose OAuth 2.0. If you have experience setting up an API development tool for OAuth 2.0, you will likely find many familiar parameters in the form.
Enter google in the Identifier field and press Enter. Click the Copy icon next to the Redirect Uri input field. The authorization server of the identity provider will send the authorization code to this URL. Keep the form open for now.
Client ID and Secret
It is time to create an OAuth client ID. For that, open another tab in the browser and visit the Google API Console to obtain OAuth 2.0 credentials such as a client ID and client secret that are known to both Google and your application.
The Google API Console is a platform for developers to build and manage API projects. It lets them create credentials, utilize APIs, and monitor usage. The console supports various API types, including public, private, and internal APIs. Additionally, it offers features like credential management, usage tracking, and API documentation.
Sign in to the console and access the Credentials in API & Services section. Click the Create Credentials button and choose the OAuth client ID option in the dropdown menu.
Set the Application Type to Web Application and enter the name for your app. Add a URI in the Authorized redirect URIs section and paste the value of the Redirect Uri of your app that is already in the clipboard.
Press the Create button and you will see the properties of the registered OAuth client application. You will need the Client ID and Client secret values to complete the configuration of the identity provider for your own app.
Do not close the form with the OAuth client parameters. The Client secret will not be available after the form is closed.
You will be able to view and change the app name and the authorized redirect URIs if necessary.
OAuth Identity Provider
Copy the Client ID to the clipboard and switch to the browser tab with the OAuth Identity Provider form. Paste the value from the clipboard into the corresponding field. Repeat the process for the Client Secret.
Complete the field in the OAuth Identity Provider form as follows:
Field
|
Value
|
Display Name
|
Google (OAuth 2.0 With PKCE)
|
Grant Type
|
Authorization Code (With PKCE)
|
Auth Uri
|
https://accounts.google.com/o/oauth2/v2/auth
|
Access Token Uri
|
https://www.googleapis.com/oauth2/v4/token
|
Revoke Uri
|
https://www.googleapis.com/oauth2/v4/revoke
|
Client Id
|
The Client ID of your app in the Google API Console.
|
Client Secret
|
The Client secret of your app in the Google API Console.
|
Code Challenge Method
|
SHA-256
|
Code Verifier
|
Leave the field value blank.
|
Scope
|
Leave the field value blank
|
Client Authentication
|
Send as Basic Auth header
|
Synchronize users
|
Enabled
|
Force users to login with this provider
|
Disabled
|
Save the form. If you reopen the identity provider record, then the OAuth Identity Provider form may look like the following.
Your own registration of Google as OAuth 2.0 identity provider will be virtually identical. The mandatory Display Name can be any user-friendly text. The Identifier is optional. Leave it blank if Google will be your only identity provider or enter an arbitrary unique alpha-numeric sequence if your app will use multiple OAuth 2.0 identity providers to authorize users.
The values of the Redirect Uri, Client Id, and Client Secret are unique to your own application. The former is a read-only value calculated by the app at runtime. The Redirect Uri will reflect the deployment address of your application.
We recommend setting the Grant Type to Authorization Code (With PKCE) to ensure the most secure method of user authentication. Set the Code Challenge Method to SHA-256 and leave the Code Verifier blank.
Authorization Code with PKCE Flow
The Authorization Code with PKCE (Proof Key for Code Exchange) flow is an OAuth 2.0 authorization flow that is designed to mitigate the risk of authorization code interception attacks. It works by using a randomly generated code verifier and challenge before exchanging the authorization code for an access token. This makes it more difficult for an attacker to intercept the authorization code and use it to obtain an access token.
Here is a brief overview of how the Authorization Code with PKCE flow works:
- The client application generates a random code verifier and calculates a code challenge from it using a cryptographic hash function.
- The client application redirects the user to the authorization server with the code challenge and other parameters.
- The user authenticates with the authorization server and grants permission to the client application to access their data.
- The authorization server generates an authorization code and redirects the user back to the client application.
- The client application exchanges the authorization code and code verifier with the authorization server for an access token.
The Authorization Code with PKCE flow is a secure and reliable way to authorize third-party applications to access user data. It is particularly useful for applications that are deployed in untrusted environments or that handle sensitive data.
Google URIs
The Auth URI points to the Google Account authorization service. Your app will redirect to the specified URL enhanced with required parameters.This will begin the authorization flow for the Google accounts. For example, the client_id parameter will identify your app, while the automatically generated code_challenge will allow the app to collect the user identity information in a secure fashion.
The Access Token URI serves as a gateway to the Google Identity API, which handles the process of obtaining and refreshing access tokens. Upon successful user authentication and authorization, the app is issued an authorization code by the authorization service. This authorization code is then utilized as a parameter within the Redirect URI previously configured in the app's Google Credentials.
The Revoke URI allows your app to notify Google that the access token is not needed anymore. This will happen when the user explicitly logs out.
Scope
By default, your app will always include the openid, email, and profile scopes in the scope parameter of the authorization URL. This instructs the authorization server to return the id_token containing the information about the user when the user grants the app access to their identity information during the sign in process.
OpenID is a decentralized authentication protocol that allows users to log in to websites and other online services using a single digital identity. Instead of creating and managing multiple usernames and passwords for different websites, users can use their OpenID to sign in to any website that supports the protocol. OpenID is designed to be secure and easy to use, and it can help to protect users from phishing attacks and other security risks.
User Authorization Flow
The standard login screen of your app will change automatically. The radio button list of identity providers is presented to the users trying to sign in. The last option in the list represents the security system of the application itself.
If there is an identity provider configured with the option to Force users to login with this provider, then the user is automatically redirected to the provider’s authorization server. Otherwise users choose their preferred method of authentication and press the Login button.
When users select Google as their authentication method, the authorization process begins. This process is controlled entirely by the identity provider vendor. If users have previously logged into other services using the same identity provider, they can skip entering their credentials and simply consent to the app accessing their identity information.
Finally, the user is redirected back to the app at the URI specified in the Redirect Url field in the identity provider configuration. Your application uses the authorization code specified in the code parameter to fetch the user identity information from Google by contacting the API specified in the Auth Token Url field of the identity provider.
The user information is received in the JSON format and includes the access_token, id_token, and optional refresh_token keys. The app will persist this information as sys/users/[USER_NAME].json “file” in the Site Content table used by the app as a general purpose CMS.
User Sign In
The id_token value specified in the user data allows your application to identify the user. Here is the sample content of the token obtained from Google.
JSON
1234567891011121314151617{
"iss": "https://accounts.google.com",
"azp": "4985749854-933kdd1o5ev29kapvid5hmn99nddddfoe1.apps.googleusercontent.com",
"aud": "4985749854-933kdd1o5ev29kapvid5hmn99nddddfoe1.apps.googleusercontent.com",
"sub": "106861556205838118498",
"hd": "idp-domain-name.com",
"preferred_username": "john.doe",
"email": "john.doe@idp-domain-name.com",
"email_verified": true,
"at_hash": "4we-xSQFZJuXPxMupn0aYA",
"name": "John Doe",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocIZcEYwKeUyxyNhdiexWrcjPHB-1oqUhUokL7mW2waO8meBeAxU=s96-c",
"given_name": "John",
"family_name": "Doe",
"iat": 1715812203,
"exp": 1715815803
}
Your app will use the preferred_username key to locate the user in the membership records. If a user with such a name exists, then the app will sign the user in. If the key is not present, then the app will attempt to locate the user with the name or email that matches the email key.
In the absence of an identity provider configured to synchronize users, the app will deny access if it cannot find the user in its membership records.
If the identity provider is configured to Synchronize users and the user is not found, then the new user account is created. The username of the new member is derived either from the preferred_username or from the email key. The password of the new member is a random sequence. The built-in membership system stores the hash value of the password, which makes the real password a complete mystery.
The picture key is the URL that allows your application to fetch the user picture and save it to the CMS.
Developers have access to the claims in the id_token through the BusinessRules.UserClaims property when writing “code” business rules.
Refresh Token
When a user successfully signs in to an app using Google as their identity provider, the app will obtain an access token that will remain valid for a short period. If the user closes the browser shortly after a successful sign-in and then accesses the app in a separate browser window within five minutes, they will automatically be logged in and won't need to sign in again. The login prompt will reappear after a longer period.
The identity provider may ask for "offline" access to the user's identity. This allows the app to refresh the access token without the user's involvement. If the user or the administrator of the authorization server revokes access to the user's identity, your app will automatically log the user out. If the authorization is still valid, user claims are automatically updated, the user will not be asked to sign in again until they log out explicitly.
The standard way to ask for a refresh token is to specify the offline_access scope. Google's authorization server requires the access_type parameter set to the offline value in the authorization URL to allow offline access to the user identity. Add this parameter in the Advanced Options of the Auth Url field in the identity provider configuration. If you have already tried signing in with this provider, then also include the prompt parameter with the consent value to ensure that the user’s authorization will be reissued.
text
12access_type=offline
prompt=consent
Note that there are advanced options associated with the Access Token Url. Developers can specify the parameters required by their authorization server for the initial token request and for the optional refresh request. The parameters may be specified in the request headers or in the body. The screenshot below shows the advanced parameters for Google account authorization. The parameters are presented as name/value pairs listed on separate lines. The app will encode the parameter values as needed at runtime.
Code On Time App as Identity Provider
In this section, we'll guide you through configuring a Code On Time application to act as an identity provider. Your application's OAuth 2.0 Identity Provider can be used with any OAuth 2.0-compliant server, such as another application built using Code On Time with its RESTful API enabled.
Apps created with Code On Time have a built-in RESTful API engine that implements a hypermedia-driven REST Level 3 API for the application data. It also implements several OAuth 2.0 Authorization flows.
Local Redirect Uri, Client Id, and Client Secret
Navigate to the Northwind application at https://demo.codeontime.com. This app was built with Code On Time and configured to expose its RESTful API to the world. Sign in with the admin credentials and navigate to the Site Content page, the content management system of the app. Click the “search” icon and find the entries containing the sys/oauth2/apps path. Select the identity consumer entry named Standalone SPA4 with RESTful Hypermedia and OAuth 2.0. This identity consumer registration record is for the app designed in the Lesson 5 of the RESTful API Workshop. We will reuse the same record to designate the Northwind application as the identity provider for our own custom app .
The Redirect Uri of the identity consumer is for the custom single-page application developed in the workshop lesson. The Local Redirect Uri of the identity consumer is a valid identity provider URI of an app created with Code On Time and running on the 60595 port at the localhost address
The identity consumer supports the Native and Server-to-Server authorization flows. The former is based on the dynamic secret and the latter relies on the static secret.
To ensure compatibility with the Northwind's "Standalone SPA4 with RESTful Hypermedia and OAuth 2.0" registration record, create a sample application using Code On Time and make certain that the Web Server configuration specifies the 60595 port.
Another option is to modify the project settings of your existing app to use the same port.
For the sample application, we will configure the OAuth 2.0 Identity Provider utilizing the Client Id and Client Secret from the Northwind's registration record.
OAuth 2.0 Endpoints
The Northwind Demo offers OAuth 2.0 RESTful API hypermedia-enhanced endpoint accessible at https://demo.codeontime.com/oauth2/v2. Hypermedia controls (authorize, token, and revoke) enable configuration of corresponding identity provider URIs. To construct the Auth Uri, Access Token Uri, and Revoke Uri of the identity provider, add the suffixes auth, token, and revoke to the endpoint respectively.
JSON
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768{
"_links": {
"self": {
"href": "/oauth2/v2"
},
"apps": {
"href": "/oauth2/v2/apps"
},
"authorize": {
"href": "/oauth2/v2/auth"
},
"token": {
"href": "/oauth2/v2/token",
"method": "POST"
},
"tokeninfo": {
"href": "/oauth2/v2/tokeninfo"
},
"userinfo": {
"href": "/oauth2/v2/userinfo",
"method": "POST"
},
"revoke": {
"href": "/oauth2/v2/revoke",
"method": "POST"
},
"authorize-client-native": {
"href": "/oauth2/v2/auth/pkce",
"method": "POST"
},
"authorize-client-spa": {
"href": "/oauth2/v2/auth/spa",
"method": "POST"
},
"authorize-server": {
"href": "/oauth2/v2/auth/server",
"method": "POST"
},
"authorize-device": {
"href": "/oauth2/v2/auth/device",
"method": "POST"
},
"schema": {
"href": "/oauth2/v2?_schema=true"
}
},
"issuer": "Northwind",
"scopes": {
"openid": {
"hint": "View the unique user id, client app id, API endpoint, token issue and expiration date."
},
"profile": {
"hint": "View the user's last and first name, birthdate, gender, picture, and preferred language."
},
"address": {
"hint": "View the user's preferred postal address."
},
"email": {
"hint": "View the user's email address."
},
"phone": {
"hint": "View the user's phone number."
},
"offline_access": {
"hint": "Access your data anytime."
}
}
}
OAuth Identity Provider
Run the sample app from Code On Time, sign in with the admin account and navigate to the Site Content. Add the new Identity Provider configured as follows:
Field
|
Value
|
Identity Provider
|
OAuth 2.0
|
Display Name
|
Northwind Demo
|
Identifier
|
northwind
|
Grant Type
|
Authorization Code (With PKCE)
|
Redirect Uri
|
http://localhost:60595/appservices/saas/oauth2-northwind
|
Auth Uri
|
https://demo.codeontime.com/oauth2/v2/auth
|
Access Token Uri
|
https://demo.codeontime.com/oauth2/v2/token
|
Revoke Uri
|
https://demo.codeontime.com/oauth2/v2/revoke
|
Client Id
|
Copy and paste the Client Id of the identity consumer record.
|
Client Secret
|
Copy and paste the Client Secret of the identity consumer record.
|
Code Challenge Method
|
SHA-256
|
Code Verifier
|
Leave the field blank.
|
Scope
|
ofline_access
|
Client Authentication
|
Send as Basic Auth header
|
Synchronize users
|
Enabled
|
Force users to login with this provider
|
Disabled
|
Save the identity provider configuration. Here is how it may look in your app.
Sign out of the sample application and choose the Login option.
User Authorization Flow
The standard login screen of your app will change. The radio button list with two options is presented to the user. The first option allows signing in with the Northwind Demo account. The second option in the list represents the security system of the application itself and allows users to sign in with the “local” account.
Choose the Northwind Demo in the Account and click the Login button. You will be redirected to the Northwind app. Proceed to sign in with the user account.
When the user enters their credentials correctly, the Northwind application displays an Account Access prompt. This prompt outlines the extent of information requested by the client app, Standalone SPA4 with RESTful Hypermedia and OAuth 2.0. Note that the name may differ from your sample app because we're reusing another application's identity consumer registration record. However, if the identity provider administrator has designated the identity consumer as Trusted, the prompt won't be shown.
If the account access is granted, then the user is redirected to the Redirect Uri specified in the authorization request, which will sign them into the sample application.
User Tokens
When a user signs in, their tokens are stored persistently. For instance, if a user named 'user' logs into the Northwind application using their credentials, a record called 'sys/users/user.json' will be created in the 'Site Content' section of the sample application. To view the contents of the CMS, log in to the sample application using the local 'admin' account. One of the records will contain the identity provider tokens. Additionally, there will be a record of the identity provider's registration and the user's profile picture retrieved from the identity provider.
The contents of the user’s identity provider tokens are shown next.
JSON
12345678910{
"access_token": "QaViPIVJ678zEw6EtpQzH~W4n6l-GK6yCJK+roxyah0Spar1fIP6TZB~DmkhyvrpXDDLzzRor07-.Ll+",
"expires_in": 900,
"token_type": "Bearer",
"id_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2RlbW8uY29kZW9udGltZS5jb20vb2F1dGgyL3YyIiwiYXpwIjoiVEt1eXplRG1JUUtXRlZuY0pjS3BDWENXRW1jc0pQM2tCOVFwdWRlZ1RyQyIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NjA1OTUvYXBwc2VydmljZXMvc2Fhcy9vYXV0aDItbm9ydGh3aW5kIiwic3ViIjoiNzc5ZTg5MGYtOWZiYi00OThmLWFjYzQtMGNmOGU2NWIxNzllIiwiaWF0IjoxNzE2MDcwODg3LCJleHAiOjE3MTYwNzE3ODcsImVtYWlsIjoidXNlckBNeUNvbXBhbnkuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsIm5hbWUiOm51bGwsImdpdmVuX25hbWUiOm51bGwsImZhbWlseV9uYW1lIjpudWxsLCJtaWRkbGVfbmFtZSI6bnVsbCwibmlja25hbWUiOm51bGwsInByZWZlcnJlZF91c2VybmFtZSI6InVzZXIiLCJwcm9maWxlIjpudWxsLCJwaWN0dXJlIjoiaHR0cHM6Ly9kZW1vLmNvZGVvbnRpbWUuY29tL29hdXRoMi92Mi91c2VyaW5mby9waWN0dXJlcy9vcmlnaW5hbC9QcndkRlIxMjd5OTJURWFlUkN2RGhMY1dUY0RjMzN3V184aVBfbEIxY3JBLmpwZWciLCJnZW5kZXIiOm51bGwsImJpcnRoZGF0ZSI6bnVsbCwiem9uZWluZm8iOiJBbWVyaWNhL0xvc19BbmdlbGVzIiwibG9jYWxlIjoiZW4tVVMiLCJ1cGRhdGVkX2F0IjpudWxsLCJzY29wZSI6Im9mZmxpbmVfYWNjZXNzIG9wZW5pZCBwcm9maWxlIGVtYWlsIn0.Xcnw4SzQNnShlvToAVkfupOflAWjXf8gC1rB3SZKNq8",
"refresh_token": "MnyiJIKD7zUQr~ppGqKpAC2RVfdUfkrV5RS-yOgtfJUHAlBlYIXZH1xgJnAB.7.C",
"scope": "offline_access openid profile email",
"picture_updated": "2024-05-18T22:21:27.9640578Z",
"expires_datetime": "2024-05-18T22:36:28.2632727Z"
}
Application uses the access_token to validate the user account and the refresh_token to refresh the access_token when it expires. The identity provider tokens are deleted when the user signs out.
User Sign In
Through the id_token content, the sample application can sign in the user. The preferred_username and email keys help identify and locate the user in the database. If no matching membership record exists, a new user account is created if the identity provider configuration specifies the Sync users option.
JSON
123456789101112131415161718192021222324{
"iss": "https://demo.codeontime.com/oauth2/v2",
"azp": "TKuyzeDmIQKWFVncJcKpCXCWEmcsJP3kB9QpudegTrC",
"aud": "http://localhost:60595/appservices/saas/oauth2-northwind",
"sub": "779e890f-9fbb-498f-acc4-0cf8e65b179e",
"iat": 1716070887,
"exp": 1716071787,
"email": "user@MyCompany.com",
"email_verified": true,
"name": null,
"given_name": null,
"family_name": null,
"middle_name": null,
"nickname": null,
"preferred_username": "user",
"profile": null,
"picture": "https://demo.codeontime.com/oauth2/v2/userinfo/pictures/original/PrwdFR127y92TEaeRCvDhLcWTcDc33wW_8iP_lB1crA.jpeg",
"gender": null,
"birthdate": null,
"zoneinfo": "America/Los_Angeles",
"locale": "en-US",
"updated_at": null,
"scope": "offline_access openid profile email"
}
Federated Identity Management
Code On Time allows creating the built-them-and-forget applications that help running various business processes. Integration of a large number of apps into enterprise with single sign-on is simple but may present a maintenance challenge. Managing users in the 3rd-party identity provider’s database is difficult, since the rich user metadata specific to your organization may not be easily described in a general purpose authorization server configuration.
Consider creating a custom app with Code On Time and designating it as an identity provider for your internal application. You can add custom associations of users with the organizational units and customer accounts. It is easy to enhance the id_token with this data. Custom apps can use this data for self-configuration purposes while your system administrators retain full control over the business configuration in a single repository.
You can implement a custom and flexible Federated Identity Management for your organization’s applications whether or not they are created with Code On Time. If you want to do it right, then do it yourself!
Better yet, register any number of external OAuth 2.0 compatible authorization servers in your custom identity provider (IdP) application. A single identity provider record will enable the Enterprise SSO for the entire application collection.