How We Achieved Unified Profiling at VideoWiki

Aman Bishnoi
videowiki.pt
Published in
8 min readFeb 21, 2023

Hello and welcome to my article! My name is Aman Bishnoi, and I work as a Backend Developer at VideoWiki, a part of GetBoarded Technologies. I’m thrilled to share with you how we accomplished Unified Profiling at VideoWiki with the help of Ory Hydra.

Managing user profiles across various applications can be overwhelming, but with the use of Ory Hydra, an open-source identity and access management solution, we were able to simplify the process. By consolidating user profile data from different identity providers into a single user record, we were able to enhance the user experience and strengthen security. Throughout this guide, I will walk you through the steps we followed to configure Ory Hydra as an OAuth 2.0 provider, connect it to identity providers, and implement a workflow for profile unification.

Authentication Flow

OAuth2 and OpenID Connect require an authenticated End-User session for all OAuth2/OpenID Connect flows, except the client_credentials flow, which does not involve End-Users. Ory OAuth2 & OpenID Connect does not contain a database with End-Users but instead uses HTTP redirects to “delegate” the login flow to another app. We call this the Login & Consent App.

This guide uses the following URLs:

The following sequence diagram describes the different API calls and HTTP Redirects when performing the OAuth2 flow:

OAuth2 Flow Diagram

Installation

To get started, it is important to ensure that you have the latest versions of both Docker and Docker Compose installed on your system.

Navigate to the directory containing the Hydra source code and execute the following command to initiate the required containers:

docker-compose -f quickstart.yml -f quickstart-postgres.yml up - build

Creating an OAuth 2.0 Client

To create an Ory Hydra client using the HTTP API, you can use the following curl command:

curl - request POST \
- url http://localhost:4445/clients \
- header 'Content-Type: application/json' \
- data '{
"client_id": "example-client",
"client_secret": "example-secret",
"grant_types": ["client_credentials"],
"response_types": ["token"],
"redirect_uris": ["https://example.com/callback"],
"scope": "hydra.clients",
"token_endpoint_auth_method": "client_secret_post"
}'

This payload includes the necessary information to create a client, such as a client ID, client secret, allowed grant types, and redirect URIs, as well as authentication details.

After creating a client in Ory Hydra, the next step is to use the client ID and client secret to authenticate the client when making API requests to the Hydra server.

Login challenge

To obtain a login challenge in Ory Hydra, you can use the HTTP API to initiate an OAuth 2.0 flow for a specific client and user. The flow will generate a unique login challenge that can be used to track the status of the login or consent request.

Here’s an example of how to obtain a login challenge using the curl command:

curl -X GET "https://{hydra-url}/oauth2/auth?audience=&max_age=0&nonce={nonce}&prompt=&client_id={client-id}&redirect_uri={redirect-uri}&response_type=code&scope={requested-scopes}&state={state}" -H "Accept: application/json"

Accepting a Login Request

Once you have obtained a login challenge in Ory Hydra, the next step is to display the login form to the user and gather their credentials, you can utilize the /oauth2/auth/requests/login/accept endpoint to trade the login challenge for an OAuth 2.0 authorization code, access token, or ID token.

Here’s an example of a curl command that sends a POST request to the /admin/oauth2/auth/requests/login/accept endpoint in Ory Hydra:

curl -X POST \
http://localhost:4444/admin/oauth2/auth/requests/login/accept \
-H 'Content-Type: application/json' \
-d '{
"acr": "acr-value",
"amr": [
"amr-value"
],
"context": null,
"force_subject_identifier": "some-value",
"remember": true,
"remember_for": 3600,
"subject": "user@example.com"
}'
  • acr: The authentication context class reference, which indicates the level of assurance of the authentication method used to authenticate the user.
  • amr: The authentication method references, which list the specific authentication methods that were used to authenticate the user.
  • context: Additional context information that may be included in the authentication request.
  • force_subject_identifier: An identifier to force the subject to a specific value. If this is not specified, the subject identifier will be generated by Ory Hydra.
  • remember: A boolean value that indicates whether the user's session should be remembered.
  • remember_for: The duration in seconds for which the user's session should be remembered.
  • subject: The subject identifier for the authenticated user.

Here’s an example of how we can store additional user data in an access token using the context parameter in Ory Hydra:

"context": {
"id": "user-id",
"name": "user-name",
"email": "user-email"
}

In this example, the context the parameter includes the user's ID, name, and email. When the access token is issued, these values will be included in the token's payload as a JSON object under the context field.

To verify that the access token contains the additional user data, you can decode the token using a JWT decoder and examine its payload. The context the field should contain the user's ID, name, and email.

Note that storing sensitive user data in an access token is generally not recommended, as the token can be intercepted or stolen. If you need to store sensitive data, consider using a separate, encrypted data store instead.

After accepting a login request in Ory Hydra, the user may be required to provide consent before accessing the protected resource. If consent is required, Ory Hydra will return a consent challenge, which you can use to redirect the user to a consent page to provide their consent.

Accept a consent request

In Ory Hydra, after a user has successfully authenticated, they may be asked to provide consent to authorize the requested scopes. To accept a consent request, you can use the /oauth2/auth/requests/consent endpoint with the following payload:

