- Introduction & Specifications
- Installation
- Authorization server
- Resource server
- Security considerations
OAuth2 | Various Implementations for open authorization
This is a TypeScript implementation of OAuth2 as documented at RFC6749. Many thanks to the OAuth 2.0 Simplified website. It was a significant help as a starting point while developing this library.
You can see with more detail the specs that was used below:
- RFC6749: OAuth 2.0 Core
- RFC6750: Bearer Tokens
- RFC6819: Threat Model and Security Consideration
- RFC7009: Token Revocation
- RFC7515: JSON Web Signature
- RFC7519: JSON Web Token
- RFC7636: PKCE Extension
- RFC7662: Token Introspection
- RFC8252: OAuth 2.0 for Native Apps
- RFC8628: Device Authorization Grant
- RFC9068: JWT Profile for OAuth 2.0 Access Tokens
- OAuth 2.0 Security Best Current Practice
- RFC9068 (JWT Profile for OAuth 2.0 Access Tokens)
- The claim
sub
(subject) must contain the user's or client'd id. The user's id in this library can be any valid json or primitive type which does not comply with the claim's (sub
) type which is string. It will be replaced inside the payload by the fielduser
and thesub
claim will be string version of it (by callingJSON.stringify(user)
). - The parameter
resource
will not be used, instead the Authorization Server should decide theaudience
claim using theaudience
option.
- The claim
oauth2
library tries to implement most of the features of OAuth2 and its extensions.
If you want to request a new feature (e.x. implementing a new flow) or report a bug
you can always open a new issue. In case it is related to OAuth2 spec or it's extensions
you must
include the related spec.
This library is not in npm. To use it you have to clone the repository to
your machine and use the link
command:
# Clone
git clone https://github.com/JexSrs/oauth2.git
# Go to your project
cd my-project
# and link
npm link ../oauth2
The core of this library, it will create Express
end-middlewares that will be attached
to your server and handle the oauth requests.
import {AuthorizationServer, authorizationCode} from "oauth2";
// Create new instance
const authServer = new AuthorizationServer({/* options */});
// Register a new flow
authServer.use(authorizationCode({/* options */}));
// Register endpoints
app.get('/oauth/v2/authorize', isLoggedIn, authServer.authorize());
app.post('/oauth/v2/token', authServer.token());
Click here for more details about the authorization server.
Flow
refers to an OAuth2 Grant Type
. The AuthorizationServer
can implement one or more different flows, without one affecting the other.
The oauth2
library comes together with some of the most popular flows:
Authorization Code
Client Credentials
Device Authorization
Implicit
Refresh Token
Resource Owner Credentials
If the flows above does not match your needs you can always create one for yourself.
To create one you have to inherit the Flow
interface and like the
rest of the flows above import them to your AuthorizationServer
instance:
authServer.use(my_flow);
Click here for mor details about how to create a new flow.
A successful OAuth2 response is a response that does not return an error.
Interceptor
is a function that will be called to alter a successful OAuth2 response.
It can be called from all
endpoints
and intercept all successful responses.
Interceptors are useful in case you want to append more information to a response. For example Google-OAuth2 will return an email alongside the tokens.
To use an interceptor you have to call the intercept
function:
authServer.intercept(myInterceptor);
Interceptors are called with the order they are registered.
Click here for mor details about how to create a new interceptor.
Using the NodeJs EventEmitter
the oauth2
library provides a set of useful events to help you keep track the progress of all the flows.
All you have to do is import
the Events
object and listen to the desired event:
import {Events} from "oauth2";
authServer.on(Events.EVENT_NAME, function (req) {
// ...
});
Click here for more details about the oauth2
events.
The AuthorizationServer
instance provides
some functions to assign to your endpoints to expose the OAuth2 flows to your
Express
server.
These functions are:
authorize
: To expose the authorization flow (where the user authorizes an application).token
: To expose the token flow (where an app requests for tokens).device
: Used for theDevice Authorization
flow.introspection
: A mechanism for the resource servers to obtain information about access tokens.revocation
: To allow access or refresh tokens revocation.authenticate
: A way to authenticate access tokens (if authorization and resource server are the same).
Click here for more details about functions and endpoints.
If you have read all the documentation so far I am sure you have noticed how all options that provide
a function (method) also pass an Ecpress Request
instance of the current request. Using that object
you can create a state between the called option functions (methods).
For example:
// During authorization
validateRedirectURI: async (client_id, redirect_uri, req) => {
return !!(await db.findClient(client_id, redirect_uri));
}
// And then during scope validation
validateScopes: async (scopes, req) => {
const client = await db.findClient(client_id, redirect_uri);
return scopes.every(scope => client.scopes.includes(scope));
}
can be transformed into this:
// During authorization
validateRedirectURI: async (client_id, redirect_uri, req) => {
const client = await db.findClient(client_id, redirect_uri);
if(!client) return false;
// The scopes a client is allowed to request.
// Depending on the implementation in may be all the available scopes
req.scopes = client.scopes;
return true;
}
// And then during scope validation
// One less request.
validateScopes: (scopes, req) => scopes.every(scope => req.scopes.includes(scope));
To be able to achieve this, the order where the options are called is necessary.
Read more at the break-down section of the
functions
and about each flow
.
The resource server is the OAuth 2.0 term for your API server. The resource server handles authenticated requests after the application has obtained an access token.
import {ResourceServer} from "oauth2";
const resoourceServer = new ResourceServer({/* options */});
Click here for more details about the resource server.
The oauth2
library will try its best to protect you from outside threats, but the problems
does not end there. Leakage of codes and access tokens can happen from the authorization server
or the client's side.
Click here for more details.