Custom OAuth2 consent flow - spring-security

I'm building a service provider application where users are supposed to be able to share their data with a third party application using OAuth2 and OpenID Connect.
The standard OAuth2 consent flow authorize scopes (which attributes / roles to share).
However, since attributes could consist of multiple values, we would also like to allow the user to select which value/s to share.
So my question is, should I replace the whole OAuth2 consent flow with a custom one where OAuth2 scopes are more or less replaced with explicit attribute key/value pairs?
It feels a bit weird to remove such a core component of OAuth2 as scopes, what do you think? Any other suggestions?
I'm currently trying out spring authorization server for customizing the consent flow (since Keycloak that we're currently using doesn't seem to be that flexible with the consent logic).
I think that replacing the standard consent flow in spring authorization server would require rewrites of both OAuth2AuthorizationConsentService, OAuth2AuthorizationConsentAuthenticationProvider as well as all the OAuth2...AuthenticationProvider classes that are used for authentication in order to forward consent to the new consent flow.

Check out the official custom consent sample! This sample demonstrates a custom consent screen without replacing the built-in components for handling submission of the consent screen and saving user consent in the OAuth2AuthorizationConsentService.
In particular, these lines configure the consent page, and this controller endpoint implements the logic for building a custom consent screen, which can be whatever you need for your application.
If you are wanting to customize what is mapped from the consent screen to the saved authorization, you would customize the OAuth2 Authorization Endpoint with an authorizationRequestConverter(). Scopes are simply stored as "authorities", so you can instead (or in addition) store anything you want.
To customize the access token (JWT) that is produced as a result of this consent and authorization, provide a OAuth2TokenCustomizer<JwtEncodingContext> as in the example OAuth2TokenCustomizer from the reference documentation.

What you are describing is the exact purpose of scope: contain user consent on what data (attributes names) a specific client can access on their behalf. Usually, to ease user selection and software maintenance, the attributes granularity in scope selection is not the same as internal data model (for instance a contact scope could represent phone, country, city, zipcode and street columns in database)
As roles, groups, permissions or whatever should be mapped to Spring authorities are not specified by Oauth2 nor OpenID, authorization-servers use private claims to store this data (and usually not scope). If you are used to Keycloak, you should have noticed that roles are put by default in realm_access.roles and resource_access.{client-id}.roles. Other authorization-servers will use other private claim(s).
Simply put, roles (or groups or permissions or whatever you want to call it) define what a specific user can do in the system when scope should contain which resources a specific client is allowed to access on behalf of that user.

Thought I'd add some use-case based notes on the parties involved, and how consent is meant to work.
CLIENT
The client app simply redirects with a scope parameter. It is possible to send a claims parameter but that is rarely used. A scope might be profile and be composed of name and date of birth claims.
AUTHORIZATION SERVER
This presents the requested information in a consent screen. The most flexible way to do this is to present the claims, eg as checkboxes. Some claims, eg name, might be marked as required and use a disabled checkbox. Others, eg date of birth, can be optional. The user might deselect the latter claim and it would then not be included in tokens issued.
CUSTOMIZING CONSENT
Ideally no customization should be needed to achieve the above, which should work out of the box. This may not be the case for Spring though. It is valid to customize consent though. An interesting case where this is done is in Open Banking, where a user can consent to payment of a runtime amount of money:
I consent to pay company X £100 for product Y from account Z

Related

OAuth/OIDC - How To Manage SPA Web App Component Visibility

With OAuth we configure an "Authorization Server" (STS) with one or more "clients" (i.e. SPA web app). Those clients are configured to allow access to one or more "resources" (i.e. API). When a client initiates an OAuth flow (i.e. Authorization Code + PKCE) a "resource owner" (user) is authenticated and at the end of the "flow" an "Access Token" (and maybe a refresh token) is provided to the client which can now be used to access resources (API).
Lets assume that the Access Token is a JWT with claims and that the client now has the ability to read those claims.
UI and component visibility is something that I'm not sure I have done correct in the past:
As the access token's intent is really to drive API access is it wrong to also use it to drive UI component visibility (i.e. determine if we should show a menu item or enable an edit button based on JWT claims in the access token)?
A concern here is we could start adding claims that are really just for the UI / web app out of connivence and have nothing to do with a resource.
Note: it should be obvious that "hiding" a menu item in a web app does
nothing to actually protect a resource so this is more about user
experience
Or - should we be using the OIDC User Info endpoint and have it configured to provide enough information to drive the UI experience?
Or - should we have an API endpoint that will return a payload that describes UI component visibility for the current user?
Or is there another recommended approach that should be used?
As you indicate, it is not recommended for UI clients to use claims in access tokens. They are intended only for use by APIs.
A common pattern is to enforce this by issuing access tokens to clients in a confidential opaque / reference token format, such as a UUID. This can also be a more secure way of dealing with sensitive claims, such as personally identifiable information (name, email etc).
The client also receives an ID token, and personally I prefer to limit ID token claims to protocol claims such as when and how the user authenticated. This ensures that you don't inadvertently reveal PII, eg in logout redirects. A client can get identity fields such as name and email by sending the access token to OAuth user info endpoint.
When fields are more domain specific it can make sense for the client to get its security rules from an API endpoint, that can be tailored to what the client needs. This might include whether orders are editable, which columns the user is allowed to see, and so on. If preferred, the SPA can make a single call to the API, which looks up user info, then returns a transformed result.
Sometimes SPAs use a backend for frontend, in which case the main difference is that the UI receives HTTP-only cookies. In this case the same techniques transfer naturally, where the UI must ask the backend for user info, claims and security rules.