curl --location --request PUT 'http://127.0.0.1:4445/oauth2/auth/requests/consent/accept?consent_challenge={consent_challenge}' \
--header 'Content-Type: application/json' \
--data-raw '{
"grant_scope": ["openid", "offline_access"],
"grant_access_token_audience": ["api://default"],
"remember": true,
"remember_for": 3600,
"session": {
"access_token": {
"id_token": {
"sub": "user-subject",
"name": "user-name",
"email": "user-email"
}
}
}
}'

Storing data in the ID token can include extra user details, such as name and email, reducing client requests to retrieve data. The ID token is a JWT returned in the OAuth 2.0 flow and allows the client to personalize the user experience. It’s important not to include sensitive information as the ID token is unencrypted and short-lived. The access token is preferred for authorization as it’s longer-lived and can access protected resources.

After accepting the consent request, the user will be redirected to the response URL that was provided in the original authorization request. The response from this endpoint will include the OAuth 2.0 authorization code, which can be exchanged for an access token and optionally a refresh token.

Here is an example of the response that the authorization server might send after the user has accepted the consent request:

HTTP/1.1 302 Found
Location: https://client.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz

In this example, the response includes a “302 Found” status code and a “Location” header that contains the redirect URL. The URL includes the authorization code as a query parameter named “code”, as well as the state value that was included in the original authorization request.

The client application can then exchange the authorization code for an access token by making a POST request to the OAuth 2.0 token endpoint with the appropriate parameters.

Access Token

Here’s an example curl command for exchanging a code with an access token using the /oauth2/token endpoint:

curl --location --request POST 'http://localhost:4444/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'code=<CODE>' \
--data-urlencode 'redirect_uri=<REDIRECT_URI>' \
--data-urlencode 'client_id=<CLIENT_ID>' \
--data-urlencode 'client_secret=<CLIENT_SECRET>'

Replace <CODE> with the authorization code obtained from the consent flow, <REDIRECT_URI> with the redirect URI registered for the client, <CLIENT_ID> with the client ID, and <CLIENT_SECRET> with the client's secret.

Note that the --data-urlencode flag URL encodes the values.

After exchanging the authorization code for an access token, the authorization server responds with a JSON object that includes the access token and other related information. The exact response may vary depending on the specific implementation of the authorization server and the OAuth 2.0 flow being used, but a typical response might look like:

{
"access_token": "abc123",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "def456",
"scope": "openid profile email"
}

Here, the access_token the field contains the actual access token that the client application can use to access protected resources on behalf of the user. The token_type field indicates the type of token (e.g. "bearer") and the expires_in field specifies the expiration time of the access token, in seconds. The refresh_token field is included if the authorization server supports the use of refresh tokens for obtaining new access tokens without requiring the user to re-authenticate. Finally, the scope field lists the scope of the access token, which indicates the specific permissions that the client application has been granted to access the user's resources.

The client application can use the access token to make API requests to the resource server, by including the access token in the Authorization header of the request. The exact syntax for including the access token in the header may vary depending on the specific API being used, but a typical format might be:

Authorization: Bearer abc123

Here, abc123 is the actual access token returned by the authorization server.

If the access token has a short lifetime, you may need to refresh it periodically by making a token refresh request using the refresh token. This is typically done using a separate API endpoint provided by the authorization server.

Multiple Clients and Profile Unification

In Ory Hydra, profile unification can be achieved by using multiple OAuth 2.0 clients. Profile unification involves linking or merging multiple accounts that belong to the same user. To implement this, separate OAuth 2.0 clients can be created for each type of authentication or identity provider, such as Google, Facebook, and email authentication. Each client can be configured to use the same or a unique user identifier.

When a user logs in with one of the identity providers, the user identifier can be used to look up the user’s existing accounts and link them together. This can be done by associating the user identifier with the user’s account in the application or database.

Using multiple clients provides a scalable and flexible solution for profile unification, as each identity provider can be independently managed and updated without affecting other parts of the system. The clients can be chosen based on the user’s preference or the authentication method that is most appropriate for the situation.

Summary

here’s a summary of what we have covered so far:

  • We started by setting up Ory Hydra, an open-source OAuth 2.0 and OpenID Connect server, and created a client application to test the server.
  • We then went through the OAuth 2.0 authentication flow, which involves the client application sending a request to the authorization server to obtain an access token.
  • We looked at how to add additional user data to the ID token, which is returned by the authorization server as part of the OAuth 2.0 authentication flow.
  • We then looked at how to handle profile unification using multiple clients in Ory Hydra. Profile unification is the process of merging or linking multiple accounts that belong to the same user.
  • Finally, we went through an example of how to use multiple clients in Ory Hydra to handle profile unification.

Overall, we covered the basics of setting up and using Ory Hydra and looked at how to use the server to implement common authentication and authorization tasks.

Thanks for reading!

Stay updated

If you liked this tutorial and are interested in further articles from us, follow us-

Helpful resources and references :

These resources should provide a good starting point for learning more about the topics we’ve covered, as well as related technologies and standards.

--

--