API SSO with OAuth2: Membrane Example
OAuth2 can be used to secure an API from unauthorized access.
Figure:
You can find a working example in the $MEMBRANE_HOME/examples/oauth2/credentials folder in the Membrane API Gateway distribution. The client/app is simulated through a script and the token validator and authorization server through separated Membrane API Gateway instances.
Running the Example
Follow these steps in the $MEMBRANE_HOME/examples/oauth2/credentials folder to run the example:
- Run the service-proxy.bat/.sh in the authorization_server subfolder.
- Run the service-proxy.bat/.sh in the token_validator subfolder.
- Wait until both membrane instances are "up and running".
- Run the client.ps1/.sh - "OK" will appear in the command line.
Figure2:
Figure 2 shows the request and response header when the client requests the protected resource. The red box is the request header and in it, in the green box, is the authorization header with the access token. The blue box shows the responses status code.
Figure3:
Figure 3 runs the client.ps1 through Windows Powershell that does essentially the same as the client.sh. The script only tells if the request was a success (OK) or a failure (Access denied).
Authorization server
Description for the authorization server is not part of this explanation. See the OAuth2 authorization code example for a thorough description of the authorization server.
Token validator
The token validator is a Membrane Service Proxy instance. Its purpose is to take the OAuth2 token from incoming messages and verify it through the authorization server. On successful verification the request continues to the protected resource. On failed verification the token validator responds with a 400 bad request message.
<serviceProxy name="Token Validator" port="2000"> <!-- Validates tokens against authorization server - blocks request on invalid tokens --> <tokenValidator endpoint="http://localhost:7007/oauth2/userinfo"/> <target host="localhost" port="3000"/> </serviceProxy> <serviceProxy port="3000"> <groovy> exc.setResponse(Response.ok("You accessed the protected resource!").build()) RETURN </groovy> </serviceProxy>
With this configuration Membrane has a service proxy that listens on port 2000 for incoming messages.
The tokenValidator interceptor is where the token validation takes place. It has the endpoint attribute that specifies the URL for the access token validation endpoint. The access token validation endpoint is provided by the OAuth2 provider, e.g. the authorization server in this example. If the validation wasn't a success then the tokenValidator blocks the request and answers with a bad request. If the validation succeeds the call is routed to the resource.
The service proxy on port 3000 simulates the resource that is to be protected against unauthorized invocation.
Note: Port 3000 should be inaccessible from outside in production use else someone with knowledge of the endpoint can call it directly.
Trusted client
The trusted client is a script that requests an access token from the authorization server. The token request has no user credentials attached and thus is an anonymous request. When the access token is received it is appended to the request for the protected resource.
Note: The trusted client could have been implemented by configuring a Membrane Service Proxy instance similarly to the token validator.
There are 2 different versions of the client. One is a powershell script and the other a shell script.
The general structure of any of those scripts is that at the top there are some settings that should be configured. These settings are:
Name | Description |
---|---|
clientId | the client id of the application |
clientSecret | the corresponding secret |
tokenEndpoint | the OAuth2 token endpoint of the authorization server |
target | the secret resource ( in this example it is the token validator that gets the secret resource on verification success ) |
The script then follows a simple procedure. It gets the access token from the token endpoint by doing a token request with the OAuth2 grant_type client_credentials and the client credentials. After retrieving the access token the client sends a request to its target putting the access token into the authorization header. Finally the result of the request is shown.
As a further reference there is also a standalone Java implementation of the trusted client called OAuth2TrustedClient in the example folder.
Help needed?
Do you need any help for this scenario? Then contact us using the Membrane Google Group or send an email to membrane@predic8.com.