Skip to content
Search

    Authentication

    This guide is about authenticating users on incoming HTTP requests. This is done by authentication middlewares setting the req.user property which is then used in authorization enforcement decisions.

    req.user cds.User class

    Represents the currently logged-in user as filled into req.user by authentication middlewares. Simply create instances of cds.User or of subclasses thereof in custom middlewares. For example:

    const cds = require('@sap/cds')
    const DummyUser = new class extends cds.User { is:()=>true }
    module.exports = (req,res,next) => {
      req.user = new DummyUser('dummy')
      next()
    }
    

    Properties & Methods

    user.id : string

    A user’s unique ID. It corresponds to $user in @restrict annotations of your CDS models (Also in JavaScript, user can act as a shortcut for user.id in comparisons.)

    user.is (<role>) boolean

    Checks if user has assigned the given role. Example usage:

    if (req.user.is('admin')) ...
    

    The role names correspond to the values of @requires and the @restrict.grants.to annotations in your CDS models.

    user.attr.<x> : string

    User-related attributes, for example, from JWT tokens These correspond to $user.<x> in @restrict annotations of your CDS models

    DEPRECATED: user.tenant : string

    Use req/msg.tenant instead.

    DEPRECATED: user.locale : string

    Use req/msg.locale instead.

    cds.User.Privileged class

    In some cases, you might need to bypass authorization checks while consuming a local service. For this, you can create a transaction with a privileged user as follows:

    this.before('*', function (req) {
      const user = new cds.User.Privileged
      return this.tx({ user }, tx => tx.run(
        INSERT.into('RequestLog').entries({
          url: req._.req.url,
          user: req.user.id
        })
      )
    })
    

    Authorization Enforcement

    Applications can use the req.user APIs to do programmatic enforcement. For example, the authorization of the following CDS service:

    service CustomerService @(requires: 'authenticated-user'){
      entity Orders @(restrict: [ 
        { grant: ['READ','WRITE'], to: 'admin' },
      ]){/*...*/}
      entity Approval @(restrict: [
        { grant: 'WRITE', where: '$user.level > 2' } 
      ]){/*...*/}
    }
    

    can be programmatically enforced by means of the API as follows:

    const cds = require('@sap/cds')
    cds.serve ('CustomerService') .with (function(){
      this.before ('*', req =>
       req.user.is('authenticated') || req.reject(403)
      )
      this.before (['READ', 'CREATE'], 'Orders', req =>
        req.user.is('admin') || req.reject(403)
      )
      this.before ('*', 'Approval', req =>
        req.user.attr.level > 2 || req.reject(403)
      )
    })
    

    Authentication Strategies

    CAP ships with a few prebuilt authentication strategies, used by default: mocked-auth during development and jwt-auth in production. You can override these defaults and configure the authentication strategy to be used through the cds.requires.auth config option in cds.env, for example:

    "cds": { // in package.json
      "requires": { 
        "auth": { "kind": "jwt-auth" }
      }
    }
    

    Run cds env get requires.auth in your project root to find out the effective authentication config for your current environment.

    Dummy Authentication

    This strategy creates a user that passes all authorization checks. It’s meant for temporarily disabling the @requires and @restrict annotations at development time.

    Configuration: Choose this strategy as follows:

    "cds": { // in package.json
      "requires": {
        "auth": { "kind": "dummy-auth" }
      }
    }
    

    Basic Authentication

    This authentication strategy uses basic authentication to use mock users during development.

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

    Configuration: Choose this strategy as follows:

    "cds": { // in package.json
      "requires": {
        "auth": { "kind": "basic-auth" }
      }
    }
    

    You can optionally configure users as follows:

    "cds": { // in package.json
      "requires": {
        "auth": {
          "kind": "basic-auth",
          "users": {
            "<user.id>": { 
              "password": "<password>", 
              "roles": [ "<role-name>", ... ],
              "userAttributes": { ... }
            },
          }
        }
      }
    }
    

    The default configuration shipped with @sap/cds specifies these users:

      "users": {
        "alice": { "roles": ["admin"] },
        "bob": { "roles": ["builder"] },
        "*": true //> all other logins are allowed as well
      }
    }
    

    This default configuration is merged with your custom configuration such that, by default, logins by alice, bob, and others (*) are allowed.

    If you want to restrict these additional logins, you need to overwrite the defaults:

      "users": {
        "alice": { "roles": [] },
        "bob": { "roles": [] },
        "*": false //> do not allow other users than the ones specified
      }
    

    JWT-based Authentication

    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.

    Prerequisites: You need to add passport to your project:

    npm add passport
    

    Prerequisites: You need to add @sap/xssec to your project:

    npm add @sap/xssec
    

    Configuration: Choose this strategy as follows:

    "cds": { // in package.json
      "requires": {
        "auth": { "kind": "jwt-auth" }
      }
    }
    

    Learn more about testing JWT-based authentication in XSUAA in Hybrid Setup.

    XSUAA-based Authentication

    Authentication kind xsuaa is a logical extension of kind jwt-auth that additionally offers access to SAML attributes through req.user.attr (for example, req.user.attr.familyName).

    Prerequisites: You need to add @sap/xssec to your project:

    npm add @sap/xssec
    

    Configuration: Choose this strategy as follows:

    "cds": { // in package.json
      "requires": {
        "auth": { "kind": "xsuaa" }
      }
    }
    

    See XSUAA in Hybrid Setup below for additional information of how to test this

    It’s recommended to only use this authentication kind if it’s necessary for your use case, as it denotes a lock-in to SAP BTP.

    Custom Authentication

    You can configure an own implementation by specifying an own impl as follows:

    "requires": {
      "auth": {
        "impl": "srv/custom-auth.js" // > relative path from project root
      }
    }
    

    Essentially, custom authentication middlewares must fulfill the req.user contract by assigning an instance of cds.User or a look-alike to the incoming request at req.user.

    XSUAA in Hybrid Setup

    Prepare Local Environment

    The following steps assume you’ve set up the Cloud Foundry Command Line Interface.

    1. Log in to Cloud Foundry:

      cf l -a <api-endpoint>
      

      If you don’t know the API endpoint, have a look at section Regions and API Endpoints Available for the Cloud Foundry Environment.

    2. Go to the project you have 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 package:

       npm install @sap/xssec
      

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

    Create XSUAA Configuration

    The xs-security.json configuration file and the XSUAA service instance created in the following steps are intended for hybrid testing only, because of the modified redirect URL that will not allow login from a deployed application. Make sure to maintain separate files and instances for hybrid testing and use from the cloud.

    1. Compile your CDS model with authentication annotations into a full xs-security.json:

       cds compile srv/ --to xsuaa >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.

      See section Application Security Descriptor Configuration Syntax for more details on configuration options.

    2. Configure the redirect URI:

      Local:

       "oauth2-configuration": {
         "redirect-uris": [
           "http://localhost:5001/"
         ]
       }
      

      SAP Business Application Studio:

      If you’re using SAP Business Application Studio as your development environment, you need to specify the URL of your dev space as a valid redirect URI for the login.

      The format is the following:

       "oauth2-configuration": {
           "redirect-uris": [
           "https://<dev-space-identifier>.<landscape>.applicationstudio.cloud.sap/"
         ]
       }
      

      This is a specific configuration for your dev space and should not be submitted or shared.

      The easiest way to find out your URL is to run your application and copy the URL from the browser.

    3. Create an XSUAA service with this configuration:

       cf create-service xsuaa application bookshop-uaa -c 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

      This step is necessary for locally running apps and for apps deployed on Cloud Foundry.

    Configure the Application

    1. Create a service key:

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

      You do this, to gain access to the XSUAA credentials from your local application.

    2. Bind to the new service key:

       cds bind -2 bookshop-uaa
      

      This adds an uaa section containing the binding and the kind xsuaa to the .cdsrc-private.json file. This file is created if it doesn’t exist and keeps the local and private settings of your app:

       {
         "requires": {
           "[hybrid]": {
             "uaa": {
               "kind": "xsuaa",
               "binding": { ... }
             }
           }
         }
       }
      

      If your running in BAS, you can alternatively create a new run configuration, connecting the uaa to your XSUAA service instance.

    3. Enhance your .cdsrc-private.json file by an auth section for the hybrid profile inside the requires block:

       {
         "requires": {
           "[hybrid]": {
             "auth": { "kind": "jwt-auth" }
           }
         }
       }
      

      This configuration, together with the bound uaa credentials, is used by the Node.js runtime to validate the JWT token. To verify it, run:

       cds env list requires.uaa --resolve-bindings --profile hybrid
      

      This prints the full uaa configuration including the credentials.

      If you chose the BAS run configuration, you should add the environment variable cds_requires_auth_kind=jwt-auth to the run configuration instead.

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

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

    Set Up the Roles for the Application

    By creating a service instance of the xsuaa service, all the roles from the xs-security.json file are added to your subaccount. Next, you create a role collection that assigns these roles to your users.

    1. Open the SAP BTP Cockpit.

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

    2. Navigate to your subaccount and then choose Security > Role Collections.
    3. Choose Create New Role Collection:

      Create role collections

    4. Enter a Name for the role collection, for example BookshopAdmin, and choose Create.
    5. Choose your new role collection to open it and switch to Edit mode.
    6. Add the admin role for your bookshop application (application id bookshop!a<XXXX>) to the Roles list.
    7. Add the email addresses for your users to the Users list.
    8. Choose Save

    Running Approuter

    The approuter component implements the necessary authentication flow 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 and check the user’s roles.

    1. Create a file app/package.json with the following content:

       {
           "name": "approuter",
           "scripts": {
               "start": "node node_modules/@sap/approuter/approuter.js"
           }
       }
      
    2. Install the latest approuter package:

       cd app
       npm install @sap/approuter
      
    3. Create the approuter configuration file app/xs-app.json with the following content:

       {
           "routes": [{
               "source": "^/(.*)",
               "destination": "srv_api"
           }]
       }
      
    4. Create a file app/default-env.json with the following content:

      {
       "destinations" : [
         {
           "name": "srv_api",
           "url": "<service-url>",
           "forwardAuthToken": true
         }
       ],
       "PORT": 5001
      }
      

      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

      You need to specify port 5001, because approuter’s default port 5000 is taken by Apple macOS Monterey.

    5. In your project folder run:

       cds bind --exec -- npm start --prefix app
      

      Learn more about cds bind --exec.

      This starts an approuter instance on http://localhost:5001 with the credentials for the XSUAA service that you have bound using cds bind.

      Usually the approuter is started using npm start in the app folder. But you need to provide the VCAP_SERVICES variable with the XSUAA credentials. With the cds bind --exec command you can launch an arbitrary command with the VCAP_SERVICES variable filled with your cds bind service bindings.

      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. Make sure that your CAP application is running as well with the hybrid profile:

       cds watch --profile hybrid
      
    7. After the approuter and CAP application are started, log in at http://localhost:5001 and verify that the routes are protected as expected.

      In our example, if you assigned the admin scope to your user in SAP BTP cockpit, you can now access the admin service at http://localhost:5001/admin.


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