Integrating Authentication (Identity) Data

Oso Cloud is authorization as a service. While similar in name, authentication and authorization have two different purposes:

  • Authentication checks who a user is.
  • Authorization checks what they can do.

This guide describes how to integrate Oso Cloud with your authentication provider.

What is authentication?

Authentication is a mechanism for checking that a user is who they say they are, i.e., checking their identity. There are a variety of methods available for checking a user's identity, from simple username and password combinations to more advanced forms like social logins and Single Sign-On (SSO). Oso Cloud is not an identity or authentication provider, but it does integrate easily with authentication providers.

How Oso Cloud uses identities

Oso Cloud assumes that you have a system in place for authenticating users and that you store user data elsewhere (e.g., in a database or hosted service).

In Oso Cloud, users are identified by a type and ID. If your application uses UUIDs, a user in Oso Cloud might look like User{"70f19088-7e97-4ca9-be0a-4deeaeedb7a7"}. For example, this is how you could tell Oso Cloud that user 70f19... has the "admin" role on a particular organization:


const user = { type: "User", id: "70f19088-7e97-4ca9-be0a-4deeaeedb7a7" };
const organization = {
type: "Organization",
id: "00e54c4c-9bd3-4fc6-99d4-8d433e65d84f",
};
// User 70f19... has the "admin" role on Organization 00e54...
await oso.bulk([[], [["has_role", user, "admin", organization]]]);

And here's how you could pass that same user object to make an authorization query:


const allowed = await oso.authorize(user, "delete", organization);
if (allowed) {
// Delete the organization.
} else {
// Return an error.
}

Choosing a user identifier

A good user identifier is:

  • unique per user;
  • consistent for the same user over time;
  • accessible from any service in your system with minimal overhead.

Examples:

  • The sub property in the response from an authentication service or in a JSON Web Token (JWT).
  • The uuid or id field on the users table in a relational datastore.

Hands-on example

In this example, users can update projects by making PUT requests to the /api/project/[projectId] endpoint. Here we use NextJS, Oso Cloud for authorization, and Stytch for authentication (though any authentication service will work).

When a user logs in, Stytch stores an opaque, random string as a session token. You authenticate the user's identity by validating the session token. The decoded session object contains a user_id for the user, which we use to identify the user to Oso Cloud:


export async function updateProject(req: NextApiRequest, res: NextApiResponse<Response | Error>) {
// Read the Stytch session token from the cookies.
const token = cookies.get('stytch_session');
// Authenticate the session token. Throws an error if the token is invalid.
const resp = await loadStytch().sessions.authenticate({ session_token: token });
// Retrieve the user ID from the decoded session.
const userID = resp.session.user_id;

With the user_id from the session, we ask Oso Cloud if the user can update the project:


// Retrieve the project ID from the request.
const { projectId } = req.query;
const user = { type: "User", id: userID };
const project = { type: "Project", id: projectId };
if (await oso.authorize(user, "update", project)) {
// Update project.
} else {
// Return an error.
}
}

Do I need to sync all my users to Oso Cloud?

No, you don’t sync users to Oso Cloud. Instead, you sync roles and attributes about your users, and Oso Cloud uses those roles and attributes to make authorization decisions. Since Oso Cloud is deny by default, if you haven’t synced any roles for a particular user, they won’t be granted access to any resources. For more information on syncing data to Oso Cloud, read the Sync and Export Data guide.

What about scopes?

Some authentication services support scopes for users. Scopes are sort of like feature flags or global roles — they provide some data that you can use to determine what a user can see or do, but they can only encode information about the user and not about the resources in your application. For example, a user might have the delete_repository scope that allows them to delete any repository, but you’re out of luck if you want to restrict users to only delete repositories they own. Scopes might suffice if you only require coarse, global access control, but they’re an incomplete solution that doesn’t support more granular resource-based authorization.

Talk to an Oso engineer

If you'd like to learn more about using Oso Cloud in your app or have any questions about this guide, connect with us on Slack. We're happy to help.

Get started with Oso Cloud →