Added Support for OIDC User Info and Token Endpoint Response

The 7/25/2020 nightly release of Ignition 8.0.16 introduces first-class support for OIDC IdPs to call the User Info API. Additionally, the token endpoint response object is now exposed to user attribute mappers, security level rules, and Perspective sessions.

User Info

The OIDC spec defines an HTTP endpoint which may be optionally exposed by IdPs. Relying party applications (such as Ignition) may optionally call this endpoint to retrieve additional claims about the authenticated user which may not exist in the ID token’s claims.

If your IdP supports the User Info endpoint and you would like to configure Ignition to call this endpoint for each authentication, go to your IdP’s settings in the Gateway Config Page and fill in the URL to the endpoint (or re-import the OIDC IdP’s metadata to have it automatically filled), then save. If your IdP does not support this endpoint or you do not want Ignition to call the endpoint for each authentication, leave it blank. This field will be blank on upgrade.

Token Endpoint Response

The Ignition Gateway’s OIDC implementation authenticates users by following the Authorization Code Flow. At a high level, this involves the following:

  1. Ignition redirects the user to the OIDC IdP login page
  2. User successfully logs into the OIDC IdP
  3. OIDC IdP redirects the user back to Ignition with an auth code
  4. Ignition makes a back-channel call to the OIDC IdP’s token endpoint and passes the auth code from the user
  5. The OIDC IdP returns a token endpoint response which contains the ID token (used to identify who the user is) as well as an access token (can be used to call other web-based APIs protected with OAuth2 bearer tokens such as the user info API) and other properties.

Before this nightly release, it was not possible to use the token endpoint response from step 5 above. Now you may use this object in user attribute mappers, security level rules, and perspective sessions. The most obvious use case for this is to be able to pull out the access token which may be used to authorize requests made by Ignition to resource servers protected by the same OIDC IdP used by Ignition to authenticate the user. You could also potentially use the ID token to pass along to other APIs as a way to authenticate the user depending on whether or not your IdP and resource servers support this kind of model. The refresh token could be used to call the token endpoint before the last token has expired in order to get a fresh set of tokens without having to send the user back to the IdP, again depending on whether or not your IdP and resource server support this capability.

Direct User Attribute Mappers

Direct user attribute mappers will now have a new drop down to pick the source of user attributes (i.e. ID Token Claims, Token Endpoint Response, User Info Claims). If an OIDC IdP does not have a user info endpoint configured, it should not be possible to select the user info claims source in the drop down (it should not even appear as an option unless it was configured beforehand). Since ID Token Claims were the only source of user attributes before, this is the default selected on upgrade.

Expression User Attribute Mappers

Expression user attribute mappers will continue to support the expression it supports from before (for backwards-compatibility), but a new expression path prefix was added to support multiple sub sources of attributes by name. The format works like this: {attribute-source:(subSourceNameHere):(pathToAttributeHere)} . For example: {attribute-source:idTokenClaims:email} will pull the value from the ID Token Claims attribute source json object with property name email.

Security Level Rules

The same goes for security level rules as explained for expression user attribute mappers (above), including the note about backwards-compatibility as well as the new expression path format for accessing multiple attribute sub-sources.

Perspective Session Props

In Perspective, a new session prop was added at session.props.auth.idpAttributes which contains the same JSON object that is returned in the test login response data for OIDC / Ignition IdPs once the user has authenticated to the session (note: SAML does not support and will not set this new session prop). Before the user has authenticated to the session, the JSON object will be empty. Note: in the designer, session.props.auth.idpAttributes is mocked out to be null an empty JSON object since designer sessions do not yet make use of IdPs.

We hope you enjoy these new features. As always, we welcome any feedback or questions you may have.

7 Likes

Great feature! Thanks!
I’m now able to use the access token response for API authentification during the perspective session by simply using the idp session props.
At the moment I’m struggeling with my Vision apps on version 8.1. I can use OIDC for logging in but I see no possibility to fetch the access token within an Vision startup script or something.
Do you have a hint on this?

We exposed the token API response to user attribute mappers, security level rules, and perspective sessions, but we did not expose it to vision clients, since this feature was implemented before 8.1 (which is when we added IdP support to Vision). I’ll create a ticket to investigate adding this capability to Vision. In the meantime, one hacky workaround is to use a user attribute mapper to map the access token to one of the user’s attributes, and then read that user attribute from a script once logged into the vision session. Another workaround might be to set a tag value as a side effect from a runScript function call in a user attribute mapper expression or a security level rule, then read that tag value from a script once logged into the vision session, but you should be careful with your book-keeping to ensure one user cannot read access tokens from another user session.

1 Like

This is an older topic, but where does the userinfo information actually go when I provide this url? Is it under the auth properties in perspective?

When you log into the OIDC IdP and are returned to Ignition, Ignition sets the user info on the user's session in the Gateway. In Perspective, you can access the user info under session.props.auth.idpAttributes. You can also configure user attribute mappings and security level rules in the IdP configuration itself to extract values from the user info.

currently trying to troubleshoot with what is going on, but I am not getting any extra user info under idpAttributes with the given endpoint that I used. Is there a way to see if my endpoint is returning a good response?

Have you performed a Test Login to see if the user info is coming back to Ignition?

I'm trying to see if it is working with this code but when I pass my idpAttirbutes['tokenEndpointResponse']['access_token'] to it it gives me a bad token response, so I am wondering if i am using the correcter bearer token.

def buildSiteInstances(token):
	
	headers = {
		'Authorization' : 'Bearer ' + token
	}
	
	url = 'https://graph.microsoft.com/oidc/userinfo'
	
	response = client.get(url = url, headers = headers)
	return str(response.json)

And yes, I just tried a test login and it isn't giving me any additional information than before I had the userinfo endpoint defined.

If you don't have an element in the IdP response data tab of the test login results page with property userInfo on it, then there might be a problem with fetching the user info using the URL provided in the configuration.

Try setting gateway logger gateway.HttpOIDCClientService to TRACE and perform another test login, then check the gateway logs to see if there are any clues there regarding the lack of user info...or before doing that, check to see if you already have an error with message Unable to retrieve user info from IDP logged at a WARN level in the gateway logs with that logger... the associated stacktrace could give clues.

The trace logs are showing that I am getting a 401 Unauthorized response for that URL. I'll try and dig some more to see if I am using the correct URL and everything.

I found the correct URL now (https://graph.microsoft.com/v1.0/me), and I even tested it by manually making a client call through the script console and passed my token as plain text and I actually got a good response.

However, whenever I try to make a client call from a perspective session and pass my token from there, I get an "Access Token Failure. Invalid Audience" error. At a little bit of a loss as to how to get this to work for me.

Consider making a new thread detailing the problem you are facing. Include a background of what it is your are trying to accomplish, links to docs for the APIs you are trying to call, what you've tried so far, etc. When I can find some time I'll try and jump on that thread and see what I can find out, meanwhile maybe others in the community may be able to spot something...

2 Likes

Hi @jspecht, Is this something that ignition can do automatically in the background or is this something we need to program by our self ? If we do it by our self can we override the idpAttribute in session props by the result we get from the refresh call?

regards

Ignition's OIDC IdP does not support refreshing tokens as a first-class feature. You will have to manage the refresh token yourself. You cannot override the session prop but you can set a different prop for refreshed tokens if you'd like to track the refreshed tokens via session prop.