Distinguishing user types in OAuth 2

We're building a system that exposes APIs, subsets of which are accessible to different user types:
organization administrator users can access relevant admin APIs that give them full access to their data. They are identified via email and a password that they control.
device registrar users can access certain APIs that should only be accessible to tablets deployed on-site at organizations. They are identified via an email and password that we control. There is a one-time setup process that the organization goes through to register a device, and it involves logging on with the device registrar account and providing some additional metadata. From there, the device caches the OAuth token and automatically renews it using the refresh token.
visitor users can access APIs that are needed by the end consumer (i.e. the general public), but they must first provide - and prove access to - a mobile number. In other words, they provide a phone number and a OTP will prove they have access to that phone.
We are building this on top of IdentityServer4 using ASP.NET Core and Firestore. We already have IS4 integrated with Firestore and can already authenticate/authorize organization administrators. Each such user in our Firestore database looks like this:
Notice that we just store a set of claims for each user, and in this case it's just an organization ID that the user is an administrator for.
What I'm struggling with a bit is understanding how best to model our other use cases: registered devices and visitors. On the one hand it feels like I could simply use claims to distinguish the different cases; something like this:
an orgid claim means that user is an organization administrator
a regordid claim means that user is able to register a device
a phone claim means that user is a visitor
But on the other hand, this feels a little fragile to me. What if, for example, we wanted both organization administrator users and device registrar users to have the orgid claim? After all, that makes sense because device registrar users are still tied to a specific organization.
On the other hand, is it "normal" to solve this by having some kind of "user type" claim?
Can anyone offer any design tips here?
Good question - some notes below on how I've dealt with this in the past:
MODELLING USERS
By all means model users and their attributes in terms of what makes sense to your company. Then manage this data via some kind of User Service. However, not all user attributes should be included in OAuth access tokens. Aim to avoid a setup where adding Claim X to a token for API 1 also affects tokens for API 2.
OAUTH USER DATA v PRODUCT USER DATA
At some point there is a separation between OAuth User Data and each API's Domain Specific User Data. You perhaps should not really be sending 'device + registrar' claims in tokens to the admin API if the claims are meaningless to the recipient?
CLAIMS BASED ARCHITECTURE
OAuth should enable an architecture where each of your APIs can collect the claims it is interested in, both from the token and from other sources. If interested in this approach, see these resources of mine:
Authorization Design Blog Post
Some C# Code that implements this pattern
In your example this would allow you to deal with 'orgid' privileges in a dynamic manner, based on what that means to each API.
PUT EACH API IN CONTROL
I tend to use the Authorization Server as a 'toolbox' with clearly defined boundaries, so that the API architecture can scale without conflicts:
The Authorization Server's role is to deal only with authentication, and issuing tokens to identify the caller
Tokens contain only a User Id and OAuth scopes, and are therefore easily sharable between multiple APIs
The API's role is to collect claims and deal with business authorization, and this tends to involve different domain specific data for each API
You could have two types of claims, admin and user. For admin users, you add the admin claim (if the claim not present the user is not admin).
If the user claim is not there, he is not an user at all. And if none of the admin/user claim is present then he is a guest. This is one approach.

What oauth pattern to follow for a super user assuming the identity of a customer

