Search

Authentication

About user authentication while accessing CDS services.

Content

Prerequisites

Authentication Strategies

You can choose from these authentication strategies:

Mocked Authentication

This strategy swaps the relevant user information that would normally come from the JWT token (for example: user ID, scopes, and attributes) by fake information. This way, no development roundtrips to UAA is necessary, which is convenient for fast development turnarounds or testing.

Note that this mode must only be used during development. It’s disabled if the NODE_ENV environment variable is set to production.

  1. Go to your project you created in Getting started in a Nutshell.

  2. Enable the strategy by installing the passport node.js package:

     npm install passport
    
  3. Open the srv/admin-service.cds file and add the @requires annotation:

     service AdminService @(requires:'authenticated-user') { ... }
    

    Save your changes. You’ve protected your service and only authenticated users can access it.

  4. Run your project:

     cds run
    
  5. Open http://localhost:4004/admin/Books

    You see a basic authentication popup. Don’t enter a user, just confirm.

  6. Now, require a dedicated role named admin:

     service AdminService @(requires:'admin') { ... }
    

    For this to work, add a mocked user alice that is admin. You have two options to equip alice with this role. Use either a .cdsrc.json or the package.json (cds section) in the root of your project and add this code:

     "auth": {
       "passport": {
         "strategy": "mock",
         "users": { "alice": { "roles": [ "admin" ] } }
       }
     }
    
  7. Stop your service with CTRL+C.

  8. Run your project:

     cds run
    
  9. Open http://localhost:4004/admin/Books.

    You see a basic authentication popup. Enter alice as username and leave the password empty.

    Result: When logged in with alice, you can access …/admin/Books, while other users get rejected.

    Tip: When you’re testing different users in the browser, it’s best to use an incognito window, because logon information might otherwise be reused.

  10. [Optional] Explicit user IDs can be configured, as well as passwords and user attributes:

     {...
       "users": {
         "alice": {
           "roles": [ "admin" ],
           "ID": "alice@wonder.land",
           "password": "secret",
           "userAttributes": { "country": "US" }
         }
       }
    
    

    If you include the ID property, that value now becomes the mock username for Basic Authentication. In this example, the user is alice@wonder.landand the password is ‘secret’. Similarly, the value passed as $user is set to the value of the ID property.

    To test this configuration, again, stop your service with CTRL+C and start it again (cds run).

    Services without @require or @restrict annotations run without authentication checks.

    Learn more about authorization annotations in CDS Learn more about CDS configuration

Token-Based Authentication (JWT)

This is the strategy to be used in production. User identity, as well as assigned roles and user attributes, are provided at runtime, by a bound instance of the ‘user account and authentication’ service (UAA). This is done in form of a JWT token in the Authorization header of incoming HTTP requests.

  1. Log in to Cloud Foundry:

     cf l -a <api-endpoint>
    

    If you don’t know you API endpoint, have a look at Regions.

  2. Go to your project you created in Getting started in a Nutshell.

  3. Start the watch process on your project:

     cds watch
    
  4. Enable the strategy by installing the @sap/xssec@^2 and the [@sap/xsenv][sap/xsenv] package:

     npm install @sap/xssec@^2 @sap/xsenv
    

    Note, that @sap/xssec@^3 is not yet supported.

Next, you need to bind and configure the UAA service.

Create XSUAA Configuration

  1. Create a folder called gen and compile your CDS model with authentication annotations into a full xs-security.json:

     mkdir gen
     cds compile srv/ --to xsuaa > gen/xs-security.json
    

    Note how in xs-security.json the admin scope from the CDS model has materialized as a scope and a role template.

  2. Create an XSUAA service with this configuration:

     cf create-service xsuaa application bookshop-uaa -c gen/xs-security.json
    

    Later on, if you’ve changed the scopes, you can use cf update-service bookshop-uaa -c xs-security.json to update the configuration.

    Troubleshooting: Invalid JSON

Note that this step is necessary for locally running apps and for apps deployed on Cloud Foundry.

Configure the Application

  1. Create a default-env.json file in the root of your project and insert this code:

         {
         "VCAP_SERVICES": {
             "xsuaa": [
                 {
                     "name": "bookshop-uaa", "label": "xsuaa", "tags": [ "xsuaa" ],
                     "credentials": {
                     }
                 }
             ]
         }
     }
    
  2. Create a service key:

     cf create-service-key bookshop-uaa bookshop-uaa-key
     cf service-key bookshop-uaa bookshop-uaa-key
    

    You do this, to gain access to the XSUAA credentials.

  3. Copy the JSON snippet from the console into the default-env.jsonfile in the VCAP_SERVICES.xsuaa.credentials block.

    This step is only necessary if your application is running locally.

  4. Enhance your app’s configuration in package.json by a uaa section inside the cds.requires block:

     "cds": {
     "requires": {
         "uaa": {
             "kind": "xsuaa"
         }
     }
     }
    

    This configuration, together with the credentials from default-env.json, is used by the Node.js runtime to validate the JWT token. To verify it, you can run cds env list requires.uaa, which prints the full uaa configuration including the credentials.

    Learn more about how this matching to VCAP_SERVICES works

  5. Install node modules that are required at runtime to authenticate the user and to read the JWT token:

     npm install --save passport @sap/xssec @sap/audit-logging
    

Set Up the Roles for the Application

Once you’ve deployed your application to the Cloud Foundry environment and created the service binding to XSUAA, you enter the SAP Cloud Platform Cockpit. In the cockpit, you set up the roles and role collections and assign the role collections to your users. This brings the necessary authorization information into the JWT token when the user logs on to your application through XSUAA and approuter.

Since XSUAA configuration in cloud cockpit only works on existing applications, you need to temporarily push the app and bind it to the previously created service. You don’t need the app to be running at this stage.

  1. Push the application without start:

     cf target  # make sure that you're logged in to the correct org and space
     cf push bookshop --no-start --no-manifest --random-route
    
  2. Bind your application to your xsuaa service instance:

     cf bind-service bookshop bookshop-uaa
    
  3. Open the SAP Cloud Platform Cockpit.

    For your trial account, this is: https://cockpit.hanatrial.ondemand.com

  4. Create a role collection.

    The roles collections are created on subaccount level in the cockpit. Navigate to your subaccount and then to Security > Role Collections. Create role collections

  5. Create roles and add them to your role collection.

    The roles are created on application level in the cockpit and based on your role templates. Navigate to the application in the correct space in your subaccount and then go to Security > Roles. The wizard takes you through all needed steps. Remember to include your role to the role collection you created before. Create roles

  6. Assign the role collections to users.

    The user role assignment is done in the Trust Configuration of your subaccount. Select the IDP where the user is authenticated. Assign role collection to user. Select IDP Enter the E-mail address and select Show Assignments, to see already existing assignments. Then select Assign Role Collection to add your user to the role collection. Assign role collection to user. Select user

    See Assign Role Collections in SAP Cloud Platform documentation for more details.

Running Approuter

The approuter component implements the necessary handshake with XSUAA to let the user log in interactively. The resulting JWT token is sent to the application where it’s used to enforce authorization.

  1. Create a file app/package.json with the following content:
    {
       "name": "approuter",
       "dependencies": {
         "@sap/approuter": "^6"
       },
       "scripts": {
         "start": "node node_modules/@sap/approuter/approuter.js"
       }
    }
    
  2. Create the approuter configuration file app/xs-app.json with the following content:
    {
     "routes": [ {
       "source": "^/(.*)",
       "destination": "srv_api"
      } ]
    }
    
  3. Create a file app/default-env.json with the following content:
    {
     "destinations" : [
         {
             "name": "srv_api",
             "url": "<service-url>",
             "forwardAuthToken": true
         }
     ]
    }
    

    where

    • srv_api is the destination name from xs-app.json.
    • <service-url> is the service root of your app, for example, http://localhost:4004
  4. Copy the VCAP_SERVICES block of file default-env.json into file app/default-env.json. This tells approuter which UAA instance to contact.

  5. In app/ folder, run
    npm install  # install approuter modules
    npm start    # start approuter
    

    This starts an approuter instance on http://localhost:5000

    Since it only serves static files or delegates to the backend service, you can keep the server running. It doesn’t need to be restarted after you have changed files.

  6. After the approuter is started, log in at http://localhost:5000 and verify that the routes are protected as expected. In our example, if you assigned the admin scope to your user in SAP Cloud Platform cockpit, you can now access http://localhost:5000/admin.


To test UIs w/o a running UAA service, just add this to xs-app.json: "authenticationMethod": "none"

Programmatic Configuration

So far, we have seen configuration as part of .cdsrc.json or package.json, which applies to all served services. By defining an authentication strategy in cds.serve options, you can specify:

  • Different authentication strategies for different services
  • Multiple authentication strategies for a single service
cds.serve('./my-service', {
    uaa: { tag: 'xsuaa' },
    passport: {
        strategy: [JWT, 'mock'],
        users: { alice: {roles: ['admin'], password: 'secret'} }
    }
})

If multiple authentication strategies are defined, the strategies are applied sequentially and combined using OR operator. It means if one strategy fails, then the next strategy is applied. The user is authenticated if one of the strategies was successful.

In the example, the JWT strategy is applied first and if it fails, the mock strategy is applied. If also the mock strategy fails, then the user is considered as not authenticated.

How the Authentication Strategy Is Detected

This summarizes how the Node.js runtime determines which strategy to apply:

  1. The Node.js runtime checks, if an authentication strategy is set programmatically. If a strategy is set, it’s applied regardless of the services’ security annotations.

  2. Then, security annotations like @require or @restrict are checked on service level, which means for the service itself and for all of its entities.
    • If at least one annotation is found, all entities in the service run authenticated. The configuration information provided in package.json or in the .cdsrc file is analyzed to find a strategy.
    • If a strategy isn’t found, but the package @sap/xssec is installed, the JWT strategy is used.
  3. If none of the strategies have been determined, all requests in a production environment are considered as nonauthenticated. In a test environment, the mock strategy is used.

You can see which authentication strategy will be used by running cds env get auth in your project directory.