- General info
- Configure Auth
- Auth via Apple
- Auth via Facebook
- Auth via Google
- About JWT strategy
- Refresh token flow
- Logout
- Q&A
By default boilerplate used sign in and sign up via email and password.
sequenceDiagram
participant A as Fronted App (Web, Mobile, Desktop)
participant B as Backend App
A->>B: 1. Sign up via email and password
A->>B: 2. Sign in via email and password
B->>A: 3. Get a JWT token
A->>B: 4. Make any requests using a JWT token
auth-email.mp4
Also you can sign up via another external services or social networks like Apple, Facebook and Google.
sequenceDiagram
participant B as External Auth Services (Apple, Google, etc)
participant A as Fronted App (Web, Mobile, Desktop)
participant C as Backend App
A->>B: 1. Sign in through an external service
B->>A: 2. Get Access Token
A->>C: 3. Send Access Token to auth endpoint
C->>A: 4. Get a JWT token
A->>C: 5. Make any requests using a JWT token
For auth with external services or social networks you need:
-
Sign in through an external service and get access token(s).
-
Call one of endpoints with access token received in frontend app on 1-st step and get JWT token from the backend app.
POST /api/v1/auth/facebook/login POST /api/v1/auth/google/login POST /api/v1/auth/apple/login
-
Make any requests using a JWT token
-
Generate secret keys for
access token
andrefresh token
:node -e "console.log('\nAUTH_JWT_SECRET=' + require('crypto').randomBytes(256).toString('base64') + '\n\nAUTH_REFRESH_SECRET=' + require('crypto').randomBytes(256).toString('base64') + '\n\nAUTH_FORGOT_SECRET=' + require('crypto').randomBytes(256).toString('base64') + '\n\nAUTH_CONFIRM_EMAIL_SECRET=' + require('crypto').randomBytes(256).toString('base64'));"
-
Go to
/.env
and replaceAUTH_JWT_SECRET
andAUTH_REFRESH_SECRET
with output from step 1.AUTH_JWT_SECRET=HERE_SECRET_KEY_FROM_STEP_1 AUTH_REFRESH_SECRET=HERE_SECRET_KEY_FROM_STEP_1
-
Change
APPLE_APP_AUDIENCE
in.env
APPLE_APP_AUDIENCE=["com.company", "com.company.web"]
-
Go to https://developers.facebook.com/apps/creation/ and create a new app
-
Go to
Settings
->Basic
and getApp ID
andApp Secret
from your app -
Change
FACEBOOK_APP_ID
andFACEBOOK_APP_SECRET
in.env
FACEBOOK_APP_ID=123 FACEBOOK_APP_SECRET=abc
-
You need a
CLIENT_ID
,CLIENT_SECRET
. You can find these pieces of information by going to the Developer Console, clicking your project (if doesn't have create it here https://console.cloud.google.com/projectcreate) ->APIs & services
->credentials
. -
Change
GOOGLE_CLIENT_ID
andGOOGLE_CLIENT_SECRET
in.env
GOOGLE_CLIENT_ID=abc GOOGLE_CLIENT_SECRET=abc
In the validate
method of the src/auth/strategies/jwt.strategy.ts
file, you can see that we do not check if the user exists in the database because it is redundant, it may lose the benefits of the JWT approach and can affect the application performance.
To better understand how JWT works, watch the video explanation https://www.youtube.com/watch?v=Y2H3DXDeS3Q and read this article https://jwt.io/introduction/
// src/auth/strategies/jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
// ...
public validate(payload) {
if (!payload.id) {
throw new UnauthorizedException();
}
return payload;
}
}
If you need to get full user information, get it in services.
- On sign in (
POST /api/v1/auth/email/login
) you will receivetoken
,tokenExpires
andrefreshToken
in response. - On each regular request you need to send
token
inAuthorization
header. - If
token
is expired (check withtokenExpires
property on client app) you need to sendrefreshToken
toPOST /api/v1/auth/refresh
inAuthorization
header to refreshtoken
. You will receive newtoken
,tokenExpires
andrefreshToken
in response.
Refresh.Token.mp4
Boilerplate supports login for multiple devices with a Refresh Token flow. This is possible due to sessions
. When a user logs in, a new session is created and stored in the database. The session record contains sessionId (id)
, userId
, and hash
.
On each POST /api/v1/auth/refresh
request we check hash
from the database with hash
from the Refresh Token. If they are equal, we return new token
, tokenExpires
, and refreshToken
. Then we update hash
in the database to disallow the use of the previous Refresh Token.
-
Call following endpoint:
POST /api/v1/auth/logout
-
Remove
access token
andrefresh token
from your client app (cookies, localStorage, etc).
After POST /api/v1/auth/logout
or removing session from the database, the user can still make requests with an access token
for some time. Why?
It's because we use JWT
. JWTs
are stateless, so we can't revoke them, but don't worry, this is the correct behavior and the access token will expire after the time specified in AUTH_JWT_TOKEN_EXPIRES_IN
(the default value is 15 minutes). If you still need to revoke JWT
tokens immediately, you can check if a session exists in jwt.strategy.ts on each request. However, it's not recommended because it can affect the application's performance.
Previous: Working with database
Next: Serialization