Is it possible to add Authentication to access to NestJS' Swagger Explorer
Solution 1
Securing access to your Swagger with HTTP Basic Auth using NestJS with Express
First run npm i express-basic-auth
then add the following to your main.{ts,js}
:
// add import
import * as basicAuth from 'express-basic-auth';
// ...
// Sometime after NestFactory add this to add HTTP Basic Auth
app.use(
['/docs', '/docs-json'],
basicAuth({
challenge: true,
users: {
yourUserName: 'p4ssw0rd',
},
}),
);
// Your code
const options = new DocumentBuilder()
.setTitle('My App')
.setSchemes('https')
.setDescription('My App API documentation')
.setVersion('1.0')
.build()
const document = SwaggerModule.createDocument(app, options)
SwaggerModule.setup('docs', app, document, {
customSiteTitle: 'My App documentation',
})
// ...
With this in place you will be prompted on any of the /docs
route with a HTTP Basic Auth prompt. We have to name /docs-json
explicitly too, to protect the generated JSON OpenAPI file.
You should not put the credentials in your code/repository but rather in your .env
and access via the ConfigService.
I have seen this solution first here.
Solution 2
Just add .addBearerAuth()
(without any parameters) to your swagger options
and @ApiBearerAuth()
to your Controller methods
const options = new DocumentBuilder()
.setTitle('My App')
.setSchemes('https')
.setDescription('My App API documentation')
.setVersion('1.0')
.addBearerAuth()
.build()
Solution 3
UPDATE
As per recent changes in DocumentBuilder
methods, this how it worked for me. Sharing for the people who are using new versions.
const options = new DocumentBuilder()
.setTitle('My API')
.setDescription('API used for testing purpose')
.setVersion('1.0.0')
.setBasePath('api')
.addBearerAuth(
{ type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
'access-token',
)
.build();
const document = SwaggerModule.createDocument(app, options);
Update Also, please use @ApiBearerAuth()
on your controller function to add auth.
@Get('/test')
@ApiBearerAuth()
access-token
is the name for reference in swagger doc. Your token in the header will be passed as below:
curl -X GET "http://localhost:3004/test" -H "accept: application/json" -H "Authorization: Bearer test-token"
Solution 4
Updated following breaking/API changes in @nestjs/swagger version 4.0.
Hi, Took a lot of try&fail to get this right. The comments in the code is what is important to understand. The names rely on each other for this to work.
main.ts
const options = new DocumentBuilder()
.setTitle('my-title')
.setDescription('my-descirption')
.setVersion('1.0')
.addBearerAuth(
{
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
name: 'JWT',
description: 'Enter JWT token',
in: 'header',
},
'JWT-auth', // This name here is important for matching up with @ApiBearerAuth() in your controller!
)
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
And in your controller you do the following (note @ApiBearerAuth() using the same name as the name on the swagger options in main.ts):
app.controller.ts
@Roles(Role.Admin)
@UseGuards(JwtAuthGuard, RolesGuard)
@ApiTags('Admin')
@ApiOperation({ summary: 'Get admin section' })
@Get('admin')
@ApiBearerAuth('JWT-auth') // This is the one that needs to match the name in main.ts
getAdminArea(@Request() req) {
return req.user;
}
Hope this saves somebody the time it took me to understand what was going on.
Solution 5
For anyone with similar challenge, you can add Authentication to your Swagger UI in Nestjs as shown below.
const options = new DocumentBuilder()
.setTitle('Sample Project API')
.setDescription('This is a sample project to demonstrate auth in Swagger UI')
.setVersion('1.0')
.addTag('Nestjs Swagger UI')
.setContactEmail('[email protected]')
.addBearerAuth('Authorization', 'header', 'basic')
.setBasePath('api')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('docs', app, document);
So .addBearerAuth takes 3 arguments (key-name, location, authentication-type). authorization-type can be basic
, bearer
or apikey
josec89
Updated on July 09, 2022Comments
-
josec89 almost 2 years
I'm currently using Swagger in my NestJS project, and I have the explorer enabled:
in
main.js
const options = new DocumentBuilder() .setTitle('My App') .setSchemes('https') .setDescription('My App API documentation') .setVersion('1.0') .build() const document = SwaggerModule.createDocument(app, options) SwaggerModule.setup('docs', app, document, { customSiteTitle: 'My App documentation', })
With this, the explorer is accessible in
/docs
which is what I expected. But I was wondering if it's possible to add any Authentication layer to the explorer, so only certain requests are accepted.I want to make this explorer accessible in production, but only for authenticated users.
Thanks in advance :)
-
chrismarx over 4 yearsI got an error when specifying "bearer" as the authentication-type to the .addBearerAuth method. Turns out if you just don't include the third parameter, it enables bearer authentication. Using the 'basic' value did turn on username/password http auth-
-
Lu Blue about 4 yearsthey made a huge change on the DocumentBuilder methods and their params, I hope someone makes an example of this changes.
-
Jacobdo almost 4 yearsSomehow this does not work for me, the header does not get applied to the request - the curl output stays - curl -X GET "localhost:3000/unit-type" -H "accept: /"
-
pravindot17 almost 4 years@Jacobdo can you see lock icon on your endpoint in swagger doc? You can click on it and pass the access token, if not then you need to add
@ApiBearerAuth()
in controller function, see updated answer -
Maciej Sikorski almost 4 yearsThis tells about the security of your endpoints, not the swagger itself.
-
Ali Turki over 3 yearsjust
.addBearerAuth({ in: 'header', type: 'http' })
-
KiwiKilian almost 3 yearsThe question is about securing access to the swagger page itself, not showing the auth options on routes swagger displays. See my answer for actually securing your
/docs
endpoint with HTTP Basic Auth. -
Pini Cheyni almost 3 yearsI followed this demo with the swagger4 but I'm having an issue with the scopes object, To register the API I used the scopeURL, and when I set only the name like you suggested profile, I get an error which says that I can't request this scope
-
CyberEternal almost 3 yearsActually, I have not used the scopeURL. I have set the scope as an object like in an example. and there can be added many properties like
{profile: 'profile', email:'email', ...}
. The value ofscopes
can be also an array, like['profile', 'email', ...]
. But I'm not sure that you can use scopeURL as a value of thescope
parameter since it can't be a string. You can check the module codes and see that. -
riqitang over 2 yearsit'd be even better if it didn't require the
@ApiBearerAuth
decorator on controllers/routes. -
CTS_AE about 2 yearsI assumed the top level bearer would apply it to everything, but I was wrong -- I guess you really do need it on every controller. Edit: is there any way to persist the authentication between refreshes?