Giter Site home page Giter Site logo

udibo / oauth2_server Goto Github PK

View Code? Open in Web Editor NEW
20.0 3.0 4.0 570 KB

A standards compliant implementation of an OAuth 2.0 authorization server with PKCE support.

License: MIT License

TypeScript 100.00%
deno typescript javascript oauth2 oauth2-server oak

oauth2_server's People

Contributors

kylejune avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

oauth2_server's Issues

Improve example's refresh token code to prevent session getting revoked

Currently there is no locking in getAccessToken around the refresh token code. If 2 requests come in at the same time, this could result in the token api being called twice for the same refresh token. That would cause the token to get revoked due to token replay prevention measures.

Fix oauth2_server not working with --no-check

denoland/deno#12799

This appears to be a bug in deno. I attempted to resolve the bug by changing how I export/import Scope but was unsuccessful. Watch the above issue on deno for either the issue getting fixed in deno or a possible way to resolve the issue in this module.

Until this issue is resolved, this module cannot be used with the --no-check flag.

Add OAuth2Client for simplifying requests to OAuth2 resource and authorization servers

Currently the example manually refreshes token when it is expired. Create an OAuth2Client object that can handle refreshing tokens and handling authorization flow. The client should have a fetch function to make it easier to make fetch requests to API endpoints that use OAuth2 for authentication.

Add getClientForRequest to server and oak adapter. Add getClientForContext to oak adapter. This will behave similar to getTokenForRequest except it will instead return an OAuth2Client that is ready to make requests for the user. For this to work, the server would need to take some configuration options like the authorizeUrl and tokenUrl.

Add error handler to example oak server

Currently the oak server uses the default error handler for errors that are not handled. Create a simple error handler that logs the error and returns an html page showing the error.

Refactor getAccessToken and add getRefreshToken

The oak-localstorage example uses a session instead of sending the access token and refresh token to the client. I did this because I wasn't sure about best way to store refresh token in the client.

I now believe it is safe to store the refresh token and access token in http only secure cookies. To avoid sending the refresh token with every request, the refresh token cookie can have the token endpoint specified as the cookie path.

https://stackoverflow.com/questions/68620374/store-access-token-and-refresh-token-in-cookies

To make this change, I will need to update the refresh token grant to have a callback option for an alternative way of getting the refresh token. In the example I will have it check for a refresh token cookie.

The getAccessToken option should be moved to the ResourceServer constructor since there would only ever be one getAccessToken function for a resource server. The Oak adapter for resource server currently takes getAccessToken in the constructor. Once this change is made, that can be removed. The getAccessToken function will no longer need a requireRefresh argument since refreshing will be left to the client.

I have another issue open that will make it easier for the client to handle request failures due to access token expiration and refreshing tokens.

#17

Add requireRefresh arg to custom getAccessToken

If the custom access token value is invalid, authenticate should call getAccessToken again with a flag indicating that the access token needs refreshed. If it cannot be refreshed, that function should return null to indicate that authentication is required.

Add allowRefreshToken

Add an allowRefreshToken function to token service for determining if a refresh token should be generated based on client, user, and scope. This could be useful for granting temporary authorization that will end when the access token expires. Keep allowRefreshToken option on the grants so that it can still be easily disabled for all token requests to a grant type. If allowed for the grant, then call allowRefreshToken for the service. Default new function to resolving to true since it already requires refresh tokens be enabled at the grant level.

Refactor OAuth2Server into ResourceServer and AuthorizationServer

OAuth2Server currently has everything on it. The resource server wouldn't need everything from it since it just needs to authenticate routes. Update readme to include that the main entrypoints are resource_server.ts and authorization_server.ts. delete mod.ts and add doc links for each sub-module.

Use PBKDF2 for password hashing instead of SHA-256

Update hashPassword function on the user service to use PBKDF2 for password hashing.

https://github.com/udibo/oauth2_server/blob/main/services/user.ts

I wrote a function for generating salt in the example. It should be moved to the user service so that it's more reusable like the hashPassword function is.

https://github.com/udibo/oauth2_server/blob/main/examples/oak-localstorage/services/user.ts#L4

To be determined, what options should hashPassword have configurable.

Notes:

https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/deriveBits#pbkdf2

import { encode as encodeHex } from "https://deno.land/[email protected]/encoding/hex.ts";

function generateSalt(): Uint8Array {
  return window.crypto.getRandomValues(new Uint8Array(16));
}

/*
Get some key material to use as input to the deriveBits method.
The key material is a password supplied by the user.
*/
function getKeyMaterial(password: string) {
  const enc = new TextEncoder();
  return window.crypto.subtle.importKey(
    "raw",
    enc.encode(password),
    "PBKDF2",
    false,
    ["deriveBits", "deriveKey"],
  );
}

