You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

token.go 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package oauth2
  5. import (
  6. "fmt"
  7. "time"
  8. "code.gitea.io/gitea/modules/timeutil"
  9. "github.com/golang-jwt/jwt/v4"
  10. )
  11. // ___________ __
  12. // \__ ___/___ | | __ ____ ____
  13. // | | / _ \| |/ // __ \ / \
  14. // | |( <_> ) <\ ___/| | \
  15. // |____| \____/|__|_ \\___ >___| /
  16. // \/ \/ \/
  17. // Token represents an Oauth grant
  18. // TokenType represents the type of token for an oauth application
  19. type TokenType int
  20. const (
  21. // TypeAccessToken is a token with short lifetime to access the api
  22. TypeAccessToken TokenType = 0
  23. // TypeRefreshToken is token with long lifetime to refresh access tokens obtained by the client
  24. TypeRefreshToken = iota
  25. )
  26. // Token represents a JWT token used to authenticate a client
  27. type Token struct {
  28. GrantID int64 `json:"gnt"`
  29. Type TokenType `json:"tt"`
  30. Counter int64 `json:"cnt,omitempty"`
  31. // FIXME: Migrate to registered claims
  32. jwt.StandardClaims
  33. }
  34. // ParseToken parses a signed jwt string
  35. func ParseToken(jwtToken string, signingKey JWTSigningKey) (*Token, error) {
  36. parsedToken, err := jwt.ParseWithClaims(jwtToken, &Token{}, func(token *jwt.Token) (interface{}, error) {
  37. if token.Method == nil || token.Method.Alg() != signingKey.SigningMethod().Alg() {
  38. return nil, fmt.Errorf("unexpected signing algo: %v", token.Header["alg"])
  39. }
  40. return signingKey.VerifyKey(), nil
  41. })
  42. if err != nil {
  43. return nil, err
  44. }
  45. var token *Token
  46. var ok bool
  47. if token, ok = parsedToken.Claims.(*Token); !ok || !parsedToken.Valid {
  48. return nil, fmt.Errorf("invalid token")
  49. }
  50. return token, nil
  51. }
  52. // SignToken signs the token with the JWT secret
  53. func (token *Token) SignToken(signingKey JWTSigningKey) (string, error) {
  54. token.IssuedAt = time.Now().Unix()
  55. jwtToken := jwt.NewWithClaims(signingKey.SigningMethod(), token)
  56. signingKey.PreProcessToken(jwtToken)
  57. return jwtToken.SignedString(signingKey.SignKey())
  58. }
  59. // OIDCToken represents an OpenID Connect id_token
  60. type OIDCToken struct {
  61. // FIXME: Migrate to RegisteredClaims
  62. jwt.StandardClaims
  63. Nonce string `json:"nonce,omitempty"`
  64. // Scope profile
  65. Name string `json:"name,omitempty"`
  66. PreferredUsername string `json:"preferred_username,omitempty"`
  67. Profile string `json:"profile,omitempty"`
  68. Picture string `json:"picture,omitempty"`
  69. Website string `json:"website,omitempty"`
  70. Locale string `json:"locale,omitempty"`
  71. UpdatedAt timeutil.TimeStamp `json:"updated_at,omitempty"`
  72. // Scope email
  73. Email string `json:"email,omitempty"`
  74. EmailVerified bool `json:"email_verified,omitempty"`
  75. // Groups are generated by organization and team names
  76. Groups []string `json:"groups,omitempty"`
  77. }
  78. // SignToken signs an id_token with the (symmetric) client secret key
  79. func (token *OIDCToken) SignToken(signingKey JWTSigningKey) (string, error) {
  80. token.IssuedAt = time.Now().Unix()
  81. jwtToken := jwt.NewWithClaims(signingKey.SigningMethod(), token)
  82. signingKey.PreProcessToken(jwtToken)
  83. return jwtToken.SignedString(signingKey.SignKey())
  84. }