Skip to main content

Using an InterSystems IRIS Web Application as an OAuth 2.0 Resource Server

This page describes how to use an InterSystems IRIS® web application as a resource server that uses the OAuth 2.0 framework.

This page primarily discusses the scenario in which the resource server uses the introspection endpoint of the authorization server. See the last section for details on variations.

The process of rotating keys used for signing, encryption, signature verification, and decryption of JWTs is discussed elsewhere.

Prerequisites for the InterSystems IRIS Resource Server

Before starting the tasks described in this page, make sure the following items are available:

  • An OAuth 2 authorization server.

  • If the resource server uses any endpoint of the authorization server, the resource server may be registered as a client of the OAuth 2.0 authorization server. The details depend upon the implementation of the authorization server.

    In this case, you will also later need to know specific details about this server:

  • If the authorization server does not support dynamic registration, you will need the client ID and client secret for the resource server. The authorization server generates these two pieces of information (on a one-time basis) and you need to get them securely to the resource server machine.

Configuration Requirements

See Configuration Requirements, with the following changes when you create the client configuration:

  • For Application name, specify the application name of the resource server.

  • For Client Type, specify Resource Server.

    Note that when you specify Resource Server as the type, the configuration page displays only the options that are applicable to a resource server.

  • For clientID, use the client ID of the resource server.

  • For clientSecret, use the client secret of the resource server.

Code Requirements

An OAuth 2.0 resource server receives a request, examines the access token that it contains, and (depending on the access token) returns the requested information.

To create an InterSystems IRIS resource server, create a subclass of %CSP.RESTOpens in a new tab, in the namespace used by the resource server’s web application. In this class, create a URL map and the corresponding methods. In the methods, do the following:

  1. Call the method GetAccessTokenFromRequest() of %SYS.OAuth2.AccessTokenOpens in a new tab. This method is as follows:

    ClassMethod GetAccessTokenFromRequest(Output sc As %Status) As %String

    The method returns the access token, if any, found in the HTTP request received by this page. It uses one of the three RFC 6750Opens in a new tab formats. The parameter sc, returned as output, is a status code that indicates whether an error was detected. If the request did not use SSL/TLS, that is an error condition. Also, if the request did not include a valid bearer header, that is an error condition.

  2. Check to see whether the status code is an error.

    If the status is an error, the method should return a suitable error (and not return the requested information).

  3. If the status code is not an error, validate the access token. To do so, use ValidateJWT() or your own custom method. See Method Details.

  4. Optionally call the GetIntrospection() method for additional information. This method calls the introspection endpoint of the authorization server and obtains claims about the access token. This method is as follows:

    ClassMethod GetIntrospection(applicationName As %String, 
                                 accessToken As %String, 
                                 Output jsonObject As %RegisteredObject) As %Status

    The arguments are as follows:

    • applicationName is the name of the client application.

    • accessToken is the access token previously returned.

    • jsonObject, which is returned as output, is a JSON object that contains the claims that the authorization server makes about this access token.

  5. If the preceding steps indicate that the user’s request for information should be granted, perform the requested processing and return the requested information.

For example:

    // This is a dummy resource server which just gets the access token from the request
    // and uses the introspection endpoint to ensure that the access token is valid.
    // Normally the response would not be security related, but would ocntain some interesting
    // data based on the request parameters.
    set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc)
    if $$$ISOK(sc) {
        set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("demo resource",accessToken,.jsonObject)
        if $$$ISOK(sc) {
            write "OAuth 2.0 access token used to authorize resource server (RFC 6749)<br>"
            write "Access token validated using introspection endpoint (RFC 7662)<br>"
            write "   scope='"_jsonObject.scope_"'<br>"
            write "   user='"_jsonObject.username_"'",!
        } else {
            write "Introspection Error="_..EscapeHTML($system.Status.GetErrorText(sc)),!
        }
    } else {
        write "Error Getting Access Token="_$system.Status.GetErrorText(sc),!
    }
    
    Quit $$$OK

Examining the Token(s)

After the resource server receives an access token, it should perform additional checks to determine whether the user has the necessary permissions to use the requested resource. To perform this examination, the client can use the methods described here to obtain additional information.

ValidateJWT()

Location: This method is in the class %SYS.OAuth2.ValidationOpens in a new tab.

ClassMethod ValidateJWT(applicationName As %String, 
                        accessToken As %String,
                        scope As %String, 
                        aud As %String, 
                        Output jsonObject As %RegisteredObject, 
                        Output securityParameters As %String, 
                        Output sc As %Status) As %Boolean