/*
Derive some bits from a password supplied by the user.
*/
async function getDerivedBits(
  password: string,
  salt: Uint8Array,
): Promise<[Uint8Array, number]> {
  const keyMaterial = await getKeyMaterial(password);
  const derivedBits = await window.crypto.subtle.deriveBits(
    {
      "name": "PBKDF2",
      salt,
      "iterations": 100000,
      "hash": "SHA-256",
    },
    keyMaterial,
    256,
  );

  const buffer = new Uint8Array(derivedBits, 0, 32);
  return [buffer, derivedBits.byteLength];
}

const salt = generateSalt();
const saltText = (new TextDecoder()).decode(encodeHex(salt));
console.log("salt: ", saltText);

const [buffer, length] = await getDerivedBits("hunter2", salt);
console.log(buffer);
console.log(length);
const hashed = (new TextDecoder()).decode(encodeHex(new Uint8Array(buffer)));
console.log(hashed);

// current SHA-256 hashPassword function
async function hashPassword(password: string, salt?: string): Promise<string> {
  const data = (new TextEncoder()).encode(
    password + (salt ? `:${salt}` : ""),
  );
  const buffer = await crypto.subtle.digest("SHA-256", data);
  return (new TextDecoder()).decode(encodeHex(new Uint8Array(buffer)));
}
console.log(await hashPassword("hunter2", saltText));

Add jwt to services

Depends on #12

This module should have a built in jwt service for resource servers to use. jwts give resource servers the ability to authenticate a route without having to make a call to the authorization server. It should extend the AbstractAccessTokenService and generate the AccessToken object from the jwt access token.

Add example of resource server and authorization server that use jwt access tokens. The services description should include the inability to revoke jwt access tokens as a disadvantage of using jwts and how short access token lifetime can help reduce the security risk.

Add test coverage for acceptedScope

This function was a recent addition and needs test coverage.

If the function returns false, that means it rejected the requested scope.
If the function returns undefined, that means it accepted the request but the request either did not request scope or the request was accepted but the token was not granted any scopes. The scoped returned does not need to match the scope passed in.

Test coverage should be added to grants/grant_test.ts, grants/client_credentials_test.ts, grants/password_test.ts, and server_test.ts.

Production example?

@KyleJune this is great. Would be amazing if you could create a production example of how this and oak work together.

I think it'll generate a lot of attention.

Not many modules focus on production applications for Deno... that could become a case study. Happy to help you write a blog post about it if you like.

This is a work in progress, expect breaking changes in the future

I'm currently working on building a Software as a Service that will make use of this library. I've paused development on this while I continue working on the other parts that will make use of this library. I have some issues open for changes I plan on making in the future to this.

Once my Software as a Service is up and running, I will create examples for how to use this with different frameworks like Oak and Fresh.

Due to this being a side project that I don't work on full time, expect progress to be slow. I have a full time job so I really only have time to work on my side project some nights and on weekends. I might not continue development on this specific module until later in the year or early next year.

Implement RFC 8628 - OAuth 2.0 Device Authorization Grant

I think it would be good to include an implementation of the device authorization grant in the grants folder so that people that would like to use this grant can easily add it to their OAuth2 Server.

See [RFC 8628] for more information about the device authorization grant.

Add authenticateView to ResourceServer

Depends on #9 & #12

To be able to use oauth2 for views,this cannot use authenticate because it responds to the request with a json error if authenticate fails and it doesn't request authentication when user is not logged in. The resource server need a separate function for authenticating the view so that it can leave the handling of errors to the routing framework and request authentication when user is not logged in.

Replace authenticate getAccessToken with getToken

I added getAccessToken as an argument to authenticate to make it easy to have alternative methods of getting an accessToken. This makes it possible to get an access token from a session without having to modify the request to have an authentication header that includes the session's accessToken.

The problem with getAccessToken is that it doesn't really give a way to work around token expiration. If I change the function to getToken, I could have it first call server.getToken with the session's accessToken. Then if the token is invalid, I could have it make an api call to refresh the token for the session before calling getToken again with the newly refreshed accessToken.

The example will need some sort of locking around refreshing tokens so that the concurrent requests don't try to refresh already refreshed tokens. If the refresh token is invalid or expired, it will need to delete the session and return an AccessDenied error.

Allow `number` to be used for `ClientInterface`.id

SQL databases in particular usually use number IDs for their rows/documents.
This feature would mean the developer has to write less boilerplate number to string conversion code to make everything work.

Use Web Crypto API instead of std/hash

std/hash has been deprecated now that the Web Crypto API is able to handle hashing.

This change will reduce the size of resource_server.ts from 308.8 kB to 116.4 kB and authorization_server.ts from 345.1 kB to 152.7 kB.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.