This topic tells you about common app architecture patterns for enterprise developers.

Externally Hosted Apps Call APIs

This section describes common architecture patterns for authenticating externally hosted apps that call APIs. In these patterns, externally hosted apps, secured either by Security Assertion Markup Language (SAML) or by OpenID Connect (OIDC) providers using JSON Web Tokens (JWTs), interact with Single Sign‑On for VMware Tanzu Application Service to gain access to services.

The following diagram is a conceptual view of an externally hosted app protected by a SAML or OIDC enterprise identity provider (IDP):

Diagram of a conceptual view of an externally hosted app. It is described in the following list.

The following describes how externally hosted apps are protected by SAML:

  • The externally hosted app is secured by an enterprise SAML or OIDC identity provider, that is, users authenticate using the SAML or OIDC provider into the externally hosted app.

  • The externally hosted app needs to invoke API-1 and API-2, which are Spring Boot microservices running on VMware Tanzu Application Service for VMs.

  • API-1 and API-2 are protected by Single Sign‑On using OAuth.

The following sections describe three authentication models that can be used for externally hosted apps using SAML or OIDC enterprise IDPs to call into APIs:

UAA Authorization Code Grant — Browser

The following sequence diagram illustrates the UAA authorization code grant model:

Diagram of the UAA authorization code grant model. Is is described in the following list.

View a larger version of this image.

The diagram above shows a SAML flow, but the interactions between the app, enterprise IDP, and UAA can also use an OIDC enterprise IDP. In that case, JWT ID tokens replace SAML and SAML assertions.

The following describes the UAA authorization code grant model:

  • The authenticated user’s session against the enterprise IDP is leveraged, which makes direct user authentication against the UAA transparent to the user.

  • The user/browser calling a micro-service is redirected to UAA and then to the IDP. Because this user session with the IDP is already authenticated, the redirect back to UAA and then back to the micro-service is transparent to the user.

  • Your enterprise IDP applies any security policies defined by your corporate policy, for example, multi-factor authentication (MFA), Kerberos, or PKI certificates.

  • Behind the scenes the UAA authenticates the user via SAML, because the user has a logged in session with the IDP.

  • UAA then generates a JWT for the authenticated user.

SAML Bearer Token Exchange — Back End

The following sequence diagram illustrates the SAML bearer token exchange model:

Sequence diagram of the SAML bearer token exchange model. It is described in the following list.

View a larger version of this image.

The following describes the SAML bearer token exchange model:

  • The user has already authenticated against the enterprise IDP via SAML through interactions with the existing integration with the IDP upstream.

  • The authenticated session against the IDP empowers the user to get a SAML assertion intended for the Single Sign‑On (also known as UAA) audience. In the SAML assertion, the recipient and audience must match UAA. See the Example SAML Assertion below.

  • The UAA allows for a token exchange permitting the upstream caller to get a UAA JSON web token (JWT), which authorizes access to hosted microservices, leveraging the SAML assertion mentioned above.

Example SAML Assertion

In the SAML assertion used in the SAML bearer token exchange, the Recipient and Audience must match UAA. For example:

Recipient

The Recipient must match the UAA entity ID.

Recipient="https://demo.login.uaa-example.com/oauth/token/alias/demo.login.uaa-example.com"/>

Audience

The Audience must match the UAA assertion consumer service URL.

<saml2:AudienceRestriction><saml2:Audience>demo.login.uaa-example.com</saml2:Audience></saml2:AudienceRestriction>

Example SAML Assertion

The Recipient and Audience properties are located near the bottom of the example SAML assertion below.

