Client (RP) Examples
This section contains client (RP) configuration examples to illustrate options for implementing InAcademia in some commonly available software libraries.
Important note: the following code samples cannot be used in a live production environment, and are only intended to illustrate the basic steps required to complete a transaction with the InAcademia service. Additional measures must be implemented by the Merchant in order to ensure a secure and fit-for-purpose implementation.
Before you can start, you need to register your service at InAcademia. You will receive an “ClientID” and you must provide a RedirectURI where the response for your service will be returned. Note that you cannot change this endpoint without re-registering. InAcademia will ask you to prove ownership of the domain used in the RedirectURI. More information on registration can be found here: https://inacademia.org/registering-your-service/
InAcademia is an OIDC-compliant OP. Therefore, all certified OIDC RPs should be compatible with InAcademia. A list of certified products and libraries can be found at the OpenID Connect website: http://openid.net/developers/certified/
Apache: mod_auth_openidc
More information can be found here.
The OIDC module for Apache is a very straight forward way of setting up Affiliation validation with InAcademia which can be integrated with many applications. This example assumes a script would live inside a specific directory on your server, protected by the OIDC module. If InAcademia validation is successful the script would pick this up, set the remote user parameter and then continue to a point in the application of your specification.
Installing mod_auth_oidc
Based on https://github.com/pingidentity/mod_auth_openidc For most common linux distributions, the implementation would pull the latest and greatest from the github release page at: https://github.com/pingidentity/mod_auth_openidc/releases. For debian/ubuntu, historically, this Apache module has been part of the standard repositories, and the implementation would install this module alternatively using: sudo apt install libapache2-mod-auth-openidc. The appropriate https/ssl configuration should be made relevant to the merchant’s domain.
Configuring mod_auth_oidc for InAcademia The mod would be configured to work with InAcademia by providing relevant configuration data to the module inside the VirtualHost configuration of the relevant server.
For a secure configuration, you must set an appropriate value for CryptoPassphrase, which would be used as part of the session and cookie hash. A long random string, for example generated using tr -c -d ‘0123456789abcdefghijklmnopqrstuvwxyz’ /dev/null;echo, would be appropriate.
Example for configuration for illustration purposes
Listen <port> ServerName <server name> LoadModule auth_openidc_module /usr/lib/apache2/modules/mod_auth_openidc.so LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so <VirtualHost _default_:*> OIDCProviderMetadataURL <inacademia url>/.well-known/openid-configuration OIDCClientID <client id> OIDCRedirectURI https://<hostname>:<port>/your_redirect_page OIDCResponseType id_token OIDCScope "openid student" OIDCAuthRequestParams "claims=%7B%22id_token%22%3A%20%7B%22domain%22%3A%20null%7D%7D" OIDCCryptoPassphrase <secret> <Location /protected> AuthType openid-connect Require valid-user Location> SSLEngine on SSLCertificateFile <ssl cert> SSLCertificateKeyFile <ssl key> </VirtualHost>
Secure location To trigger Affiliation validation, it would be necessary to create a Location directive in your virtualhost section as illustrated in the example below.
<Location /validate/>
AuthType openid-connect
Require valid-user
LogLevel debug
</Location>
It would be necessary to make sure the directory is part of the Redirect URL!
Python 3: pyoidc
More information can be found here.
Example configuration for illustration purposes
Setup client instance
from oic.oic import Client from oic.oic.message import RegistrationResponse from oic.utils.authn.client import CLIENT_AUTHN_METHOD # create a client instance client = Client(client_id=..., client_authn_method=CLIENT_AUTHN_METHOD) # fetch the provider configuration information client.provider_config(inacademia_url)
Make authentication request
from oic.oauth2 import rndstr from oic.oic.message import Claims, ClaimsRequest from oic.utils.http_util import Redirect # make the authentication request scope = "openid student" # request verification of student affiliation claims_request = ClaimsRequest(id_token=Claims(domain=None)) # request the additional claim 'domain' args = { "client_id": client.client_id, "response_type": "id_token", "redirect_uri": redirect_uri, "nonce": rndstr(), "scope": scope, "claims": claims_request } auth_req = client.construct_AuthorizationRequest(request_args=args) login_url = auth_req.request(client.authorization_endpoint) http_response = Redirect(login_url)
Receive the authentication response
from oic.utils.http_util import Response # Send HTML page with form that POSTs the url fragment back to the server page = """ <html><body> <form action="/parse_response" method="post"> <input type="hidden" name="response" id="response" value=""/> </form> <script type="text/javascript"> document.getElementById("response").value = window.location.hash.substring(1); document.forms[0].submit(); </script> </body></html> """ http_response = Response(page)
Process the authentication response server-side
from oic.oic.message import AuthorizationResponse from urllib.parse import unquote, parse_qsl post_data = ... # read POST data from HTTP request params = dict(parse_qsl(unquote(post_data)))["response"] authn_resp = client.parse_response(AuthorizationResponse, params, sformat="urlencoded") id_token = authn_resp["id_token"] # ... Verify the ID Token and use its claims
Java: Nimbus OAuth 2.0 SDK
More information can be found here.
Example configuration for illustration purposes
Fetch provider configuration information
import java.io.InputStream; import java.net.URI; import java.net.URL; import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata; URI issuerURI = new URI(inacademiaURL); URL providerConfigurationURL = issuerURI.resolve( "/.well-known/openid-configuration").toURL(); InputStream stream = providerConfigurationURL.openStream(); // Read all data from URL String providerInfo = null; try (java.util.Scanner s = new java.util.Scanner(stream)) { providerInfo = s.useDelimiter("\\A").hasNext() ? s.next() : ""; } OIDCProviderMetadata providerMetadata = OIDCProviderMetadata .parse(providerInfo);
Make authentication request
import java.net.URI; import com.nimbusds.oauth2.sdk.ResponseType; import com.nimbusds.oauth2.sdk.Scope; import com.nimbusds.openid.connect.sdk.AuthenticationRequest; import com.nimbusds.openid.connect.sdk.ClaimsRequest; import com.nimbusds.openid.connect.sdk.Nonce; import com.nimbusds.openid.connect.sdk.OIDCResponseTypeValue; Scope studentValidationScope = new Scope("openid", "student"); AuthenticationRequest.Builder authenticationRequest = new AuthenticationRequest.Builder( new ResponseType(OIDCResponseTypeValue.ID_TOKEN), studentValidationScope, clientID, redirectURI); // Request additional claim 'domain' ClaimsRequest claimsReq = new ClaimsRequest(); claimsReq.addIDTokenClaim("domain"); authenticationRequest.nonce(new Nonce()).claims(claimsReq) .endpointURI(providerMetadata.getAuthorizationEndpointURI()); URI loginURL = authenticationRequest.build().toURI(); // ... Make HTTP Redirect to loginURL
Receive the authentication response
StringBuilder sb = new StringBuilder(); sb.append("<html><body>"); sb.append("<form action=\"/response\" method=\"post\">"); sb.append("<input type=\"hidden\" name=\"response\" id=\"response\" value=\"\"/>"); sb.append("</form>"); sb.append("<script type=\"text/javascript\">"); sb.append("document.getElementById(\"response\").value = window.location.hash.substring(1);"); sb.append("document.forms[0].submit();"); sb.append("</script>"); sb.append("</body></html>"); // ... Make HTTP response with sb.toString()
Process the authentication response server-side
import java.net.URI; import com.nimbusds.jwt.JWT; import com.nimbusds.jwt.ReadOnlyJWTClaimsSet; import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser; import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse; Map<String, String> post_data = ... // read POST data from HTTP request URI url = new URI("http://example.com#" + post_data.get("response")); AuthenticationResponse authResp = AuthenticationResponseParser.parse(url); AuthenticationSuccessResponse successResponse = (AuthenticationSuccessResponse) authResp; JWT idToken = successResponse.getIDToken(); // ... Verify the ID Token and use its claims
PHP: JumboJett
Introduction
This example will integrate InAcademia with PHP using OpenID Connect using the JumboJett OIDC library.
To achieve this, we create a basic PHP web site and add InAcademia connectivity to it. There are many libraries that help you with setting up OIDC in PHP. We will first use a very simple and easy to use OpenID Connect package and create a connection with that to sign in a user and retrieve user information.
Prerequisites
- A registered client_id and secret on InAcademia.
- A working domain name, must be TLS protected when deploying to production but can be localhost while developing.
- Knowledge of PHP and an installation on your machine.
Setting up InAcademia
Before diving into the integration process, ensure you have properly set up InAcademia:
- Decided on a callback URL: InAcademia will need to know where to redirect users after they have been authenticated. Once you have decided on a callback URL (typically https://yourdomain.com/oidc_callback.php). It’s always a good idea to include a localhost URL in there for testing the solution locally.
- Register with InAcademia: If you haven’t already, initiate the registration process. At the end of the registration process you will be asked for your callback URL and given a staging client_id and secrett to perform the integration.
With the application registered, we can use the provided credentials (client ID and client secret) and endpoint details to prepare for your application’s authentication flow with InAcademia.
Important note: the code in this article often follows the happy flow so we can emphasize on the working. You should not use it as is in your code. You have to make your code robust, like responsive to missing variables, servers who do not respond, expiring tokens, etc.
Example Implementation:
We start by creating a very minimal web-app using PHP. For OpenId Connect we will use a very simple but powerful library called Jumbojett PHP OpenIDConnect Client.
- Create index.php file for the root of the application
- Create oidc_callback.php. This fille will handle the validation and the callback.
Validation and handling the callback can be handled by the same code, since Jumbojett\OpenIDConnectClient can handle it with the same call. - We will also create a config.php file that will contain the required information for InAcademia.
When we sign in we will add the relevant user information to session variables. Within home.php we then can check if those sessions variables exist and show the values.
index.php
In the editor create a file index.php
and add code for the root of the website.
<?php
// index.php
session_start();
$title
=
"Home Page"
;
if
(isset(
$_SESSION
[
'claims'
])) {
$claims
=
$_SESSION
[
'claims'
];
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?php
echo
$title
; ?></title>
</head>
<body>
<nav>
<ul>
<li><a href=
"index.php"
>Home</a></li>
<?php
if
(! isset(
$claims
)) : ?>
<li><a href=
"oidc_callback.php"
>Validate</a></li>
<?php
endif
; ?>
</ul>
</nav>
<div
class
=
"container"
>
<h1>Welcome student</h1>
<p>This is a basic home page created with PHP.</p>
<pre><?php var_export(
$claims
); ?></pre>
</div>
</body>
</html>
Then it builds up the homepage and it shows a validate link based on the existence of $claims.
oidc_callback.php
The root file index.php
will be executed when we browse the website. When we choose to validate, the user is directed to oidc_callback.php. This script is aware of the state of the validation, so for the first time it will redirect to InAcademia. In case of the callback we can go back to oidc_callback.php since Jumbojett OpenIDConnect Client can handle it with the same call authenticate();
<?php
// oicd_callback.php
session_start();
// load the required libraries and define the use of the OpenIDConnectClient
require
'vendor/autoload.php'
;
use
Jumbojett\OpenIDConnectClient;
require
(
"config.php"
);
// creating the OpenIDConnect client
$oidc
=
new
OpenIDConnectClient(
$cfg
[
"provider"
],
$cfg
[
"client_id"
],
$cfg
[
"client_secret"
]
);
$oidc
->setRedirectURL(
$cfg
[
"redirect_uri"
]);
$oidc
->addScope(
$cfg
[
"scopes"
]);
try
{
$oidc
->authenticate();
$_SESSION
[
'claims'
] =
$oidc
->getVerifiedClaims();
header(
'Location: index.php'
);
}
catch
(Exception
$e
) {
echo
'Error: '
.
$e
->getMessage();
}
The start of the code initializes the possibility to use sessions variables and reads the config,php file.
Then we set up the OpenIdConnect client and inject the information from the configuration.
Validation
We add the scopes from the configuration. The call authenticate() will validate the user if the user is not validated yet. If we validate, the code stops here: we are redirected to InAcademia, we sign in and afterwards the callback happens.
The callback
When the callback is triggered from InAcademia we will be sent back to oidc_callback.php, start the validation again and now the authenticate() function will get (behind the scenes) the required authentication tokens for subsequent calls.
The code will continue to call getVerifiedClaims(). Under the hood the OpenIdConnect client will use the authentication token and retrieve the user info within the requested scopes. The returned data is mapped into a session variable.
Directly after we have set the session variable we redirect the code back to index.php.
config.php
So we have everything in place except the real handling of the connection to InAcademia. Let’s first create a php file that will contain the required information for the OpenID client. This file will be stored next to the other files. Replace the placeholders with the values you have received from InAcademia support.
<?php
$cfg
= [
"provider"
=>
"<INACADEMIA OPENID PROVIDER URL>"
,
"client_id"
=>
"<CLIENT ID>"
,
"client_secret"
=>
"<SECRET>"
,
"redirect_uri"
=>
"http://localhost/oidc_callback.php"
,
"scopes"
=> [
"openid"
,
"student"
],
];
Jumbojett OpenIDConnect Client
uses the OpenID .well-known configuration endpoint, but you do not need to specify the url to that location. It will use the provider to find it and read the relevant information from it.
The scopes determine the validation we request from InAcademia.