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
orid
field on theusers
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.