I'm working at a company where we have a standard JWT token given to an end user. This user will get their JWT access token by going through the authorisation code oauth flow. By passing their access token into the Authorization header they can make calls into the microservice api's.
We now have a scenario where we need someone from the customer service centre assume the identity of an end user for the purpose of giving the service centre representative access to the users data for short period of time.
To solve this we have discussed having two access tokens flowing into the Authorization header in the microservice api's. The first would represent the customer service centre representative and the second would be the users access token but i am confused on how to best architect this solution.
Can anyone recommend a good solution staying as close to open id connect standards as possible. Microsoft seem to have an oauth flow named on behalf of which kind of matches what i want but seems more like it caters for a system on behalf of a user where I want a user on behalf of another user.
thanks
LONGER TERM
User Managed Access may provide solutions in this area:
End User sets a policy at the Authorization Server for their personal resources
A Company Administrator applies a policy at the Authorization Server for corporate resources (for multiple users)
A Requesting Party (app) presents claims as proof that they meet the policy
REAL WORLD
Almost no Authorization Servers support this capability, and even those that do may not do what you want. It is more than an OAuth pattern though, since a solution also ties into back end behaviour.
WHAT I WOULD DO
Build a solution around claims:
Service centre user logs in, to establish their own identity
After login, lookup claims, to see if the user has 'super' rights
If so, your UI presents an option to act on behalf of another user
Service center user types in email of who they are acting as
Update claims with the second identity
Authorization needs to take both identities into account
Auditing needs to log both identities
The above list hints at requirements, and of course not all of these can be solved with OAuth, but claims should give you the flexibility you need.
See my claims write up for how you could apply this pattern to collect claims from multiple places - not just access tokens. In your case, the ApiClaims object could include your database user ids for both users.

Google OAuth2 API Separate Tokens by Subdomain

I have a multi-tenanted app that I need to integrate with a Google API endpoint, lets say the Calendar API.
The application is organized much like Slack. You can create a namespace and invite users to it. The subdomain is used to separate namespaces, so there could be: foo.domain.com, bar.domain.com, and baz.domain.com.
A user, can belong to multiple namespaces, much like in slack where you can belong to different teams. So John can be a member of both foo and bar.
The problem is, when John decides he wants to give foo access to his calendar info, Google links the authorization to domain.com rather than foo.domain.com. When I attempt to give access his calendar to bar as well, there is no refresh token because technically John has already authorized the access... but I would like these to be treated independent. So that John is able to revoke access to foo.domain.com but continue to have bar.domain.com access his calendar data.
Is there a way to create independent authorizations for the same user to the same app? I can't share the refresh_token across subdomains as they may be physically separated, and I can't create a different app for each subdomain as they are dynamically generated.
The way authentication works is that its based upon the client you created in Google developer console.
If John grants your client access to his calendar data then that client will have access to his calendar data. Google has no way of knowing that its your foo or bar subdomains that have been granted access.
Multiple client option
You should probably created different client credentials for each of the different sub domains. Thats probably going to be the most logical way of doing it.
Single client option
Besides doing that you could store the information in your database someplace John has granted access to foo but not bar and store the refresh token for foo but not for bar and if he wants to delete it for foo then he can do that. You wont have to worry about keeping the refresh tokens updated as a user can technically have up to 50 refresh tokens associated with a single client.
Just watch it with revoke if the user does a revoke its going to revoke access to everything not just a single app.
Google's OAuth implementation only returns a refresh token in the response if the user explicitly clicked the "Authorize" button. This always happens the first time the user is prompted for authorization, but by default the consent screen is skipped when the same application asks for authorization again for the same scopes.
You can override this behavior, and force the user to see the consent screen again by adding the parameter prompt=consent in your authorization URL:
https://developers.google.com/identity/protocols/OpenIDConnect#re-consent
Doing so will ensure that a refresh token is returned each time. Keep in mind that a given user-application pair can only have 50 refresh tokens active at a time, after which older tokens will be invalidated:
https://developers.google.com/identity/protocols/OAuth2#expiration

Ways to skip user consent in OpenID Connect

In the Authentication Request, if users previously gave consent to some client (for a specific list of scopes) and because they might be prompted for the same authorization multiple times. ¿Could be acceptable to skip it?. ¿Works on both code and implicit flows?. ¿How much time remember the consent?.
I'm a little bit confused about the way to implement this. The Oauth2 draft say:
... and obtains an authorization decision
(by asking the resource owner or by
establishing approval via other means).
And OpenID draft say:
... this MAY be done through an interactive dialogue with the End-User
that makes it clear what is being consented to or by establishing
consent via conditions for processing the request or other means
(for example, via previous administrative consent).
Am working on an OpenID Provider implementation for Django.
https://github.com/juanifioren/django-openid-provider
Thanks for your time. Greetings.
Consent is a tricky business. There are different rules in different countries and even different interpretations within the same country. But that aside a common way of handling consent in SSO systems is to ask the user for consent the first time she appears from a specific client and then also ask if the choice should be remembered or if it should only be valid this once. Of course if the user says her consent should be remember she still should have the possibility to later redraw the consent but then outside the normal authorization flow.
You should ask for approval for a specific client only the first time that a user logs in to that client and then store it for later usage. In some use cases user consent is not required because it may be implicit, e.g. in an enterprise setting where users use internal clients.

Resources