cancel
Showing results for 
Search instead for 
Did you mean: 

CDS/CAP/Node.js cannot get XSUAA to work locally

Dear community,

I am trying to get authentication via SCP's XSUAA service working while running my CAP/Node.js app locally during development.

I have followed the instructions on https://cap.cloud.sap/docs/node.js/authentication to build JWT based authentication into my CAP app. When I deploy the app to SCP, authentication works as expected. However, when I try to run the same app locally and provide the XSUAA service in default-env.json, the service component returns a 403 with Unsuccessful Login Attempt in the console log.

To test this I have built a barebone app from scratch. You can review the implementation here:

https://github.com/manuelseeger/cap-auth-xsuaa

This works perfectly fine when deployed to SCP trial. I have assigned the CA_Admin scope to a role collection assigned to my user. When I access the approuter component in SCP it forwards me to login and after the protected services are accessible.

When I try the same locally, the approuter also forwards me to the SCP login screen. The JWT token comes back as expected. But, the service component returns 403.

Log of the service:

Log of the app router:

Before the JWT token is logged as above, the app router prints the following to the log:

#2.0#2020 03 17 13:06:18:854#+01:00#INFO#/Auth/OAuth2#####k7vupaze####c46AFZAVSeyC34rlCLyuB-pGfQubl3NM######k7vupaze#PLAIN##req.url: /#
#2.0#2020 03 17 13:06:18:855#+01:00#INFO#/Auth/OAuth2#####k7vupaze####c46AFZAVSeyC34rlCLyuB-pGfQubl3NM######k7vupaze#PLAIN##sending page with client-side redirect to https://s0015861181trial.authentication.eu10.hana.ondemand.com/oauth/authorize?response_type=code&cl...
#2.0#2020 03 17 13:06:18:855#+01:00#INFO#/Auth/OAuth2#####k7vupaze####c46AFZAVSeyC34rlCLyuB-pGfQubl3NM######k7vupaze#PLAIN##x-forwarded-path header: undefined#

I have copied the VCAP_SERVICES environmental variable from the app's approuter component on SCP and copied that into the default-env.json in both the root and the app/ directory of my CAP application, as described in the documentation.

My default-env.json looks like this:

{
    "destinations": [
        {
            "name": "srv-binding",
            "url": "http://localhost:4004",
            "forwardAuthToken": true,
            "strictSSL": false
        }
    ],
    "VCAP_SERVICES": {
        "xsuaa": [
         {
          "binding_name": null,
          "credentials": {
           "apiurl": "https://api.authentication.eu10.hana.ondemand.com",
           "clientid": "sb-cap-auth-xsuaa!t38354",
           "clientsecret": "ommitted",
           "identityzone": "s0015861181trial",
           "identityzoneid": "cfeeccea-a2c7-4284-b65f-ab1f13f02699",
           "sburl": "https://internal-xsuaa.authentication.eu10.hana.ondemand.com",
           "tenantid": "cfeeccea-a2c7-4284-b65f-ab1f13f02699",
           "tenantmode": "dedicated",
           "uaadomain": "authentication.eu10.hana.ondemand.com",
           "url": "https://s0015861181trial.authentication.eu10.hana.ondemand.com",
           "verificationkey": "-----BEGIN PUBLIC KEY-----[ommitted]-----END PUBLIC KEY-----",
           "xsappname": "cap-auth-xsuaa!t38354"
          },
          "instance_name": "cap-auth-xsuaa-uaa",
          "label": "xsuaa",
          "name": "cap-auth-xsuaa-uaa",
          "plan": "application",
          "provider": null,
          "syslog_drain_url": null,
          "tags": [
           "xsuaa"
          ],
          "volume_mounts": []
         }
        ]
       }
}

And this seems to do the trick since I am getting the login screen from SCP and I can login and receive my JWToken. But the locally running service just does not accept it and keeps returning 403.

Any idea how I can make XSUAA authentication work locally? I have been working on this for days now and nothing seems to do the trick.

Best regards,

Manuel

Accepted Solutions (1)

Accepted Solutions (1)

Hi everyone,

it looks like I finally managed to fix it. I checked cds env and found that auth.passport.strategy was set to mock if run locally. This is a bit surprising to me as I have not configured a mock strategy anywhere, and as far as I understand the documentation, the JWT strategy should be deducted from the installed @sap/xssec package.

https://cap.cloud.sap/docs/node.js/authentication#how-the-authentication-strategy-is-detected

I now added a .cdsrc.json file with explicit configuration of the strategy:

{
    "auth": {
        "passport": {
            "strategy": "JWT"
        }
    }
}

This seems to do the trick. The service now accepts the JWToken.

Maybe someone can explain why the detection of the JWT strategy doesn't work implicitly in this case?

Best regards,

Manuel

Ivan-Mirisola
Product and Topic Expert
Product and Topic Expert

Hi seegerm

If you take a look at "node_modules\@sap\cds\lib\env\defaults.js" you will see that the default strategy equals to "mock" with some default users.

Hence, this is the reason why you must declare the strategy as "JWT" somewhere if you want to authenticate users against you account's IdP in SCP.

If you type the following command at the root of your project:

cds env src 

You will get a list of files in processing order - where such variable should be placed. The first one to grab the value for auth.passport.strategy wins. I didn't play with the profiles defined under the variable NODE_ENV. Technically it would be possible to switch back and forth between JWT and MOCK just by changing the value of NODE_ENV.