<?xml version="1.0" encoding="UTF-8"?><saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="id41261893195735352003413868" IssueInstant="2018-01-24T19:23:15.522Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://www.okta.com/exk9sgb2ayyAikL150h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id41261893195735352003413868"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>oTsVYrWJ4Yah1eM3p0e4DCLP3NlsgFoAZ6R/KIIonL8=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>BYg9pYj2MwO4OvQvtuH2WOWemcEew7R6dIyxEaUC9sAtTyMBB0dumMhDZMtOXu7G6+Uoba7B1XqAS8YM5/llQsW/oGZAH9NuhYhNW1eWw8eSrTQjpfKn61Vei2EmihWwTRptBZUucu4ZSblvqPnUYt0SF/hMfHqYRbILeicZTgT/TlllOIMoPcET7JHC1ZkMYGJfKjXue1t34FER55ce1CnQQIxBN435R0WWLhx0UNd9XGWPlB3ddtaMJlehO9EZDECe1ORGP1niVplLSsx0QE1inVTr7Qn7+x3tGlX/9MVgEDevZaGdZzwdbkwwfDssFWppjLpqpcBLZLK8USSN1Q==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAVmywjWWMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEG
A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU
MBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi0yODEzNzYxHDAaBgkqhkiG9w0BCQEW
DWluZm9Ab2t0YS5jb20wHhcNMTcwMTE4MTgwNTI5WhcNMjcwMTE4MTgwNjI5WjCBkjELMAkGA1UE
BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNV
BAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtMjgxMzc2MRwwGgYJ
KoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
0okZSvNaxO/QzpT92pxALWevO1j3F0DyFRjWz1x4u8AbPjJDizbr42pnm/dOxw5bij2CecwIvI3b
G/LNMh0NMB1uuMwRppIpNkU0mu/8b3u1szmgMSULRiAtCQFIKAd8VXApbmnLlsfzN5CnJzeDEZ29
3E/RGVr0WvSUKWYZaij57BfH2r2A44TZfRNpfUgtsvsVVQvtwDgKBo+rNqZIkQoMi0hdpX2Z522Z
l6vpbDGu56kWR0fqyfoshKHPnHNvk/c0HkwkCIAm1l7DW95PnrTxjx7QQuLZibUFPD1sQE2S4Vxe
W6kxXhT8ttmML0OjirEqtD+98BcbqCc9SgYtzwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQDKqs49
VBGpRTAWvGm+giBHT2uJd5JCefE6ap/OPp+ajfslXXH3yUOq6CiyK1iVgS9j15MOVBDTou8vTtsK
w0TmdG1NHKCJqpTe2h/+3uvCG2yv9D6rfDiQcO4KgeG+5hXnS2fGcFTuCmODX7ivEYB9eeAqXkJG
4LFwxVhse8j0rwkdPESkdL7KdTbzK5rsM3tWihSsuccm4a6Zp6faFZzWhvd6ujBGIlLtaVHP9jUG
eMHVqMYK6C91CalL4/kGUJYGsKhbuF4CdjwlK9PB4PvNLn+ijWk9dYkVlQYMH93Lg9T/2OYVBux7
MQsY0xtKYytwky+LiE1SjODZPQvYXaS3</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">[email protected]</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData NotOnOrAfter="2018-01-24T19:28:15.522Z"
Recipient="https://demo.login.uaa-example.com/oauth/token/alias/demo.login.uaa-example.com"/>
</saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2018-01-24T19:18:15.522Z" NotOnOrAfter="2018-01-24T19:28:15.522Z" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<saml2:AudienceRestriction><saml2:Audience>demo.login.uaa-example.com</saml2:Audience></saml2:AudienceRestriction>
</saml2:Conditions><saml2:AuthnStatement AuthnInstant="2018-01-24T19:23:15.522Z" SessionIndex="id1516821795522.1919419636" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement><saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion"><saml2:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">[email protected]</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name="fn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Sree</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name="ln" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Tummidi</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name="roles" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Everyone</saml2:AttributeValue><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Writer-Admin</saml2:AttributeValue><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Reader</saml2:AttributeValue><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Writer</saml2:AttributeValue><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Writer-a-Admin</saml2:AttributeValue><saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Reader-Admin</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement></saml2:Assertion>

