Git Product home page Git Product logo

Comments (7)

pmrt avatar pmrt commented on August 13, 2024 4

Yeah, that's definitely not the best way to do this.

I think there's some confusion here. When you're saying "claims", I guess you're referring to JWT which this library doesn't use by default. It does use and generate tokens, but not JWT. That's why you can't add 'claims' to the default token model, because it's not a JWT and there's no such thing as 'claims',
just a replaceable AccessGenerate struct to generate the access_token.

So, how is the access token generated?

If you take a look at the code in the manager.go:GenerateAccessToken, the access_token is generated here

It instantiates the default AccessGenerate: generates/access.go In that file, the Token() method generates the access_token itself.

After generating the access_token, the token info is stored in the token store to (I believe, correct me if I'm wrong @LyricTian) later retrieve the token info from the store (in memory or persistent), rather than decoding the access_token and to store the token so you can e.g. invalidate it —and that kind of stuff— with the tokenStore (you can use the tokenStore methods for that).

How to create a custom access token?

Good news are that you CAN change the way the access token is generated, as the README states: you CAN use JWT to generate access tokens.

How? Easy. Just use a custom AccessGenerate struct like the one in generates/access.go . The library itself includes here: generates/jwt_access.go the JWTAccessGenerate you need to create custom access_token with JWT.

Change that file as you want with the claims you want:

func (a *JWTAccessGenerate) Token(data *oauth2.GenerateBasic, isGenRefresh bool) (access, refresh string, err error) {
	claims := &JWTAccessClaims{
		ClientID:  data.Client.GetID(),
		UserID:    data.UserID,
		ExpiredAt: data.TokenInfo.GetAccessCreateAt().Add(data.TokenInfo.GetAccessExpiresIn()).Unix(),
	}

	token := jwt.NewWithClaims(a.SignedMethod, claims)
	var key interface{}

and then change the AccessGenerate used by default with manager.MapAccessGenerate():

import "gopkg.in/oauth2.v3/generates"
import "github.com/dgrijalva/jwt-go"

// ...
manager.MapAccessGenerate(generates.NewJWTAccessGenerate([]byte("00000000"), jwt.SigningMethodHS512))

If you want to parse it and retrieve the claims, use the JWT library (as in the README.md):

import "github.com/dgrijalva/jwt-go"

// Verify jwt access token
token, err := jwt.ParseWithClaims(access, &generates.JWTAccessClaims{}, func(t *jwt.Token) (interface{}, error) {
	if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
		return nil, fmt.Errorf("parse error")
	}
	return []byte("00000000"), nil
})
if err != nil {
	panic(err)
}

claims, ok := token.Claims.(*generates.JWTAccessClaims)
if !ok || !token.Valid {
	panic("invalid token")
}

In my opinion, I would strongly recommend using a custom JWTAccessGenerate to generate your access_token, even if you don't need custom claims.

Just because then you could generate a JWT access_token with asymmetric encryption (like RSA), and you'd have a public and a private key in your auth server and only the public key in the Resource server. This way you can verify and decode tokens from the resource server without additional round trips to the auth server.

To conclude, I would want to thank you @LyricTian for this great library. It's well-coded and it's easy to customize, but as a suggestion I would pick someone who speaks native english (I don't) or open an issue with a 'help needed' label to look for someone, and get him to write up some documentation explaining this sort of things (eg. How is the access token generated, how to change the AccessGenerate, digging into the custom handlers —which I would rename to lifecycle hooks because at first I thought that by 'handlers' you were referring to something related with HTTP because 'handler' is like a convention in golang, also: isGenerateRefresh to allowRefresh.. but that would mean breaking changes so...—, etc.)

Anyway, I hope this helps anyone to add custom JWT claims.

from oauth2.

jakubknejzlik avatar jakubknejzlik commented on August 13, 2024 2

I would like to thank @pmrt for his answer 👏.
Also I would like to ask why not use JWT standard claims. For example this mapping:
user_id: "sub" (https://tools.ietf.org/html/rfc7519#section-4.1.2)
expire_at: "exp" (https://tools.ietf.org/html/rfc7519#section-4.1.4)
client_id: "aud" (https://tools.ietf.org/html/rfc7519#section-4.1.3)

These are also specified here: https://github.com/dgrijalva/jwt-go/blob/06ea1031745cb8b3dab3f6a236daf2b0aa468b7e/claims.go#L18

I've created draft PR if I'm not clear :) ... #102

from oauth2.

jakubknejzlik avatar jakubknejzlik commented on August 13, 2024 1

You are right, at the time of writing my comment I was under impression that aud should be used differently than its actual purpose.

from oauth2.

LyricTian avatar LyricTian commented on August 13, 2024

UserID is a string type, you can encode the data you need into a string using JSON encoding.

from oauth2.

dharmjit avatar dharmjit commented on August 13, 2024

you means to say to use userID for all the claims

from oauth2.

SergeMerzliakov avatar SergeMerzliakov commented on August 13, 2024

An example of adding public and/or private custom claims would be nice, as this is not obvious to me.

from oauth2.

xiaofei-du avatar xiaofei-du commented on August 13, 2024

I would like to thank @pmrt for his answer 👏.
Also I would like to ask why not use JWT standard claims. For example this mapping:
user_id: "sub" (https://tools.ietf.org/html/rfc7519#section-4.1.2)
expire_at: "exp" (https://tools.ietf.org/html/rfc7519#section-4.1.4)
client_id: "aud" (https://tools.ietf.org/html/rfc7519#section-4.1.3)

These are also specified here: https://github.com/dgrijalva/jwt-go/blob/06ea1031745cb8b3dab3f6a236daf2b0aa468b7e/claims.go#L18

I've created draft PR if I'm not clear :) ... #102

Thanks for the PR. 👍

One question about the standard claims:
AFAIK, "aud" in OAuth2 refers to the Resource Server that accepts this token, normally it would be the url of the resource. see discussion.
"sub" would be relevant to the client_id or user_id depending on which OAuth2 Grant Type is involved (whether it is user-driven or machine-to-machine)

from oauth2.

Related Issues (20)

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.