Node.js Login with Express and OIDC

Node.js Login with Express and OIDC

This screencast shows you how to create an Express app and add login to it in just a few steps.

nikivancic

Thank you Matt for pointing me to this tutorial as it made me aware of github.com/oktadeveloper/schematics - a worldclass addition to anyone trying to “arm” the code for proper use of Okta’s OIDS SDKs (I now know that it was the Angular team that delivered this innovation, but making is specific to Okta is great and appreciated job).

nikivancic

Running the command npm i @oktadev/schematics schematics @oktadev/schematics:add-auth --issuer=$<a href="https://dev-487304.okta.com/oauth2/default" rel="nofollow noopener" title="https://dev-487304.okta.com/oauth2/default">https://dev-487304.okta.com...</a> --clientId=$myclientid --clientSecret=$myclientsecret

results with (removed the irrelevant stuff)


verbose stack Error: ENOENT: no such file or directory, open ‘c:\work\learning\okta\okta-nodejs-login-example@oktadev\schematics:add-auth\package.json’

error Could not install from “@oktadev\schematics:add-auth” as it does not contain a package.json file.

why would “@oktadev\schematics:add-auth” expect a package.json file (note that there is a package.json file in the root level of the project’s folder.

Second question is simpler: are the $ characters parts of the “npm i @oktadev …” command?

Matt Raible

Can you try running the command from the root directory? It adds dependencies to package.json, that’s why it’s needed.

You need to substitute the $variable placeholders with actual values.

nikivancic

I am indeed running this command at the root level - the difference between your case and mine is that I am using Windows 10 PRO version 1903.

https://uploads.disquscdn.c…

On ‘$’ question: I was not sure whether the ‘$’ should remain on the command line or not, Your answer still leaves this question open :slight_smile:

Matt Raible

No, the $ should not be included. You should run “npm i @oktadev/schematics” on one line, and the schematics command on the next. You can watch the video in this post to see how to do it.

nikivancic

If I would guess based on watching your video (which tells me that you are using MacOS) my problem with using schematics, ought to be a consequence of insufficient access rights to package.json file (on Windows)

nikivancic

A bit more information: this statement from the "debug.log"
16 verbose stack Error: ENOENT: no such file or directory, open 'c:\work\learning\okta\okta-nodejs-login-example@oktadev\schematics:add-auth\package.json’
seems to indicate that the “schematics” has a bad reference of the package.json file (the path “@oktadev\schematics:add-auth” does not exist)

Matt Raible

Hmmmm, I’m not sure why this doesn’t work for you. I just tried using Windows 10 and it worked fine for me.

https://uploads.disquscdn.c…

The only thing I can think of is to try installing WSL.

nikivancic

I found the problem: and it is of my doing: i took the whole content of of the step4 (at the beginning of your written tutorial above


npm i @oktadev/schematics
schematics @oktadev/schematics:add-auth --issuer=$issuer --clientId=$clientId --clientSecret=$clientSecret

as one command - what I should have done is this

schematics @oktadev/schematics:add-auth --issuer=$issuer --clientId=$clientId --clientSecret=$clientSecret

This time I get:

λ schematics @oktadev/schematics:add-auth --issuer=$https://dev-487304.okta.com/oauth2/default --clientId=$0oarifhve59q3PrM84x6 --clientSecret=$YtnXc6qGCmDegWQOoj_gwg8CMA6rKqgRRz1MODCV
:white_check_mark::white_check_mark: Added ‘express-session’ into dependencies
:white_check_mark::white_check_mark: Added ‘@okta/oidc-middleware’ into dependencies
:white_check_mark::white_check_mark: Added ‘dotenv’ into dependencies
� Installing packages…
CREATE .env (228 bytes)
UPDATE app.js (1677 bytes)
UPDATE routes/index.js (316 bytes)
UPDATE views/index.pug (162 bytes)
UPDATE views/login.pug (90 bytes)
√ Packages installed successfully.

If there is anything to be changed in this sample, it is to provide a better indication that the step 4 consists of two commands.

Thanks a lot for staying with me throughout this thread - now I have a piece of rope that can help me understand why is it that every single attempt to run Okta samples failed - and failed the same way each time

Matt Raible

I’m glad you got it working! I see in your output that you still have “$” in the values. You should edit the created .env and remove these from the values.

nikivancic

I actually did not it work until completion - just managed to run the schematics tool correctly (the extra $ in OIDC Issuer was my typo when creating the schematic command line.

I observed that .env file does not contain the callback definition, and the schematics tool does not generate that route. Since I cannot see your Okta application definition, I am not sure whether this is a bug or a feature. Either way running npm start I get the page with Login link and click on that link results with

400: Bad Request
BAD REQUEST

Your request resulted in an error.

It seems that my problems ought to be in the Okta app setup - as all of my attempts end this same way. Not sure how to get through the Authorize step with the debugger, so I will look around to find some hints

Matt Raible

When you get a 400 error, it’s caused by an invalid redirect URI or an invalid client ID. If the 400 error page says invalid redirect, you can look at the URL in your browser and see the “redirect_uri” it’s trying to use. If you pop that into the Login redirect URI’s list in your Okta app, it’ll solve the problem.

As far as setting up the app on Okta, you’ll need to do that manually (step 2 above).

nikivancic

The client ID is verified as correct, and the callback uri is set (in Okta application) as http://localhost:3000

Note that the sample okta-nodejs-login-example has all of its files generated by either express-generator or schematics tools and neither creates the route that fits http://localhost:3000. So, I ought to be confused with something and will dive deeper, not to bug you any more. Once I find my problem, I will certainly let you know is the problem was on Okta’s side.

Again, thanks for your gigantic patience. I hated when I was in your role, planning to do something interesting and was receiving endless string of questions

Matt Raible

The callback on Okta should be http://localhost:3000/callback. When you use OktaDev Schematics to configure your app, it configures a /callback route in app.js:


var app = express();
const oidc = new ExpressOIDC({
issuer: process.env.OIDC_ISSUER,
client_id: process.env.OIDC_CLIENT_ID,
client_secret: process.env.OIDC_CLIENT_SECRET,
appBaseUrl: process.env.BASE_URL,
loginRedirectUri: ${process.env.BASE_URL}/callback,
scope: ‘openid profile’,
routes: {
loginCallback: {
path: ‘/callback’
},
}
});

If you don’t like this path, you can change it to whatever you like. You just have to make sure the login redirect URI matches on Okta.

Karthik Guduri

@mattraible Hope you’re doing good. I have 2 applications which share same application home page after successful login. Initially i used @okta/oidc-middleware in nodejs for authentication for app1. Now i got a requirement to configure app2. How can i create multiple instances of express oidc routers in node.js. Can you please help me out. Bottom Line need to implement common login for 2 domains with (abc.com/abc-login, bcd.com/bc-login) in one node js application using @okta/oidc-middleware .

Matt Raible

I’m on vacation for the next two weeks. Can you please enter an issue in the OIDC middleware project with your question? https://github.com/okta/okt…

Vasanth Rajaraman

Thanks @mattraible . I just followed your steps to create the app and it worked like magic without making any changes. However i wanted to change the storage for session data with session-file-store, so i initialized it like below:

var FileStore = require(‘session-file-store’)(session);
var fileSessionStore = new FileStore();

And linked it with app as below:

app.use(session({
store: fileSessionStore,
secret: process.env.SESSION_SECRET,
resave: true,
saveUninitialized: false
}));

And with the above changes when I login to the app, it’s rendering me the login.pug file. (For some reason in index route the req.userContext is not set).
And if i click login link in that page again, it’s making the “authorize” call to OKTA and the “callback” call to my local server, and renders me the login.pug again from index routing. https://uploads.disquscdn.c…

Could you please provide some hint on this?

Vasanth Rajaraman

It looks like an issue with SessionFileStore, when i switch it with redis or other stores it works nicely. Thanks.

Matt Raible

Thanks for letting us know that you figured out a solution!