JWT Bearer Token Exchange

The following sequence diagram illustrates the JWT bearer token exchange model. This flow is for externally hosted apps using OIDC.

Sequence diagram of the JWT bearer token exchange model. It is described in the following list.

View a larger version of this image.

The following describes the JWT bearer token exchange model, which is similar to the SAML bearer token exchange model:

  • The upstream app contacts UAA and requests a JWT native to TAS for VMs. The app provides a JWT generated by the enterprise IDP as evidence that the user has been authenticated.

  • The returned JWT can then be used to invoke protected microservices hosted within TAS for VMs.

The difference between this flow and the SAML exchange one is that there is no need to get a specific SAML assertion for the UAA audience.

Example JWT Token Content

{
  "sub": "mysub",
  "iss": "https://my.idp.com",
  "aud": "http://appliesto/myidpjwt",
  "iat": 1517486551,
  "exp": 1517490151,
  "sess": "bf8d6812-0747-11e8-a94b-005056be1e86",
  "groups": [
    "my-admins"
  ],
  "emailAddress": [
    "[email protected]"
  ]
}

Handling the JWT Token Exchange Using a Gateway

In the sequence illustrated above, the token exchange is handled by the app. However, you can abstract away the token exchange from the app. Instead, a gateway such as Apigee or Mulesoft intercepts the call and handles the token exchange transparently, as shown in the diagram below.

Diagram shows the gateway that sits between the Enterprise IDP (OIDC) and UAA.
All communication from the app and Enterprise IDP (OIDC) to UAA and the foundation
microservice passes through the gateway.

View a larger version of this image.

Set Up for SAML or JWT Bearer Token Exchange

The following setup procedure uses the example shown in the conceptual diagram above.

  1. Create API-1 and API-2 as resources in Single Sign‑On, for example, api1.read, api1.write and api2.read, api2.write.

    For instructions, see Create or Edit Resources.

  2. Create an Admin Client with the ability to create more OAuth Clients under the Single Sign‑On service plan. Therefore, use the scope clients.admin.

    For instructions, see Create Admin Client.

  3. Use UAAC to target the Single Sign‑On service plan and log in using the Admin Client created in the previous step.

    For instructions, see step 4 in Manage Users with the UAAC.

  4. For each client of the externally hosted app, run the following command to register the client:

    uaac client add -i
    

    In this example, there are two clients: API-1 and API-2.

  5. When prompted:

    1. Specify a client ID and secret, and record them for future use in the API call.
    2. Specify the Grant Type as either of the following:
      • For SAML: urn:ietf:params:oauth:grant-type:saml2-bearer
      • For JWT: urn:ietf:params:oauth:grant-type:jwt-bearer
    3. Specify the scopes. In this example, they are either: api1.read and api1.write, or api2.read and api2.write.
    4. You can leave the redirect URI and other options empty.
  6. A plan admin must do the following in the Single Sign‑On Plan Administrator Dashboard:

    1. Add the enterprise SAML or OIDC (for JWT) provider. For instructions, see Configure an External Identity Provider.
    2. Do one of the following:

      • Set up external group mappings for api1.read and other scopes. For instructions, see Create or Edit Resource Permissions.
      • Add the corresponding scopes to the users that require this access. For instructions, see Managing Users.
      • Make the scopes as default authorities so that users do not need to be assigned the groups individually.

        For instructions, see Add Default Groups for Users.

  7. The externally hosted app, or gateway, must make the following API call:

    1. Invoke the /oauth/token endpoint of the Single Sign‑On service plan with the parameters laid out in this documentation:
    2. Pass in the following:
      • Client ID and client secret registered for the externally hosted app
      • The SAML assertion or JWT token from the externally hosted app

    The response is a token that you must add in the authorization header when making a call to API-1 or API-2.

check-circle-line exclamation-circle-line close-line
Scroll to top icon