Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

custom token header #868

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/loud-camels-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'grafana-infinity-datasource': minor
---

🚀 **OAuth2 customization**: **Experimental**: Support for custom header key and custom token prefix for OAuth2 authentication methods
18 changes: 11 additions & 7 deletions docs/sources/setup/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,15 @@ If your Grafana user is already authenticated via OAuth, this authentication met

OAuth 2.0 client credentials require the following parameters:

| Key | Description |
| ------------------- | ------------------------------------------------------------------------------------------------- |
| **Client ID** | ClientID is the application's ID |
| **Client Secret** | ClientSecret is the application's secret. |
| **Token URL** | TokenURL is the resource server's token endpoint URL. This is a constant specific to each server. |
| **Scopes** | Scope specifies optional requested permissions. |
| **Endpoint params** | EndpointParams specifies additional parameters for requests to the token endpoint. |
| Key | Description |
| ----------------------- | ----------------------------------------------------------------------------------------------------------- |
| **Client ID** | ClientID is the application's ID |
| **Client Secret** | ClientSecret is the application's secret. |
| **Token URL** | TokenURL is the resource server's token endpoint URL. This is a constant specific to each server. |
| **Scopes** | Scope specifies optional requested permissions. |
| **Endpoint params** | EndpointParams specifies additional parameters for requests to the token endpoint. |
| **Custom header key** | (advanced) When configured, Instead of `Authorization` header this key will be used when sending the token |
| **Custom token prefix** | (advanced) When configured, Instead of `Bearer ` prefix, this will be used as prefix when sending the token |

## OAuth 2.0 JWT

Expand All @@ -103,6 +105,8 @@ OAuth 2.0 JWT require the following parameters
| **Token URL** | TokenURL is the endpoint required to complete the 2-legged JWT flow. |
| **Subject** | Optional. Subject is the optional user to impersonate. |
| **Scopes** | Scopes optionally specifies a list of requested permission scopes. Provide scopes as a comma separated values. |
| **Custom header key** | (advanced) When configured, Instead of `Authorization` header this key will be used when sending the token |
| **Custom token prefix** | (advanced) When configured, Instead of `Bearer ` prefix, this will be used as prefix when sending the token |