Use this method only if the access token is a JWT (rather than an opaque token).

This method decrypts the JWT if necessary, validates the JWT, and creates an object (jsonObject) to contain the JWT properties. To validate the JWT, the method checks the audience (if aud is specified), issuer endpoint (must match that specified in server description), and scope (if scope is specified). The method also makes sure the access token has not expired. Both signed and unsigned JWTs are accepted. If the JWT is signed, the method checks the signature.

This method returns 1 if the JWT is valid or returns 0 otherwise. It also returns several arguments as output.

The arguments are as follows:

  • applicationName is the name of the client application.

  • accessToken is the JWT to be validated.

  • scope is a space-delimited list of scopes, for example: "scope1 scope2 scope3"

    If scope is specified, the JWT must contain a scope claim that includes this scope.

  • aud specifies the audience that is using the token. If the token has an associated aud property (usually because the audience was specified when requesting the token), then aud is matched to the token audience. If aud is not specified, then no audience checking takes place.

  • jsonObject, which is returned as output, is a dynamic object that contains the claims in the JWT. This dynamic object contains properties such as aud, exp, iss, and so on. For details on dynamic objects, see Using JSON.

  • securityParameters, which is returned as output, is a multidimensional array that contains security information taken from the header, for optional additional use in verifying signatures, decrypting, or both.

    This array contains the following nodes:

    Node Value
    securityParameters("sigalg") The signature or MAC algorithm. Set only if the JWT is signed
    securityParameters("keyalg") The key management algorithm
    securityParameters("encalg") The content encryption algorithm

    The keyalg and encalg nodes are either both specified or both null.

  • sc, which is returned as output, contains the status code set by this method.

If this method returns success (1), examine jsonObject, and use the contained claims as needed to determine whether to allow access to the requested resource. Use securityParameters if needed.

Because the Oauth specification allows an application to accept both signed and unsigned JWTs, the ValidateJWT method does not reject an unsigned JWT. However, in many cases it is strongly recommended that your application implement stricter security by rejecting an unsigned JWT. You can determine whether the token passed into ValidateJWT was unsigned by inspecting the securityParameters array that is returned by the method. If securityParameters("sigalg") was not set, the token was unsigned. For example, the following code determines whether the token was unsigned and rejects it if it was:

Set tInitialValidationPassed = ##class(%SYS.OAuth2.Validation).ValidateJWT(tClientName, tAccessToken, "", "", .tJsonObj,.tSecurityParams, .tValidateStatus)
// the “sigalg” subscript is set only if the JWT was signed
Set tIsTokenSigned = $Data(tSecurityParams("sigalg"))#2 
If 'tIsTokenSigned {
   $$$ThrowStatus($System.Status.Error($$$AccessDenied))
}
GetIntrospection()

Location: This method is in the class %SYS.OAuth2.AccessTokenOpens in a new tab.

ClassMethod GetIntrospection(applicationName As %String, 
                             accessToken As %String, 
                             Output jsonObject As %RegisteredObject) As %Status

This method sends the access token to the introspection endpoint, receives a response that contains claims, and creates an object (jsonObject) that contains the claims returned by that endpoint.

The request is authorized using the basic authorization HTTP header with the client_id and client_secret associated with applicationName.

The arguments are as follows:

  • applicationName is the name of the client application.

  • accessToken is the access token.

  • jsonObject, which is returned as output, is a dynamic object that contains the claims returned by introspection endpoint. For details on dynamic objects, see Using JSON.

Note that you cannot use this method if the server does not specify an introspection endpoint or if Client secret is not specified.

If this method returns success (1), examine jsonObject, and use the contained claims as needed to determine whether to allow access to the requested resource.

Variations

This page primarily discusses the scenario in which the InterSystems IRIS resource server uses the introspection endpoint of the authorization server. This section discusses some possible variations.

Variation: Resource Server Calls Userinfo Endpoint

The resource server can also call the Userinfo endpoint. To do so, the resource server code must use the GetUserinfo() method as you do for an OAuth client.

Variation: Resource Server Does Not Call Endpoints

If the InterSystems IRIS resource server does not use any endpoints of the authorization server, it is not necessary to create an OAuth 2.0 configuration on this machine.

Also, the resource server does not need to use GetAccessTokenFromRequest(). Instead, it can get the access token directly from the HTTP authorization header and use it as needed.

FeedbackOpens in a new tab