If you enter the following command at the root of your project:

cds env list requires.uaa

In case you have JWT configured properly, you should get just a single line like the following (in your case, you've entered it on .cdsrc, hence it won't be under requires):

requires.auth.credentials.* = stuff you've entered in the default-env.json file

Here is an excerpt from my project:

requires.uaa.credentials.apiurl = https://api.authentication.eu10.hana.ondemand.com
requires.uaa.credentials.clientid = Jajajajajajajaaj!t39993
requires.uaa.credentials.clientsecret = Jajajajajajajaaj=
requires.uaa.credentials.identityzone = Jajajajajajajaaj
requires.uaa.credentials.identityzoneid = Jajajajajajajaaj
requires.uaa.credentials.sburl = https://internal-xsuaa.authentication.eu10.hana.ondemand.com
requires.uaa.credentials.tenantid = Jajajajajajajaaj
requires.uaa.credentials.tenantmode = dedicated
requires.uaa.credentials.uaadomain = authentication.eu10.hana.ondemand.com
requires.uaa.credentials.url = https://Jajajajajajajaaj.authentication.eu10.hana.ondemand.com
requires.uaa.credentials.verificationkey = -----BEGIN PUBLIC KEY-----Jajajajajajajajaja==-----END PUBLIC KEY-----
requires.uaa.credentials.xsappname = Jajajajajajajaaj!t39993
requires.uaa.kind = xsuaa

If you enter the following command at the root of your project:

cds env list auth.passport

You should get the JWT strategy defined in your package.json file. It must match exactly like the line below:

auth.passport.strategy = JWT

Here you may notice that you will also get the default local users (bob and alice). But, since the strategy is no longer mock, you could safely disregard those values.

auth.passport.users.* = true
auth.passport.users.alice.roles = [ 'admin' ]
auth.passport.users.bob.roles = [ 'builder' ]

NOTE1: Previously I had mistakenly entered the auth.passport.strategy part as part of the requires, not as part of cds directly. So, one more reason why it was not working like it was supposed to.

NOTE2: The VCAP_SERVICES template from the documentation does work for both AppRouter and the root of your MTA. No need to adapt it or change the xsuaa name to uaa. Just copy the entire VCAP_SERVICES from the root default-env.json file into the AppRouter's file under the destination declaration - and it should work without any modifications to it. I removed the default-services.json entirely and it is now working without it.

I've opened an issue for the product owners to add to the documentation the part about auth.passport.strategy = JWT. It is indeed missing on the documentation. I'm confident they will update the documentation and will post any updates here once they let me know.

Hope this clarifies.

Best regards,
Ivan

0 Kudos

Hi ivan.mirisola ,

Thanks for the explanation. Can you please expand why default-services is the correct place for this type of configuration? I followed the documentation at https://cap.cloud.sap/docs/advanced/config when I tried to figure out where to put what and it makes no mention of default-services.

Best regards,

Manuel

Ivan-Mirisola
Product and Topic Expert
Product and Topic Expert

Hi Manuel Seeger,

That's what I'm trying to figure out with the product team. As soon as I get an answer I'll share here.

Best regards,
Ivan

Ivan-Mirisola
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Manuel Seeger,

I've updated my answer with more details about the issues we've faced.

Hope this time it makes more sense to you.

Best regards,
Ivan

Answers (3)

Answers (3)

gregorw
Active Contributor

Hi Manuel,

does the package.json for your CAP Service contain a section auth.passport.stratey:

	"cds": {
		"requires": {
			"db": {
				"kind": "hana",
				"model": "gen/csn.json"
			}
		},
		"auth": {
			"passport": {
				"strategy": "JWT"
			}
		}
	}

like in my sample project: package.json#L27? During debugging I found this parameter. I would think it must be added to the documentation Token-Based Authentication (JWT).

Best regards
Gregor

0 Kudos

Hi Greg,

yes, this seems to be the reason. I also think the documentation is off here - see my answer below.

Thanks!

sapdeveloper_
Explorer

Hello Gregor Wolf,

I am facing the same issue. Although I already have added the code block (suggested by you ) in package.json file.

And also have updated default-env.json with destination and xsuaa properties copied from the app router ( as an application in CF)

Thanks in advance.

Regards,

Sandeep

david_kunz2
Advisor
Advisor
0 Kudos

Hi Manuel,

Which `@sap/cds` version are you using?

It seems the scopes are not included. I don't know why there is a difference compared to the Cloud Foundry one. Did you try with the environmental variable `NODE_ENV=production`?

Thanks and best regards,
David

0 Kudos

Hi David,

I am running @sap/cds@3.31.2. Can you expand on what you mean by the scopes are not included? They are included in the JWToken if that is what you mean.

Do you mean run it locally with the production profile? This fails with [ERROR] VError: No service matches xsuaa. at Object.getServices (/Users/manuels/Documents/ccscp/capm_auth/cap-auth-xsuaa/node_modules/@sap/xsenv/lib/xsservices.js:50:15)

Best regards,

Manuel

balbino_soaresferreirafil
Active Participant
0 Kudos

Hi Manuel, are you include the dependencies of "@sap/xsenv" and "@sap/xssec" in your package.json on srv folder?

0 Kudos

I have just tried that, but it makes no difference. The service still returns 403 and logs Unsuccessful login attempt on the protected resources.