## Azure

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,5 @@ require (
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

replace golang.org/x/oauth2 => github.com/yesoreyeram/oauth2 v0.0.0-20240604200051-1e1fbf66b807
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ github.com/yesoreyeram/grafana-plugins/lib/go/utils v0.0.1 h1:A4C+oGjvMq8sINwXqK
github.com/yesoreyeram/grafana-plugins/lib/go/utils v0.0.1/go.mod h1:4uhug7R1Gu7qDisf6y6p2lI+wdNbLyM0Og1wJJDDLr0=
github.com/yesoreyeram/grafana-plugins/lib/go/xmlframer v0.0.6 h1:ZRudrWQQuizKXMWzsVhouGsvZNLFhZW3GhuUWfde+08=
github.com/yesoreyeram/grafana-plugins/lib/go/xmlframer v0.0.6/go.mod h1:lSz0gqi4MeK3ubDlp2gAxEfAlCSRQtiZyeXndXwtOWU=
github.com/yesoreyeram/oauth2 v0.0.0-20240604200051-1e1fbf66b807 h1:IiFeWJ/Ig4NKo5pDjAfioezT6wT9IGbGvYKmPiFXxCY=
github.com/yesoreyeram/oauth2 v0.0.0-20240604200051-1e1fbf66b807/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down Expand Up @@ -382,8 +384,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down
4 changes: 4 additions & 0 deletions pkg/infinity/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ func ApplyOAuthClientCredentials(ctx context.Context, httpClient *http.Client, s
EndpointParams: url.Values{},
AuthStyle: settings.OAuth2Settings.AuthStyle,
}
oauthConfig.CustomTokenHeaderKey = settings.OAuth2Settings.HeaderKey
oauthConfig.CustomTokenPrefix = settings.OAuth2Settings.TokenPrefix
for _, scope := range settings.OAuth2Settings.Scopes {
if scope != "" {
oauthConfig.Scopes = append(oauthConfig.Scopes, scope)
Expand Down Expand Up @@ -60,6 +62,8 @@ func ApplyOAuthJWT(ctx context.Context, httpClient *http.Client, settings models
Subject: settings.OAuth2Settings.Subject,
Scopes: []string{},
}
jwtConfig.CustomTokenHeaderKey = settings.OAuth2Settings.HeaderKey
jwtConfig.CustomTokenPrefix = settings.OAuth2Settings.TokenPrefix
for _, scope := range settings.OAuth2Settings.Scopes {
if scope != "" {
jwtConfig.Scopes = append(jwtConfig.Scopes, scope)
Expand Down
2 changes: 2 additions & 0 deletions pkg/models/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type OAuth2Settings struct {
Subject string `json:"subject,omitempty"`
Scopes []string `json:"scopes,omitempty"`
AuthStyle oauth2.AuthStyle `json:"authStyle,omitempty"`
HeaderKey string `json:"headerKey,omitempty"`
TokenPrefix string `json:"tokenPrefix,omitempty"`
ClientSecret string
PrivateKey string
EndpointParams map[string]string
Expand Down
26 changes: 26 additions & 0 deletions src/editors/config/OAuthInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { css } from '@emotion/css';
import { onUpdateDatasourceSecureJsonDataOption, DataSourcePluginOptionsEditorProps, SelectableValue } from '@grafana/data';
import { InlineFormLabel, Input, LegacyForms, LinkButton, RadioButtonGroup } from '@grafana/ui';
import { Stack } from 'components/extended/Stack';
import React from 'react';
import { SecureFieldsEditor } from './../../components/config/SecureFieldsEditor';
import type { InfinityOptions, InfinitySecureOptions, OAuth2Props, OAuth2Type } from './../../types';
Expand All @@ -11,6 +13,11 @@ const oAuthTypes: Array<SelectableValue<OAuth2Type>> = [
];

export const OAuthInputsEditor = (props: DataSourcePluginOptionsEditorProps<InfinityOptions>) => {
const styles = {
subheading: css`
margin-block: 20px;
`,
};
const { options, onOptionsChange } = props;
const { secureJsonFields } = options;
const secureJsonData = (options.secureJsonData || {}) as InfinitySecureOptions;
Expand Down Expand Up @@ -181,6 +188,25 @@ export const OAuthInputsEditor = (props: DataSourcePluginOptionsEditorProps<Infi
</p>
</div>
)}
{oauth2.oauth2_type !== 'others' && (
<>
<h5 className={styles.subheading}>Advanced OAuth2 config</h5>
<Stack direction="column" gap={0.5}>
<Stack gap={0.5}>
<InlineFormLabel width={10} tooltip={'Custom header key can be used to modify the header key. If provided, instead of Authorization this will be used'}>
Custom header key
</InlineFormLabel>
<Input onChange={(v) => onOAuth2PropsChange('headerKey', v.currentTarget.value)} value={oauth2.headerKey} width={30} placeholder={'Authorization'} />
</Stack>
<Stack gap={0.5}>
<InlineFormLabel width={10} tooltip={'Custom prefix to be added to the token. If empty, type will be used from token URL response. To clear the prefix, use empty space.'}>
Custom token prefix
</InlineFormLabel>
<Input onChange={(v) => onOAuth2PropsChange('tokenPrefix', v.currentTarget.value)} value={oauth2.tokenPrefix} width={30} placeholder={'Bearer '} />
</Stack>
</Stack>
</>
)}
</>
);
};
2 changes: 2 additions & 0 deletions src/types/config.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export type OAuth2Props = {
token_url?: string;
scopes?: string[];
authStyle?: number;
headerKey?: string;
tokenPrefix?: string;
};
export type AWSAuthProps = {
authType?: 'keys';
Expand Down
Loading